diff --git a/src/App.cpp b/src/App.cpp index 492dcef..10daa23 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -1,8 +1,8 @@ -#include "App.h" -#include "IPlatform.h" +#include "App.hpp" +#include "IPlatform.hpp" -#include "platform/server/PlatformServer.h" -#include "platform/glfw/PlatformGlfw.h" +#include "platform/server/PlatformServer.hpp" +#include "platform/glfw/PlatformGlfw.hpp" std::unique_ptr App::CreatePlatform() { #if defined(STANDALONE_SERVER) diff --git a/src/App.h b/src/App.hpp similarity index 93% rename from src/App.h rename to src/App.hpp index d140ab8..fb0852d 100755 --- a/src/App.h +++ b/src/App.hpp @@ -8,7 +8,7 @@ #define NO_EGL #endif -#include +#include #ifndef NO_EGL #include #endif diff --git a/src/EglConfigPrinter.h b/src/EglConfigPrinter.hpp similarity index 100% rename from src/EglConfigPrinter.h rename to src/EglConfigPrinter.hpp diff --git a/src/IPlatform.cpp b/src/IPlatform.cpp index 3dac481..8504812 100644 --- a/src/IPlatform.cpp +++ b/src/IPlatform.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include void IPlatform::runMainLoop(App& app) { diff --git a/src/IPlatform.h b/src/IPlatform.hpp similarity index 94% rename from src/IPlatform.h rename to src/IPlatform.hpp index 9be2a2d..a5c187d 100755 --- a/src/IPlatform.h +++ b/src/IPlatform.hpp @@ -1,81 +1,81 @@ -#pragma once -#include -#include -#include "client/renderer/TextureData.h" -#include - -typedef std::vector StringVector; -typedef std::vector ByteVector; - -class App; - -class IPlatform { -public: - IPlatform() : keyboardVisible(false), windowSizeChanged(false), m_targetFrametime(0.f) {} - virtual ~IPlatform() {} - - virtual bool init() { return true; } - virtual void swapBuffers() {} - - virtual void runMainLoop(App& app); - - virtual ByteVector readAssetFile(const std::string& path); - - - // Mojang functions here - virtual TextureData loadTexture(const std::string& filename_, bool textureFolder) { return TextureData(); } - virtual TextureData loadTextureFromMemory(const unsigned char* data, size_t size) { return TextureData(); } - - virtual void playSound(const std::string& fn, float volume, float pitch) {} - - virtual void hideCursor(bool hide) {} - - virtual std::string getDateString(int s) = 0; - - virtual void uploadPlatformDependentData(int id, void* data) {} - // virtual BinaryBlob readAssetFile(const std::string& filename) { return BinaryBlob(); } - virtual void _tick() {} - - virtual int getScreenWidth() { return 854; } - virtual int getScreenHeight() { return 480; } - virtual float getPixelsPerMillimeter() { return 10; } - - virtual bool isNetworkEnabled(bool onlyWifiAllowed) { return true; } - - virtual bool isPowerVR() { - return false; - } - virtual int getKeyFromKeyCode(int keyCode, int metaState, int deviceId) {return 0;} -#ifdef __APPLE__ - virtual bool isSuperFast() = 0; -#endif - - virtual void openURL(const std::string& url) {} - - virtual void finish() {} - - virtual bool supportsTouchscreen() { return false; } - - virtual void vibrate(int milliSeconds) {} - - virtual std::string getPlatformStringVar(int stringId) = 0; - - virtual void showKeyboard() { keyboardVisible = true; } - - virtual void hideKeyboard() { keyboardVisible = false; } - - virtual bool isKeyboardVisible() { return keyboardVisible; } - - virtual void setTargetFPS(int fps) { m_targetFrametime = 1.0 / fps; } - - bool isWindowSizeChanged() { return windowSizeChanged; } - - virtual void setVSync(bool on) { vsync = on; } - -protected: - bool keyboardVisible; - bool windowSizeChanged; - bool vsync; - - double m_targetFrametime; -}; +#pragma once +#include +#include +#include "client/renderer/TextureData.hpp" +#include + +typedef std::vector StringVector; +typedef std::vector ByteVector; + +class App; + +class IPlatform { +public: + IPlatform() : keyboardVisible(false), windowSizeChanged(false), m_targetFrametime(0.f) {} + virtual ~IPlatform() {} + + virtual bool init() { return true; } + virtual void swapBuffers() {} + + virtual void runMainLoop(App& app); + + virtual ByteVector readAssetFile(const std::string& path); + + + // Mojang functions here + virtual TextureData loadTexture(const std::string& filename_, bool textureFolder) { return TextureData(); } + virtual TextureData loadTextureFromMemory(const unsigned char* data, size_t size) { return TextureData(); } + + virtual void playSound(const std::string& fn, float volume, float pitch) {} + + virtual void hideCursor(bool hide) {} + + virtual std::string getDateString(int s) = 0; + + virtual void uploadPlatformDependentData(int id, void* data) {} + // virtual BinaryBlob readAssetFile(const std::string& filename) { return BinaryBlob(); } + virtual void _tick() {} + + virtual int getScreenWidth() { return 854; } + virtual int getScreenHeight() { return 480; } + virtual float getPixelsPerMillimeter() { return 10; } + + virtual bool isNetworkEnabled(bool onlyWifiAllowed) { return true; } + + virtual bool isPowerVR() { + return false; + } + virtual int getKeyFromKeyCode(int keyCode, int metaState, int deviceId) {return 0;} +#ifdef __APPLE__ + virtual bool isSuperFast() = 0; +#endif + + virtual void openURL(const std::string& url) {} + + virtual void finish() {} + + virtual bool supportsTouchscreen() { return false; } + + virtual void vibrate(int milliSeconds) {} + + virtual std::string getPlatformStringVar(int stringId) = 0; + + virtual void showKeyboard() { keyboardVisible = true; } + + virtual void hideKeyboard() { keyboardVisible = false; } + + virtual bool isKeyboardVisible() { return keyboardVisible; } + + virtual void setTargetFPS(int fps) { m_targetFrametime = 1.0 / fps; } + + bool isWindowSizeChanged() { return windowSizeChanged; } + + virtual void setVSync(bool on) { vsync = on; } + +protected: + bool keyboardVisible; + bool windowSizeChanged; + bool vsync; + + double m_targetFrametime; +}; diff --git a/src/LicenseCodes.h b/src/LicenseCodes.hpp similarity index 100% rename from src/LicenseCodes.h rename to src/LicenseCodes.hpp diff --git a/src/Minecraft.cpp b/src/Minecraft.cpp index 29ca115..ed3511e 100755 --- a/src/Minecraft.cpp +++ b/src/Minecraft.cpp @@ -1,502 +1,502 @@ -#include -#include "gamemode/CreativeMode.h" -#include "gamemode/SurvivalMode.h" -#include "gamemode/CreatorMode.h" -#include "world/entity/player/Player.h" -#include "world/item/Item.h" -#include "world/item/ItemInstance.h" -#include "world/item/crafting/Recipes.h" -#include "world/level/Level.h" -#include "world/level/tile/entity/TileEntity.h" -#include -#include -#include "client/gui/Screen.h" -#include "world/level/storage/ExternalFileLevelStorageSource.h" - -#if defined(APPLE_DEMO_PROMOTION) - #define NO_NETWORK -#endif - -#if defined(RPI) - #define CREATORMODE -#endif -#include "network/RakNetInstance.h" -#include "network/ClientSideNetworkHandler.h" -#include "network/ServerSideNetworkHandler.h" -//#include "network/Packet.h" -#include "world/entity/player/Inventory.h" -#include "world/level/tile/Tile.h" -#include "world/level/storage/LevelStorageSource.h" -#include "world/level/storage/LevelStorage.h" -#include "world/level/chunk/ChunkSource.h" - -#include "platform/CThread.h" -#include -#include "util/PerfTimer.h" -#include "util/PerfRenderer.h" - -#include "world/entity/MobFactory.h" -#include "world/level/MobSpawner.h" -#include "util/Mth.h" -#include "world/entity/MobCategory.h" -#include "server/ServerLevel.h" - -#ifdef CREATORMODE -#include "server/CreatorLevel.h" -#endif - -#include "network/command/CommandServer.h" - -/*static*/ -const char* Minecraft::progressMessages[] = { - "Locating server", - "Building terrain", - "Preparing", - "Saving chunks" -}; - -// int Minecraft::customDebugId = Minecraft::CDI_NONE; -bool Minecraft::_hasInitedStatics = false; - -#if defined(_MSC_VER) - #pragma warning( disable : 4355 ) // 'this' pointer in initialization list which is perfectly legal -#endif - -// Minecraft::Minecraft() : -// #ifdef __APPLE__ -// _isSuperFast(false), -// #endif - - -// #if defined(NO_NETWORK) -// raknetInstance = new IRakNetInstance(); -// #else -// raknetInstance = new RakNetInstance(); -// #endif -// #ifndef STANDALONE_SERVER -// soundEngine = new SoundEngine(20.0f); -// soundEngine->init(this, &options); -// #endif -// //setupPieces(); - -// #if defined(ANDROID) || defined(__APPLE__) || defined(RPI) -// signal(SIGPIPE, SIG_IGN); -// #endif - -// externalCacheStoragePath = '.'; -// externalCacheStoragePath = '.'; -// } - -Minecraft::~Minecraft() { - delete netCallback; - delete raknetInstance; - delete gameMode; - - if (level != NULL) { - level->saveGame(); - if (level->getChunkSource()) - level->getChunkSource()->saveAll(true); - delete level->getLevelStorage(); - delete level; - level = NULL; - } - - //delete player; - delete storageSource; - delete _commandServer; - - MobFactory::clearStaticTestMobs(); - - // Note: Don't tear down statics if we run on Android - // (we might change this in the future) -#ifndef ANDROID - Biome::teardownBiomes(); - Item ::teardownItems(); - Tile ::teardownTiles(); - Material::teardownMaterials(); - Recipes ::teardownRecipes(); - TileEntity::teardownTileEntities(); -#endif -} - -// Only called by server -void Minecraft::selectLevel( const std::string& levelId, const std::string& levelName, const LevelSettings& settings ) { - level = (Level*)new ServerLevel( - storageSource->selectLevel(levelId, false), - levelName, - settings, - SharedConstants::GeneratorVersion - ); - - // note: settings is useless beyond this point, since it's - // either copied to LevelData (or LevelData read from file) - setLevel(level, "Generating level"); - setIsCreativeMode(level->getLevelData()->getGameType() == GameType::Creative); - _running = true; -} - -void Minecraft::setLevel(Level* level, const std::string& message, Player* forceInsertPlayer) { - LOGI("Seed is %ld\n", level->getSeed()); - - if (level != NULL) { - level->raknetInstance = raknetInstance; - gameMode->initLevel(level); - - this->level = level; - _hasSignaledGeneratingLevelFinished = false; -#ifdef STANDALONE_SERVER - const bool threadedLevelCreation = false; -#else - const bool threadedLevelCreation = true; -#endif - - if (threadedLevelCreation) { - // Threaded - // "Lock" - isGeneratingLevel = true; - generateLevelThread = new CThread(Minecraft::prepareLevel_tspawn, this); - } else { - // Non-threaded - generateLevel("Currently not used", level); - } - } - - this->lastTickTime = 0; - this->_running = true; -} - -void Minecraft::prepareLevel(const std::string& title) { - LOGI("status: 1\n"); - progressStageStatusId = 1; - - Stopwatch A, B, C, D; - A.start(); - - Stopwatch L; - - // Dont update lights if we load the level (ok, actually just with leveldata version=1.+(?)) - if (!level->isNew()) - level->setUpdateLights(false); - - int Max = CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; - int pp = 0; - for (int x = 8; x < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); x += CHUNK_WIDTH) { - for (int z = 8; z < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); z += CHUNK_WIDTH) { - progressStagePercentage = 100 * pp++ / Max; - //printf("level generation progress %d\n", progressStagePercentage); - B.start(); - level->getTile(x, 64, z); - B.stop(); - L.start(); - if (level->isNew()) - while (level->updateLights()) - ; - L.stop(); - } - } - A.stop(); - level->setUpdateLights(true); - - C.start(); - for (int x = 0; x < CHUNK_CACHE_WIDTH; x++) - { - for (int z = 0; z < CHUNK_CACHE_WIDTH; z++) - { - LevelChunk* chunk = level->getChunk(x, z); - if (chunk && !chunk->createdFromSave) - { - chunk->unsaved = false; - chunk->clearUpdateMap(); - } - } - } - C.stop(); - - LOGI("status: 3\n"); - progressStageStatusId = 3; - if (level->isNew()) { - level->setInitialSpawn(); // @note: should obviously be called from Level itself - level->saveLevelData(); - level->getChunkSource()->saveAll(false); - level->saveGame(); - } else { - level->saveLevelData(); - level->loadEntities(); - } - - progressStagePercentage = -1; - progressStageStatusId = 2; - LOGI("status: 2\n"); - - D.start(); - level->prepare(); - D.stop(); - - A.print("Generate level: "); - L.print(" - light: "); - B.print(" - getTl: "); - C.print(" - clear: "); - D.print(" - prepr: "); - progressStageStatusId = 0; -} - -void Minecraft::update() { - - timer.advanceTime(); - raknetInstance->runEvents(netCallback); - - TIMER_PUSH("tick"); - int toTick = timer.ticks; - timer.ticks = 0; - for (int i = 0; i < toTick; ++i, ++ticks) tick(i, toTick-1); - - TIMER_POP_PUSH("updatelights"); - { - if (level && !isGeneratingLevel) { - level->updateLights(); - } - } - TIMER_POP(); - - - // Restart the server if (our modded) RakNet reports an error - if (level && raknetInstance->isProbablyBroken() && raknetInstance->isServer()) { - restartServer(); - } -} - -void Minecraft::restartServer() { - if (!level) return; - - raknetInstance->resetIsBroken(); - - hostMultiplayer(); - if (netCallback) netCallback->levelGenerated(level); -} - -void Minecraft::tick(int nTick, int maxTick) { - if (missTime > 0) missTime--; - - TIMER_PUSH("gameMode"); - if (level) { - gameMode->tick(); - } - - TIMER_POP_PUSH("commandServer"); - if (level && _commandServer) { - _commandServer->tick(); - } - - // - // Ongoing level generation in a (perhaps) different thread. When it's - // ready, _levelGenerated() is called once and any threads are deleted. - // - if (isGeneratingLevel) { - return; - } else if (!_hasSignaledGeneratingLevelFinished) { - if (generateLevelThread) { - delete generateLevelThread; - generateLevelThread = NULL; - } - _levelGenerated(); - } - - // - // Normal game loop, run before or efter level generation - // - if (level != NULL) { - TIMER_POP_PUSH("level"); - level->tickEntities(); - level->tick(); - } - - TIMER_POP(); -} - -bool Minecraft::isOnlineClient() { - return false; -} - -bool Minecraft::isOnline() { - return netCallback != NULL; -} - -void Minecraft::init() -{ - // WHY DO WE NEED THIS ON MODERN PLATFORMS :sob: - // Global initialization goes here - Mth::initMth(); - - if (raknetInstance != nullptr) { - delete raknetInstance; - } - - raknetInstance = new RakNetInstance(); - - // If we're running Android, only initialize - // the first time class is instanced -#ifdef ANDROID - if (!_hasInitedStatics) { - _hasInitedStatics = true; -#endif - Material::initMaterials(); - MobCategory::initMobCategories(); - Tile::initTiles(); - Item::initItems(); - Biome::initBiomes(); - TileEntity::initTileEntities(); - -#ifdef ANDROID - } -#endif - - setIsCreativeMode(false); // false means it's Survival Mode - -#if !defined(NO_STORAGE) - storageSource = new ExternalFileLevelStorageSource(externalStoragePath, externalCacheStoragePath); -#else - storageSource = new MemoryLevelStorageSource(); -#endif - - // Server-only featire @todo server class app - hostMultiplayer(); -} - - -// -// Multiplayer -// - -void Minecraft::hostMultiplayer(int port) { - // Tear down last instance - raknetInstance->disconnect(); - delete netCallback; - netCallback = nullptr; - -#if !defined(NO_NETWORK) - netCallback = new ServerSideNetworkHandler(this, raknetInstance); -#endif -} - -// -// Level generation -// -/*static*/ - -void* Minecraft::prepareLevel_tspawn(void *p_param) { - Minecraft* mc = (Minecraft*) p_param; - mc->generateLevel("Currently not used", mc->level); - return 0; -} - -void Minecraft::generateLevel( const std::string& message, Level* level ) { - Stopwatch s; - s.start(); - prepareLevel(message); - s.stop(); - s.print("Level generated: "); - - // "Unlock" - isGeneratingLevel = false; -} - -void Minecraft::_levelGenerated() { - level->validateSpawn(); - - if (raknetInstance->isServer()) - raknetInstance->announceServer(getServerName()); - - if (netCallback) { - netCallback->levelGenerated(level); - } - - _hasSignaledGeneratingLevelFinished = true; -} - -Player* Minecraft::respawnPlayer(int playerId) { - for (unsigned int i = 0; i < level->players.size(); ++i) { - if (level->players[i]->entityId == playerId) { - resetPlayer(level->players[i]); - return level->players[i]; - } - } - return NULL; -} - -void Minecraft::resetPlayer(Player* player) { - level->validateSpawn(); - player->reset(); - - Pos p; - if(player->hasRespawnPosition()) { - p = player->getRespawnPosition(); - } - else { - p = level->getSharedSpawnPos(); - } - player->setPos((float)p.x + 0.5f, (float)p.y + 1.0f, (float)p.z + 0.5f); - player->resetPos(true); - - if (isCreativeMode()) - player->inventory->clearInventoryWithDefault(); -} - -int Minecraft::getProgressStatusId() { - return progressStageStatusId; -} - -const char* Minecraft::getProgressMessage() -{ - return progressMessages[progressStageStatusId]; -} - -bool Minecraft::isLevelGenerated() -{ - return level != NULL && !isGeneratingLevel; -} - -LevelStorageSource* Minecraft::getLevelSource() -{ - return storageSource; -} - -void Minecraft::setIsCreativeMode(bool isCreative) -{ -#ifdef CREATORMODE - delete gameMode; - gameMode = new CreatorMode(this); - _isCreativeMode = true; -#else - if (!gameMode || isCreative != _isCreativeMode) - { - delete gameMode; - if (isCreative) gameMode = new CreativeMode(*this); - else gameMode = new SurvivalMode(*this); - _isCreativeMode = isCreative; - } -#endif -} - -bool Minecraft::isCreativeMode() { - return _isCreativeMode; -} - -ICreator* Minecraft::getCreator() -{ -#ifdef CREATORMODE - return ((CreatorMode*)gameMode)->getCreator(); -#else - return NULL; -#endif -} - -void Minecraft::optionUpdated(OptionId option, bool value ) { - if(netCallback != NULL && option == OPTIONS_SERVER_VISIBLE) { - ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback; - ss->allowIncomingConnections(value); - } -} - -void Minecraft::optionUpdated(OptionId option, float value ) {} - -void Minecraft::optionUpdated(OptionId option, int value ) {} +#include +#include "gamemode/CreativeMode.hpp" +#include "gamemode/SurvivalMode.hpp" +#include "gamemode/CreatorMode.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/item/crafting/Recipes.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/entity/TileEntity.hpp" +#include +#include +#include "client/gui/Screen.hpp" +#include "world/level/storage/ExternalFileLevelStorageSource.hpp" + +#if defined(APPLE_DEMO_PROMOTION) + #define NO_NETWORK +#endif + +#if defined(RPI) + #define CREATORMODE +#endif +#include "network/RakNetInstance.hpp" +#include "network/ClientSideNetworkHandler.hpp" +#include "network/ServerSideNetworkHandler.hpp" +//#include "network/Packet.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/storage/LevelStorageSource.hpp" +#include "world/level/storage/LevelStorage.hpp" +#include "world/level/chunk/ChunkSource.hpp" + +#include "platform/CThread.hpp" +#include +#include "util/PerfTimer.hpp" +#include "util/PerfRenderer.hpp" + +#include "world/entity/MobFactory.hpp" +#include "world/level/MobSpawner.hpp" +#include "util/Mth.hpp" +#include "world/entity/MobCategory.hpp" +#include "server/ServerLevel.hpp" + +#ifdef CREATORMODE +#include "server/CreatorLevel.hpp" +#endif + +#include "network/command/CommandServer.hpp" + +/*static*/ +const char* Minecraft::progressMessages[] = { + "Locating server", + "Building terrain", + "Preparing", + "Saving chunks" +}; + +// int Minecraft::customDebugId = Minecraft::CDI_NONE; +bool Minecraft::_hasInitedStatics = false; + +#if defined(_MSC_VER) + #pragma warning( disable : 4355 ) // 'this' pointer in initialization list which is perfectly legal +#endif + +// Minecraft::Minecraft() : +// #ifdef __APPLE__ +// _isSuperFast(false), +// #endif + + +// #if defined(NO_NETWORK) +// raknetInstance = new IRakNetInstance(); +// #else +// raknetInstance = new RakNetInstance(); +// #endif +// #ifndef STANDALONE_SERVER +// soundEngine = new SoundEngine(20.0f); +// soundEngine->init(this, &options); +// #endif +// //setupPieces(); + +// #if defined(ANDROID) || defined(__APPLE__) || defined(RPI) +// signal(SIGPIPE, SIG_IGN); +// #endif + +// externalCacheStoragePath = '.'; +// externalCacheStoragePath = '.'; +// } + +Minecraft::~Minecraft() { + delete netCallback; + delete raknetInstance; + delete gameMode; + + if (level != NULL) { + level->saveGame(); + if (level->getChunkSource()) + level->getChunkSource()->saveAll(true); + delete level->getLevelStorage(); + delete level; + level = NULL; + } + + //delete player; + delete storageSource; + delete _commandServer; + + MobFactory::clearStaticTestMobs(); + + // Note: Don't tear down statics if we run on Android + // (we might change this in the future) +#ifndef ANDROID + Biome::teardownBiomes(); + Item ::teardownItems(); + Tile ::teardownTiles(); + Material::teardownMaterials(); + Recipes ::teardownRecipes(); + TileEntity::teardownTileEntities(); +#endif +} + +// Only called by server +void Minecraft::selectLevel( const std::string& levelId, const std::string& levelName, const LevelSettings& settings ) { + level = (Level*)new ServerLevel( + storageSource->selectLevel(levelId, false), + levelName, + settings, + SharedConstants::GeneratorVersion + ); + + // note: settings is useless beyond this point, since it's + // either copied to LevelData (or LevelData read from file) + setLevel(level, "Generating level"); + setIsCreativeMode(level->getLevelData()->getGameType() == GameType::Creative); + _running = true; +} + +void Minecraft::setLevel(Level* level, const std::string& message, Player* forceInsertPlayer) { + LOGI("Seed is %ld\n", level->getSeed()); + + if (level != NULL) { + level->raknetInstance = raknetInstance; + gameMode->initLevel(level); + + this->level = level; + _hasSignaledGeneratingLevelFinished = false; +#ifdef STANDALONE_SERVER + const bool threadedLevelCreation = false; +#else + const bool threadedLevelCreation = true; +#endif + + if (threadedLevelCreation) { + // Threaded + // "Lock" + isGeneratingLevel = true; + generateLevelThread = new CThread(Minecraft::prepareLevel_tspawn, this); + } else { + // Non-threaded + generateLevel("Currently not used", level); + } + } + + this->lastTickTime = 0; + this->_running = true; +} + +void Minecraft::prepareLevel(const std::string& title) { + LOGI("status: 1\n"); + progressStageStatusId = 1; + + Stopwatch A, B, C, D; + A.start(); + + Stopwatch L; + + // Dont update lights if we load the level (ok, actually just with leveldata version=1.+(?)) + if (!level->isNew()) + level->setUpdateLights(false); + + int Max = CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; + int pp = 0; + for (int x = 8; x < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); x += CHUNK_WIDTH) { + for (int z = 8; z < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); z += CHUNK_WIDTH) { + progressStagePercentage = 100 * pp++ / Max; + //printf("level generation progress %d\n", progressStagePercentage); + B.start(); + level->getTile(x, 64, z); + B.stop(); + L.start(); + if (level->isNew()) + while (level->updateLights()) + ; + L.stop(); + } + } + A.stop(); + level->setUpdateLights(true); + + C.start(); + for (int x = 0; x < CHUNK_CACHE_WIDTH; x++) + { + for (int z = 0; z < CHUNK_CACHE_WIDTH; z++) + { + LevelChunk* chunk = level->getChunk(x, z); + if (chunk && !chunk->createdFromSave) + { + chunk->unsaved = false; + chunk->clearUpdateMap(); + } + } + } + C.stop(); + + LOGI("status: 3\n"); + progressStageStatusId = 3; + if (level->isNew()) { + level->setInitialSpawn(); // @note: should obviously be called from Level itself + level->saveLevelData(); + level->getChunkSource()->saveAll(false); + level->saveGame(); + } else { + level->saveLevelData(); + level->loadEntities(); + } + + progressStagePercentage = -1; + progressStageStatusId = 2; + LOGI("status: 2\n"); + + D.start(); + level->prepare(); + D.stop(); + + A.print("Generate level: "); + L.print(" - light: "); + B.print(" - getTl: "); + C.print(" - clear: "); + D.print(" - prepr: "); + progressStageStatusId = 0; +} + +void Minecraft::update() { + + timer.advanceTime(); + raknetInstance->runEvents(netCallback); + + TIMER_PUSH("tick"); + int toTick = timer.ticks; + timer.ticks = 0; + for (int i = 0; i < toTick; ++i, ++ticks) tick(i, toTick-1); + + TIMER_POP_PUSH("updatelights"); + { + if (level && !isGeneratingLevel) { + level->updateLights(); + } + } + TIMER_POP(); + + + // Restart the server if (our modded) RakNet reports an error + if (level && raknetInstance->isProbablyBroken() && raknetInstance->isServer()) { + restartServer(); + } +} + +void Minecraft::restartServer() { + if (!level) return; + + raknetInstance->resetIsBroken(); + + hostMultiplayer(); + if (netCallback) netCallback->levelGenerated(level); +} + +void Minecraft::tick(int nTick, int maxTick) { + if (missTime > 0) missTime--; + + TIMER_PUSH("gameMode"); + if (level) { + gameMode->tick(); + } + + TIMER_POP_PUSH("commandServer"); + if (level && _commandServer) { + _commandServer->tick(); + } + + // + // Ongoing level generation in a (perhaps) different thread. When it's + // ready, _levelGenerated() is called once and any threads are deleted. + // + if (isGeneratingLevel) { + return; + } else if (!_hasSignaledGeneratingLevelFinished) { + if (generateLevelThread) { + delete generateLevelThread; + generateLevelThread = NULL; + } + _levelGenerated(); + } + + // + // Normal game loop, run before or efter level generation + // + if (level != NULL) { + TIMER_POP_PUSH("level"); + level->tickEntities(); + level->tick(); + } + + TIMER_POP(); +} + +bool Minecraft::isOnlineClient() { + return false; +} + +bool Minecraft::isOnline() { + return netCallback != NULL; +} + +void Minecraft::init() +{ + // WHY DO WE NEED THIS ON MODERN PLATFORMS :sob: + // Global initialization goes here + Mth::initMth(); + + if (raknetInstance != nullptr) { + delete raknetInstance; + } + + raknetInstance = new RakNetInstance(); + + // If we're running Android, only initialize + // the first time class is instanced +#ifdef ANDROID + if (!_hasInitedStatics) { + _hasInitedStatics = true; +#endif + Material::initMaterials(); + MobCategory::initMobCategories(); + Tile::initTiles(); + Item::initItems(); + Biome::initBiomes(); + TileEntity::initTileEntities(); + +#ifdef ANDROID + } +#endif + + setIsCreativeMode(false); // false means it's Survival Mode + +#if !defined(NO_STORAGE) + storageSource = new ExternalFileLevelStorageSource(externalStoragePath, externalCacheStoragePath); +#else + storageSource = new MemoryLevelStorageSource(); +#endif + + // Server-only featire @todo server class app + hostMultiplayer(); +} + + +// +// Multiplayer +// + +void Minecraft::hostMultiplayer(int port) { + // Tear down last instance + raknetInstance->disconnect(); + delete netCallback; + netCallback = nullptr; + +#if !defined(NO_NETWORK) + netCallback = new ServerSideNetworkHandler(this, raknetInstance); +#endif +} + +// +// Level generation +// +/*static*/ + +void* Minecraft::prepareLevel_tspawn(void *p_param) { + Minecraft* mc = (Minecraft*) p_param; + mc->generateLevel("Currently not used", mc->level); + return 0; +} + +void Minecraft::generateLevel( const std::string& message, Level* level ) { + Stopwatch s; + s.start(); + prepareLevel(message); + s.stop(); + s.print("Level generated: "); + + // "Unlock" + isGeneratingLevel = false; +} + +void Minecraft::_levelGenerated() { + level->validateSpawn(); + + if (raknetInstance->isServer()) + raknetInstance->announceServer(getServerName()); + + if (netCallback) { + netCallback->levelGenerated(level); + } + + _hasSignaledGeneratingLevelFinished = true; +} + +Player* Minecraft::respawnPlayer(int playerId) { + for (unsigned int i = 0; i < level->players.size(); ++i) { + if (level->players[i]->entityId == playerId) { + resetPlayer(level->players[i]); + return level->players[i]; + } + } + return NULL; +} + +void Minecraft::resetPlayer(Player* player) { + level->validateSpawn(); + player->reset(); + + Pos p; + if(player->hasRespawnPosition()) { + p = player->getRespawnPosition(); + } + else { + p = level->getSharedSpawnPos(); + } + player->setPos((float)p.x + 0.5f, (float)p.y + 1.0f, (float)p.z + 0.5f); + player->resetPos(true); + + if (isCreativeMode()) + player->inventory->clearInventoryWithDefault(); +} + +int Minecraft::getProgressStatusId() { + return progressStageStatusId; +} + +const char* Minecraft::getProgressMessage() +{ + return progressMessages[progressStageStatusId]; +} + +bool Minecraft::isLevelGenerated() +{ + return level != NULL && !isGeneratingLevel; +} + +LevelStorageSource* Minecraft::getLevelSource() +{ + return storageSource; +} + +void Minecraft::setIsCreativeMode(bool isCreative) +{ +#ifdef CREATORMODE + delete gameMode; + gameMode = new CreatorMode(this); + _isCreativeMode = true; +#else + if (!gameMode || isCreative != _isCreativeMode) + { + delete gameMode; + if (isCreative) gameMode = new CreativeMode(*this); + else gameMode = new SurvivalMode(*this); + _isCreativeMode = isCreative; + } +#endif +} + +bool Minecraft::isCreativeMode() { + return _isCreativeMode; +} + +ICreator* Minecraft::getCreator() +{ +#ifdef CREATORMODE + return ((CreatorMode*)gameMode)->getCreator(); +#else + return NULL; +#endif +} + +void Minecraft::optionUpdated(OptionId option, bool value ) { + if(netCallback != NULL && option == OPTIONS_SERVER_VISIBLE) { + ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) netCallback; + ss->allowIncomingConnections(value); + } +} + +void Minecraft::optionUpdated(OptionId option, float value ) {} + +void Minecraft::optionUpdated(OptionId option, int value ) {} diff --git a/src/Minecraft.h b/src/Minecraft.hpp similarity index 95% rename from src/Minecraft.h rename to src/Minecraft.hpp index 1842493..5eb14e7 100755 --- a/src/Minecraft.h +++ b/src/Minecraft.hpp @@ -1,12 +1,12 @@ #pragma once -#include "client/Options.h" -#include "client/Timer.h" +#include "client/Options.hpp" +#include "client/Timer.hpp" -//#include "../network/RakNetInstance.h" -#include "world/phys/HitResult.h" +//#include "../network/RakNetInstance.hpp" +#include "world/phys/HitResult.hpp" -#include "App.h" +#include "App.hpp" #include class Level; diff --git a/src/MinecraftClient.cpp b/src/MinecraftClient.cpp index c505b59..7c5dc71 100644 --- a/src/MinecraftClient.cpp +++ b/src/MinecraftClient.cpp @@ -1,36 +1,36 @@ -#include "Minecraft.h" -#include "client/Options.h" -#include "client/gamemode/GameMode.h" -#include "client/gui/screens/ChatScreen.h" -#include "client/gui/screens/ConsoleScreen.h" -#include "client/gui/screens/DeathScreen.h" -#include "client/gui/screens/UsernameScreen.h" -#include "client/player/LocalPlayer.h" -#include "client/player/input/IBuildInput.h" -#include "client/player/input/IInputHolder.h" -#include "client/player/input/KeyboardInput.h" -#include "client/player/input/MouseBuildInput.h" -#include "client/player/input/MouseTurnInput.h" -#include "client/player/input/touchscreen/TouchscreenInput.h" -#include "client/player/input/touchscreen/TouchInputHolder.h" -#include "client/renderer/Chunk.h" -#include "client/renderer/EntityTileRenderer.h" -#include "client/renderer/ItemInHandRenderer.h" -#include "client/renderer/Tesselator.h" -#include "client/renderer/entity/EntityRenderDispatcher.h" -#include "client/renderer/entity/ItemRenderer.h" -#include "client/renderer/ptexture/DynamicTexture.h" -#include "network/RakNetInstance.h" -#include "network/ServerSideNetworkHandler.h" -#include "network/packet/InteractPacket.h" -#include "network/packet/RespawnPacket.h" -#include "platform/CThread.h" -#include "platform/input/Multitouch.h" -#include "util/PerfRenderer.h" -#include "util/PerfTimer.h" -#include "world/level/Level.h" -#include "world/level/chunk/ChunkSource.h" -#include +#include "Minecraft.hpp" +#include "client/Options.hpp" +#include "client/gamemode/GameMode.hpp" +#include "client/gui/screens/ChatScreen.hpp" +#include "client/gui/screens/ConsoleScreen.hpp" +#include "client/gui/screens/DeathScreen.hpp" +#include "client/gui/screens/UsernameScreen.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/player/input/IBuildInput.hpp" +#include "client/player/input/IInputHolder.hpp" +#include "client/player/input/KeyboardInput.hpp" +#include "client/player/input/MouseBuildInput.hpp" +#include "client/player/input/MouseTurnInput.hpp" +#include "client/player/input/touchscreen/TouchscreenInput.hpp" +#include "client/player/input/touchscreen/TouchInputHolder.hpp" +#include "client/renderer/Chunk.hpp" +#include "client/renderer/EntityTileRenderer.hpp" +#include "client/renderer/ItemInHandRenderer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/entity/EntityRenderDispatcher.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "client/renderer/ptexture/DynamicTexture.hpp" +#include "network/RakNetInstance.hpp" +#include "network/ServerSideNetworkHandler.hpp" +#include "network/packet/InteractPacket.hpp" +#include "network/packet/RespawnPacket.hpp" +#include "platform/CThread.hpp" +#include "platform/input/Multitouch.hpp" +#include "util/PerfRenderer.hpp" +#include "util/PerfTimer.hpp" +#include "world/level/Level.hpp" +#include "world/level/chunk/ChunkSource.hpp" +#include static void checkGlError(const char* tag) { #ifdef GLDEBUG diff --git a/src/MinecraftClient.h b/src/MinecraftClient.hpp similarity index 87% rename from src/MinecraftClient.h rename to src/MinecraftClient.hpp index 5e68fa2..27639d6 100644 --- a/src/MinecraftClient.h +++ b/src/MinecraftClient.hpp @@ -1,18 +1,18 @@ #pragma once -#include "client/gui/Font.h" -#include "client/gui/Screen.h" -#include "client/particle/ParticleEngine.h" -#include "client/player/LocalPlayer.h" -#include "client/renderer/GameRenderer.h" -#include "client/renderer/Textures.h" -#include "client/sound/SoundEngine.h" -#include +#include "client/gui/Font.hpp" +#include "client/gui/Screen.hpp" +#include "client/particle/ParticleEngine.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/GameRenderer.hpp" +#include "client/renderer/Textures.hpp" +#include "client/sound/SoundEngine.hpp" +#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include class MinecraftClient : public Minecraft { public: diff --git a/src/MinecraftServer.cpp b/src/MinecraftServer.cpp index 6752e4b..fa0f30d 100644 --- a/src/MinecraftServer.cpp +++ b/src/MinecraftServer.cpp @@ -1,6 +1,6 @@ -#include "MinecraftServer.h" -#include -#include +#include "MinecraftServer.hpp" +#include +#include void MinecraftServer::hostMultiplayer(int port) { diff --git a/src/MinecraftServer.h b/src/MinecraftServer.hpp similarity index 88% rename from src/MinecraftServer.h rename to src/MinecraftServer.hpp index bd84890..5f65472 100644 --- a/src/MinecraftServer.h +++ b/src/MinecraftServer.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include class MinecraftServer : public Minecraft { public: diff --git a/src/Performance.cpp b/src/Performance.cpp index 82c1343..5aed66a 100755 --- a/src/Performance.cpp +++ b/src/Performance.cpp @@ -1,4 +1,4 @@ -#include "Performance.h" - -/*static*/ -StopwatchHandler Performance::watches; +#include "Performance.hpp" + +/*static*/ +StopwatchHandler Performance::watches; diff --git a/src/Performance.h b/src/Performance.hpp similarity index 74% rename from src/Performance.h rename to src/Performance.hpp index 1eec129..53d0940 100755 --- a/src/Performance.h +++ b/src/Performance.hpp @@ -1,6 +1,6 @@ #pragma once -#include "platform/time.h" +#include "platform/time.hpp" class Performance { diff --git a/src/SharedConstants.cpp b/src/SharedConstants.cpp index 4a31175..bd86c0e 100755 --- a/src/SharedConstants.cpp +++ b/src/SharedConstants.cpp @@ -1,16 +1,16 @@ -#include "SharedConstants.h" - -namespace Common { - -std::string getGameVersionString(const std::string& versionSuffix /* = "" */) -{ - std::string result = std::string("v0.6.1") + versionSuffix; - // append 64-bit port marker only on Android 64‑bit targets - #if defined(ANDROID) && (defined(__aarch64__) || defined(__x86_64__)) - result += " (64-bit port)"; - #endif - result += " alpha"; - return result; -} - -}; +#include "SharedConstants.hpp" + +namespace Common { + +std::string getGameVersionString(const std::string& versionSuffix /* = "" */) +{ + std::string result = std::string("v0.6.1") + versionSuffix; + // append 64-bit port marker only on Android 64‑bit targets + #if defined(ANDROID) && (defined(__aarch64__) || defined(__x86_64__)) + result += " (64-bit port)"; + #endif + result += " alpha"; + return result; +} + +}; diff --git a/src/SharedConstants.h b/src/SharedConstants.hpp similarity index 100% rename from src/SharedConstants.h rename to src/SharedConstants.hpp diff --git a/src/client/IConfigListener.cpp b/src/client/IConfigListener.cpp index 2c312e7..7b6792f 100755 --- a/src/client/IConfigListener.cpp +++ b/src/client/IConfigListener.cpp @@ -1,16 +1,16 @@ -#include "IConfigListener.h" -#include "Minecraft.h" -#ifndef STANDALONE_SERVER -#include "gui/Gui.h" -#endif /* STANDALONE_SERVER */ -Config createConfig(Minecraft* mc) { - Config c; - #ifndef STANDALONE_SERVER - c.setScreenSize(mc->width, mc->height, Gui::GuiScale); - #endif - c.pixelCalc = mc->pixelCalc; - c.pixelCalcUi = mc->pixelCalcUi; - c.minecraft = mc; - c.options = &mc->options; - return c; -} +#include "IConfigListener.hpp" +#include "Minecraft.hpp" +#ifndef STANDALONE_SERVER +#include "gui/Gui.hpp" +#endif /* STANDALONE_SERVER */ +Config createConfig(Minecraft* mc) { + Config c; + #ifndef STANDALONE_SERVER + c.setScreenSize(mc->width, mc->height, Gui::GuiScale); + #endif + c.pixelCalc = mc->pixelCalc; + c.pixelCalcUi = mc->pixelCalcUi; + c.minecraft = mc; + c.options = &mc->options; + return c; +} diff --git a/src/client/IConfigListener.h b/src/client/IConfigListener.hpp similarity index 97% rename from src/client/IConfigListener.h rename to src/client/IConfigListener.hpp index 9821c55..3c29a20 100755 --- a/src/client/IConfigListener.h +++ b/src/client/IConfigListener.hpp @@ -1,6 +1,6 @@ #pragma once -#include "PixelCalc.h" +#include "PixelCalc.hpp" class Minecraft; class Options; diff --git a/src/client/MouseHandler.cpp b/src/client/MouseHandler.cpp index d77e28b..bbfafe1 100755 --- a/src/client/MouseHandler.cpp +++ b/src/client/MouseHandler.cpp @@ -1,60 +1,60 @@ -#include "MouseHandler.h" -#include "player/input/ITurnInput.h" - -#ifdef RPI -#include -#endif - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) -#include -#endif - -MouseHandler::MouseHandler( ITurnInput* turnInput ) -: _turnInput(turnInput) -{} - -MouseHandler::MouseHandler() -: _turnInput(0) -{} - -MouseHandler::~MouseHandler() { -} - -void MouseHandler::setTurnInput( ITurnInput* turnInput ) { - _turnInput = turnInput; -} - -void MouseHandler::grab() { - xd = 0; - yd = 0; - -#if defined(RPI) - //LOGI("Grabbing input!\n"); - SDL_WM_GrabInput(SDL_GRAB_ON); - SDL_ShowCursor(0); -#endif - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); -#endif -} - -void MouseHandler::release() { -#if defined(RPI) - //LOGI("Releasing input!\n"); - SDL_WM_GrabInput(SDL_GRAB_OFF); - SDL_ShowCursor(1); -#endif - -#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) - glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); -#endif -} - -void MouseHandler::poll() { - if (_turnInput != 0) { - TurnDelta td = _turnInput->getTurnDelta(); - xd = td.x; - yd = td.y; - } -} +#include "MouseHandler.hpp" +#include "player/input/ITurnInput.hpp" + +#ifdef RPI +#include +#endif + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) +#include +#endif + +MouseHandler::MouseHandler( ITurnInput* turnInput ) +: _turnInput(turnInput) +{} + +MouseHandler::MouseHandler() +: _turnInput(0) +{} + +MouseHandler::~MouseHandler() { +} + +void MouseHandler::setTurnInput( ITurnInput* turnInput ) { + _turnInput = turnInput; +} + +void MouseHandler::grab() { + xd = 0; + yd = 0; + +#if defined(RPI) + //LOGI("Grabbing input!\n"); + SDL_WM_GrabInput(SDL_GRAB_ON); + SDL_ShowCursor(0); +#endif + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); +#endif +} + +void MouseHandler::release() { +#if defined(RPI) + //LOGI("Releasing input!\n"); + SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_ShowCursor(1); +#endif + +#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB) + glfwSetInputMode(glfwGetCurrentContext(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); +#endif +} + +void MouseHandler::poll() { + if (_turnInput != 0) { + TurnDelta td = _turnInput->getTurnDelta(); + xd = td.x; + yd = td.y; + } +} diff --git a/src/client/MouseHandler.h b/src/client/MouseHandler.hpp similarity index 100% rename from src/client/MouseHandler.h rename to src/client/MouseHandler.hpp diff --git a/src/client/Option.cpp b/src/client/Option.cpp index 5b8c422..f99752c 100644 --- a/src/client/Option.cpp +++ b/src/client/Option.cpp @@ -1,4 +1,4 @@ -#include "Option.h" +#include "Option.hpp" #include #include diff --git a/src/client/Option.h b/src/client/Option.hpp similarity index 99% rename from src/client/Option.h rename to src/client/Option.hpp index cc6547a..71fcbe9 100644 --- a/src/client/Option.h +++ b/src/client/Option.hpp @@ -1,7 +1,7 @@ #pragma once #include #include -#include +#include /* template struct is_option_type : std::false_type {}; diff --git a/src/client/OptionStrings.cpp b/src/client/OptionStrings.cpp index b856d17..4450517 100755 --- a/src/client/OptionStrings.cpp +++ b/src/client/OptionStrings.cpp @@ -1,4 +1,4 @@ -#include "OptionStrings.h" +#include "OptionStrings.hpp" const char* OptionStrings::Multiplayer_Username = "mp_username"; const char* OptionStrings::Multiplayer_ServerVisible = "mp_server_visible_default"; diff --git a/src/client/OptionStrings.h b/src/client/OptionStrings.hpp similarity index 100% rename from src/client/OptionStrings.h rename to src/client/OptionStrings.hpp diff --git a/src/client/Options.cpp b/src/client/Options.cpp index 69cd130..fa5d621 100755 --- a/src/client/Options.cpp +++ b/src/client/Options.cpp @@ -1,297 +1,297 @@ -#include "Options.h" -#include "../world/Difficulty.h" -#include - -bool Options::debugGl = false; - -// OPTIONS TABLE - -OptionInt difficulty("difficulty", Difficulty::NORMAL, 0, Difficulty::COUNT); -OptionBool hidegui("hidegui", false); -OptionBool thirdPersonView("thirdperson", false); -OptionBool renderDebug("renderDebug", false); -OptionBool smoothCamera("smoothCamera", false); -OptionBool fixedCamera("fixedCamera", false); -OptionBool isFlying("isflying", false); -OptionBool barOnTop("barOnTop", false); -OptionBool allowSprint("allowSprint", true); -OptionBool rpiCursor("rpiCursor", false); -OptionBool autoJump("autoJump", true); - - -OptionFloat flySpeed("flySpeed", 1.f); -OptionFloat cameraSpeed("cameraSpeed", 1.f); - -OptionInt guiScale("guiScale", 0, 0, 5); - -OptionString skin("skin", "Default"); - -#ifdef RPI -OptionString username("username", "StevePi"); -#else -OptionString username("username", "Steve"); -#endif - -OptionBool destroyVibration("destroyVibration", true); -OptionBool isLeftHanded("isLeftHanded", false); -OptionBool isJoyTouchArea("isJoyTouchArea", false); - -OptionFloat musicVolume("music", 1.f, MUSIC_MIN_VALUE, MUSIC_MAX_VALUE); -OptionFloat soundVolume("sound", 1.f, SOUND_MIN_VALUE, SOUND_MAX_VALUE); - -OptionFloat sensitivityOpt("sensitivity", 0.5f, SENSITIVITY_MIN_VALUE, SENSITIVITY_MAX_VALUE); - -OptionBool invertYMouse("invertMouse", false); -OptionInt viewDistance("renderDistance", 2, 0, 4); - -OptionBool anaglyph3d("anaglyph3d", false); -OptionBool limitFramerate("limitFramerate", false); -OptionBool vsync("vsync", true); -OptionBool fancyGraphics("fancyGraphics", true); -OptionBool viewBobbing("viewBobbing", true); -OptionBool ambientOcclusion("ao", false); - -OptionBool useTouchscreen("useTouchscreen", true); - -OptionBool serverVisible("servervisible", true); - -OptionInt keyForward("key.forward", Keyboard::KEY_W); -OptionInt keyLeft("key.left", Keyboard::KEY_A); -OptionInt keyBack("key.back", Keyboard::KEY_S); -OptionInt keyRight("key.right", Keyboard::KEY_D); -OptionInt keyJump("key.jump", Keyboard::KEY_SPACE); -OptionInt keyInventory("key.inventory", Keyboard::KEY_E); -OptionInt keySneak("key.sneak", Keyboard::KEY_LSHIFT); -OptionInt keyDrop("key.drop", Keyboard::KEY_Q); -OptionInt keyChat("key.chat", Keyboard::KEY_T); -OptionInt keyFog("key.fog", Keyboard::KEY_F); -OptionInt keyUse("key.use", Keyboard::KEY_U); - -// TODO: make human readable keycodes here -OptionInt keyMenuNext("key.menu.next", 40); -OptionInt keyMenuPrev("key.menu.previous", 38); -OptionInt keyMenuOk("key.menu.ok", 13); -OptionInt keyMenuCancel("key.menu.cancel", 8); - -OptionBool firstLaunch("firstLaunch", true); - -OptionString lastIp("lastip"); - -void Options::initTable() { - m_options[OPTIONS_DIFFICULTY] = &difficulty; - m_options[OPTIONS_HIDEGUI] = &hidegui; - m_options[OPTIONS_THIRD_PERSON_VIEW] = &thirdPersonView; - m_options[OPTIONS_RENDER_DEBUG] = &renderDebug; - m_options[OPTIONS_SMOOTH_CAMERA] = &smoothCamera; - m_options[OPTIONS_FIXED_CAMERA] = &fixedCamera; - m_options[OPTIONS_IS_FLYING] = &isFlying; - - m_options[OPTIONS_FLY_SPEED] = &flySpeed; - m_options[OPTIONS_CAMERA_SPEED] = &cameraSpeed; - - m_options[OPTIONS_GUI_SCALE] = &guiScale; - - m_options[OPTIONS_DESTROY_VIBRATION] = &destroyVibration; - - m_options[OPTIONS_IS_LEFT_HANDED] = &isLeftHanded; - m_options[OPTIONS_IS_JOY_TOUCH_AREA] = &isJoyTouchArea; - - m_options[OPTIONS_MUSIC_VOLUME] = &musicVolume; - m_options[OPTIONS_SOUND_VOLUME] = &soundVolume; - - #if defined(PLATFORM_DESKTOP) || defined(RPI) - float sensitivity = sensitivityOpt.get(); - sensitivity *= 0.4f; - sensitivityOpt.set(sensitivity); - #endif - - - m_options[OPTIONS_GUI_SCALE] = &guiScale; - - m_options[OPTIONS_SKIN] = &skin; - m_options[OPTIONS_USERNAME] = &username; - - m_options[OPTIONS_DESTROY_VIBRATION] = &destroyVibration; - m_options[OPTIONS_IS_LEFT_HANDED] = &isLeftHanded; - - m_options[OPTIONS_MUSIC_VOLUME] = &musicVolume; - m_options[OPTIONS_SOUND_VOLUME] = &soundVolume; - - m_options[OPTIONS_SENSITIVITY] = &sensitivityOpt; - - m_options[OPTIONS_INVERT_Y_MOUSE] = &invertYMouse; - m_options[OPTIONS_VIEW_DISTANCE] = &viewDistance; - - m_options[OPTIONS_ANAGLYPH_3D] = &anaglyph3d; - m_options[OPTIONS_LIMIT_FRAMERATE] = &limitFramerate; - m_options[OPTIONS_VSYNC] = &vsync; - m_options[OPTIONS_FANCY_GRAPHICS] = &fancyGraphics; - m_options[OPTIONS_VIEW_BOBBING] = &viewBobbing; - m_options[OPTIONS_AMBIENT_OCCLUSION] = &ambientOcclusion; - - m_options[OPTIONS_USE_TOUCHSCREEN] = &useTouchscreen; - - m_options[OPTIONS_SERVER_VISIBLE] = &serverVisible; - - m_options[OPTIONS_KEY_FORWARD] = &keyForward; - m_options[OPTIONS_KEY_LEFT] = &keyLeft; - m_options[OPTIONS_KEY_BACK] = &keyBack; - m_options[OPTIONS_KEY_RIGHT] = &keyRight; - m_options[OPTIONS_KEY_JUMP] = &keyJump; - m_options[OPTIONS_KEY_INVENTORY] = &keyInventory; - m_options[OPTIONS_KEY_SNEAK] = &keySneak; - m_options[OPTIONS_KEY_DROP] = &keyDrop; - m_options[OPTIONS_KEY_CHAT] = &keyChat; - m_options[OPTIONS_KEY_FOG] = &keyFog; - m_options[OPTIONS_KEY_USE] = &keyUse; - - m_options[OPTIONS_KEY_MENU_NEXT] = &keyMenuNext; - m_options[OPTIONS_KEY_MENU_PREV] = &keyMenuPrev; - m_options[OPTIONS_KEY_MENU_OK] = &keyMenuOk; - m_options[OPTIONS_KEY_MENU_CANCEL] = &keyMenuCancel; - - m_options[OPTIONS_FIRST_LAUNCH] = &firstLaunch; - - m_options[OPTIONS_BAR_ON_TOP] = &barOnTop; - m_options[OPTIONS_ALLOW_SPRINT] = &allowSprint; - m_options[OPTIONS_RPI_CURSOR] = &rpiCursor; - - m_options[OPTIONS_AUTOJUMP] = &autoJump; - m_options[OPTIONS_LAST_IP] = &lastIp; -} - -void Options::set(OptionId key, const std::string& value) { - auto option = opt(key); - - if (option) { - option->set(value); - notifyOptionUpdate(key, value); - } -} - -void Options::set(OptionId key, float value) { - auto option = opt(key); - - if (option) { - option->set(value); - notifyOptionUpdate(key, value); - } -} - -void Options::set(OptionId key, int value) { - auto option = opt(key); - - if (option) { - option->set(value); - notifyOptionUpdate(key, value); - } -} - -void Options::toggle(OptionId key) { - auto option = opt(key); - - if (option) { - option->toggle(); - notifyOptionUpdate(key, option->get()); - } -} - -void Options::load() { - StringVector optionStrings = optionsFile.getOptionStrings(); - - for (auto i = 0; i < optionStrings.size(); i += 2) { - const std::string& key = optionStrings[i]; - const std::string& value = optionStrings[i+1]; - - // FIXME: woah this is so slow - auto opt = std::find_if(m_options.begin(), m_options.end(), [&](auto& it) { - return it != nullptr && it->getStringId() == key; - }); - - if (opt == m_options.end()) continue; - - (*opt)->parse(value); -/* - // //LOGI("reading key: %s (%s)\n", key.c_str(), value.c_str()); - - // // Multiplayer - // // if (key == OptionStrings::Multiplayer_Username) username = value; - // if (key == OptionStrings::Multiplayer_ServerVisible) { - // m_options[OPTIONS_SERVER_VISIBLE] = readBool(value); - // } - - // // Controls - // if (key == OptionStrings::Controls_Sensitivity) { - // float sens = readFloat(value); - - // // sens is in range [0,1] with default/center at 0.5 (for aesthetics) - // // We wanna map it to something like [0.3, 0.9] BUT keep 0.5 @ ~0.5... - // m_options[OPTIONS_SENSITIVITY] = 0.3f + std::pow(1.1f * sens, 1.3f) * 0.42f; - // } - - // if (key == OptionStrings::Controls_InvertMouse) { - // m_options[OPTIONS_INVERT_Y_MOUSE] = readBool(value); - // } - - // if (key == OptionStrings::Controls_IsLefthanded) { - // m_options[OPTIONS_IS_LEFT_HANDED] = readBool(value); - // } - - // if (key == OptionStrings::Controls_UseTouchJoypad) { - // m_options[OPTIONS_IS_JOY_TOUCH_AREA] = readBool(value) && minecraft->useTouchscreen(); - // } - - // // Feedback - // if (key == OptionStrings::Controls_FeedbackVibration) { - // m_options[OPTIONS_DESTROY_VIBRATION] = readBool(value); - // } - - // // Graphics - // if (key == OptionStrings::Graphics_Fancy) { - // m_options[OPTIONS_FANCY_GRAPHICS] = readBool(value); - // } - - // // Graphics extras - // if (key == OptionStrings::Graphics_Vsync) { - // m_options[OPTIONS_VSYNC] = readBool(value); - // } - - // if (key == OptionStrings::Graphics_GUIScale) { - // m_options[OPTIONS_GUI_SCALE] = readInt(value) % 5; - // } - - // // Game - // if (key == OptionStrings::Game_DifficultyLevel) { - // readInt(value, difficulty); - // // Only support peaceful and normal right now - // if (difficulty != Difficulty::PEACEFUL && difficulty != Difficulty::NORMAL) - // difficulty = Difficulty::NORMAL; - // }*/ - } -} - -void Options::save() { - StringVector stringVec; - - for (auto& it : m_options) { - if (it) stringVec.push_back(it->serialize()); - } - - optionsFile.save(stringVec); -} - -void Options::setOptionsFilePath(const std::string& path) { - optionsFile.setOptionsPath(path + "/options.txt"); -} - -void Options::notifyOptionUpdate(OptionId key, bool value) { - minecraft.optionUpdated(key, value); -} - -void Options::notifyOptionUpdate(OptionId key, float value) { - minecraft.optionUpdated(key, value); -} - -void Options::notifyOptionUpdate(OptionId key, int value) { - minecraft.optionUpdated(key, value); -} +#include "Options.hpp" +#include "world/Difficulty.hpp" +#include + +bool Options::debugGl = false; + +// OPTIONS TABLE + +OptionInt difficulty("difficulty", Difficulty::NORMAL, 0, Difficulty::COUNT); +OptionBool hidegui("hidegui", false); +OptionBool thirdPersonView("thirdperson", false); +OptionBool renderDebug("renderDebug", false); +OptionBool smoothCamera("smoothCamera", false); +OptionBool fixedCamera("fixedCamera", false); +OptionBool isFlying("isflying", false); +OptionBool barOnTop("barOnTop", false); +OptionBool allowSprint("allowSprint", true); +OptionBool rpiCursor("rpiCursor", false); +OptionBool autoJump("autoJump", true); + + +OptionFloat flySpeed("flySpeed", 1.f); +OptionFloat cameraSpeed("cameraSpeed", 1.f); + +OptionInt guiScale("guiScale", 0, 0, 5); + +OptionString skin("skin", "Default"); + +#ifdef RPI +OptionString username("username", "StevePi"); +#else +OptionString username("username", "Steve"); +#endif + +OptionBool destroyVibration("destroyVibration", true); +OptionBool isLeftHanded("isLeftHanded", false); +OptionBool isJoyTouchArea("isJoyTouchArea", false); + +OptionFloat musicVolume("music", 1.f, MUSIC_MIN_VALUE, MUSIC_MAX_VALUE); +OptionFloat soundVolume("sound", 1.f, SOUND_MIN_VALUE, SOUND_MAX_VALUE); + +OptionFloat sensitivityOpt("sensitivity", 0.5f, SENSITIVITY_MIN_VALUE, SENSITIVITY_MAX_VALUE); + +OptionBool invertYMouse("invertMouse", false); +OptionInt viewDistance("renderDistance", 2, 0, 4); + +OptionBool anaglyph3d("anaglyph3d", false); +OptionBool limitFramerate("limitFramerate", false); +OptionBool vsync("vsync", true); +OptionBool fancyGraphics("fancyGraphics", true); +OptionBool viewBobbing("viewBobbing", true); +OptionBool ambientOcclusion("ao", false); + +OptionBool useTouchscreen("useTouchscreen", true); + +OptionBool serverVisible("servervisible", true); + +OptionInt keyForward("key.forward", Keyboard::KEY_W); +OptionInt keyLeft("key.left", Keyboard::KEY_A); +OptionInt keyBack("key.back", Keyboard::KEY_S); +OptionInt keyRight("key.right", Keyboard::KEY_D); +OptionInt keyJump("key.jump", Keyboard::KEY_SPACE); +OptionInt keyInventory("key.inventory", Keyboard::KEY_E); +OptionInt keySneak("key.sneak", Keyboard::KEY_LSHIFT); +OptionInt keyDrop("key.drop", Keyboard::KEY_Q); +OptionInt keyChat("key.chat", Keyboard::KEY_T); +OptionInt keyFog("key.fog", Keyboard::KEY_F); +OptionInt keyUse("key.use", Keyboard::KEY_U); + +// TODO: make human readable keycodes here +OptionInt keyMenuNext("key.menu.next", 40); +OptionInt keyMenuPrev("key.menu.previous", 38); +OptionInt keyMenuOk("key.menu.ok", 13); +OptionInt keyMenuCancel("key.menu.cancel", 8); + +OptionBool firstLaunch("firstLaunch", true); + +OptionString lastIp("lastip"); + +void Options::initTable() { + m_options[OPTIONS_DIFFICULTY] = &difficulty; + m_options[OPTIONS_HIDEGUI] = &hidegui; + m_options[OPTIONS_THIRD_PERSON_VIEW] = &thirdPersonView; + m_options[OPTIONS_RENDER_DEBUG] = &renderDebug; + m_options[OPTIONS_SMOOTH_CAMERA] = &smoothCamera; + m_options[OPTIONS_FIXED_CAMERA] = &fixedCamera; + m_options[OPTIONS_IS_FLYING] = &isFlying; + + m_options[OPTIONS_FLY_SPEED] = &flySpeed; + m_options[OPTIONS_CAMERA_SPEED] = &cameraSpeed; + + m_options[OPTIONS_GUI_SCALE] = &guiScale; + + m_options[OPTIONS_DESTROY_VIBRATION] = &destroyVibration; + + m_options[OPTIONS_IS_LEFT_HANDED] = &isLeftHanded; + m_options[OPTIONS_IS_JOY_TOUCH_AREA] = &isJoyTouchArea; + + m_options[OPTIONS_MUSIC_VOLUME] = &musicVolume; + m_options[OPTIONS_SOUND_VOLUME] = &soundVolume; + + #if defined(PLATFORM_DESKTOP) || defined(RPI) + float sensitivity = sensitivityOpt.get(); + sensitivity *= 0.4f; + sensitivityOpt.set(sensitivity); + #endif + + + m_options[OPTIONS_GUI_SCALE] = &guiScale; + + m_options[OPTIONS_SKIN] = &skin; + m_options[OPTIONS_USERNAME] = &username; + + m_options[OPTIONS_DESTROY_VIBRATION] = &destroyVibration; + m_options[OPTIONS_IS_LEFT_HANDED] = &isLeftHanded; + + m_options[OPTIONS_MUSIC_VOLUME] = &musicVolume; + m_options[OPTIONS_SOUND_VOLUME] = &soundVolume; + + m_options[OPTIONS_SENSITIVITY] = &sensitivityOpt; + + m_options[OPTIONS_INVERT_Y_MOUSE] = &invertYMouse; + m_options[OPTIONS_VIEW_DISTANCE] = &viewDistance; + + m_options[OPTIONS_ANAGLYPH_3D] = &anaglyph3d; + m_options[OPTIONS_LIMIT_FRAMERATE] = &limitFramerate; + m_options[OPTIONS_VSYNC] = &vsync; + m_options[OPTIONS_FANCY_GRAPHICS] = &fancyGraphics; + m_options[OPTIONS_VIEW_BOBBING] = &viewBobbing; + m_options[OPTIONS_AMBIENT_OCCLUSION] = &ambientOcclusion; + + m_options[OPTIONS_USE_TOUCHSCREEN] = &useTouchscreen; + + m_options[OPTIONS_SERVER_VISIBLE] = &serverVisible; + + m_options[OPTIONS_KEY_FORWARD] = &keyForward; + m_options[OPTIONS_KEY_LEFT] = &keyLeft; + m_options[OPTIONS_KEY_BACK] = &keyBack; + m_options[OPTIONS_KEY_RIGHT] = &keyRight; + m_options[OPTIONS_KEY_JUMP] = &keyJump; + m_options[OPTIONS_KEY_INVENTORY] = &keyInventory; + m_options[OPTIONS_KEY_SNEAK] = &keySneak; + m_options[OPTIONS_KEY_DROP] = &keyDrop; + m_options[OPTIONS_KEY_CHAT] = &keyChat; + m_options[OPTIONS_KEY_FOG] = &keyFog; + m_options[OPTIONS_KEY_USE] = &keyUse; + + m_options[OPTIONS_KEY_MENU_NEXT] = &keyMenuNext; + m_options[OPTIONS_KEY_MENU_PREV] = &keyMenuPrev; + m_options[OPTIONS_KEY_MENU_OK] = &keyMenuOk; + m_options[OPTIONS_KEY_MENU_CANCEL] = &keyMenuCancel; + + m_options[OPTIONS_FIRST_LAUNCH] = &firstLaunch; + + m_options[OPTIONS_BAR_ON_TOP] = &barOnTop; + m_options[OPTIONS_ALLOW_SPRINT] = &allowSprint; + m_options[OPTIONS_RPI_CURSOR] = &rpiCursor; + + m_options[OPTIONS_AUTOJUMP] = &autoJump; + m_options[OPTIONS_LAST_IP] = &lastIp; +} + +void Options::set(OptionId key, const std::string& value) { + auto option = opt(key); + + if (option) { + option->set(value); + notifyOptionUpdate(key, value); + } +} + +void Options::set(OptionId key, float value) { + auto option = opt(key); + + if (option) { + option->set(value); + notifyOptionUpdate(key, value); + } +} + +void Options::set(OptionId key, int value) { + auto option = opt(key); + + if (option) { + option->set(value); + notifyOptionUpdate(key, value); + } +} + +void Options::toggle(OptionId key) { + auto option = opt(key); + + if (option) { + option->toggle(); + notifyOptionUpdate(key, option->get()); + } +} + +void Options::load() { + StringVector optionStrings = optionsFile.getOptionStrings(); + + for (auto i = 0; i < optionStrings.size(); i += 2) { + const std::string& key = optionStrings[i]; + const std::string& value = optionStrings[i+1]; + + // FIXME: woah this is so slow + auto opt = std::find_if(m_options.begin(), m_options.end(), [&](auto& it) { + return it != nullptr && it->getStringId() == key; + }); + + if (opt == m_options.end()) continue; + + (*opt)->parse(value); +/* + // //LOGI("reading key: %s (%s)\n", key.c_str(), value.c_str()); + + // // Multiplayer + // // if (key == OptionStrings::Multiplayer_Username) username = value; + // if (key == OptionStrings::Multiplayer_ServerVisible) { + // m_options[OPTIONS_SERVER_VISIBLE] = readBool(value); + // } + + // // Controls + // if (key == OptionStrings::Controls_Sensitivity) { + // float sens = readFloat(value); + + // // sens is in range [0,1] with default/center at 0.5 (for aesthetics) + // // We wanna map it to something like [0.3, 0.9] BUT keep 0.5 @ ~0.5... + // m_options[OPTIONS_SENSITIVITY] = 0.3f + std::pow(1.1f * sens, 1.3f) * 0.42f; + // } + + // if (key == OptionStrings::Controls_InvertMouse) { + // m_options[OPTIONS_INVERT_Y_MOUSE] = readBool(value); + // } + + // if (key == OptionStrings::Controls_IsLefthanded) { + // m_options[OPTIONS_IS_LEFT_HANDED] = readBool(value); + // } + + // if (key == OptionStrings::Controls_UseTouchJoypad) { + // m_options[OPTIONS_IS_JOY_TOUCH_AREA] = readBool(value) && minecraft->useTouchscreen(); + // } + + // // Feedback + // if (key == OptionStrings::Controls_FeedbackVibration) { + // m_options[OPTIONS_DESTROY_VIBRATION] = readBool(value); + // } + + // // Graphics + // if (key == OptionStrings::Graphics_Fancy) { + // m_options[OPTIONS_FANCY_GRAPHICS] = readBool(value); + // } + + // // Graphics extras + // if (key == OptionStrings::Graphics_Vsync) { + // m_options[OPTIONS_VSYNC] = readBool(value); + // } + + // if (key == OptionStrings::Graphics_GUIScale) { + // m_options[OPTIONS_GUI_SCALE] = readInt(value) % 5; + // } + + // // Game + // if (key == OptionStrings::Game_DifficultyLevel) { + // readInt(value, difficulty); + // // Only support peaceful and normal right now + // if (difficulty != Difficulty::PEACEFUL && difficulty != Difficulty::NORMAL) + // difficulty = Difficulty::NORMAL; + // }*/ + } +} + +void Options::save() { + StringVector stringVec; + + for (auto& it : m_options) { + if (it) stringVec.push_back(it->serialize()); + } + + optionsFile.save(stringVec); +} + +void Options::setOptionsFilePath(const std::string& path) { + optionsFile.setOptionsPath(path + "/options.txt"); +} + +void Options::notifyOptionUpdate(OptionId key, bool value) { + minecraft.optionUpdated(key, value); +} + +void Options::notifyOptionUpdate(OptionId key, float value) { + minecraft.optionUpdated(key, value); +} + +void Options::notifyOptionUpdate(OptionId key, int value) { + minecraft.optionUpdated(key, value); +} diff --git a/src/client/Options.h b/src/client/Options.hpp similarity index 96% rename from src/client/Options.h rename to src/client/Options.hpp index 90435a5..56b6b54 100755 --- a/src/client/Options.h +++ b/src/client/Options.hpp @@ -11,13 +11,13 @@ //package net.minecraft.client; -//#include "locale/Language.h" +//#include "locale/Language.hpp" #include -#include -#include -#include "OptionsFile.h" -#include "Option.h" +#include +#include +#include "OptionsFile.hpp" +#include "Option.hpp" #include enum OptionId { diff --git a/src/client/OptionsFile.cpp b/src/client/OptionsFile.cpp index ef2a0dc..368541d 100755 --- a/src/client/OptionsFile.cpp +++ b/src/client/OptionsFile.cpp @@ -1,98 +1,98 @@ -#include "OptionsFile.h" -#include -#include -#include -#include - -#if defined(_WIN32) - #include -#else - #include - #include -#endif - -OptionsFile::OptionsFile() { -#ifdef __APPLE__ - settingsPath = "./Documents/options.txt"; -#elif defined(ANDROID) - settingsPath = "options.txt"; -#elif defined(__EMSCRIPTEN__) - settingsPath = "/games/com.mojang/options.txt"; -#else - settingsPath = "options.txt"; -#endif -} - -void OptionsFile::setOptionsPath(const std::string& path) { - settingsPath = path; -} - -std::string OptionsFile::getOptionsPath() const { - return settingsPath; -} -void OptionsFile::save(const StringVector& settings) { - FILE* pFile = fopen(settingsPath.c_str(), "w"); - - if (!pFile && errno == ENOENT) { - std::string dir = settingsPath; - size_t fpos = dir.find_last_of("/\\"); - if (fpos != std::string::npos) { - dir.resize(fpos); - - std::string toCreate; - for (size_t i = 0; i <= dir.size(); ++i) { - if (i == dir.size() || dir[i] == '/' || dir[i] == '\\') { - if (!toCreate.empty()) { -#if defined(_WIN32) - _mkdir(toCreate.c_str()); -#else - mkdir(toCreate.c_str(), 0755); -#endif - } - } - if (i < dir.size()) - toCreate.push_back(dir[i]); - } - } - - pFile = fopen(settingsPath.c_str(), "w"); - } - - if (!pFile) { - LOGI("OptionsFile::save failed: %s", strerror(errno)); - return; - } - - for (const auto& s : settings) { - fprintf(pFile, "%s\n", s.c_str()); - } - - fclose(pFile); -} - - -StringVector OptionsFile::getOptionStrings() { - StringVector returnVector; - FILE* pFile = fopen(settingsPath.c_str(), "r"); - if(pFile != NULL) { - char lineBuff[128]; - while(fgets(lineBuff, sizeof lineBuff, pFile)) { - // Strip trailing newline - size_t len = strlen(lineBuff); - while(len > 0 && (lineBuff[len-1] == '\n' || lineBuff[len-1] == '\r')) - lineBuff[--len] = '\0'; - if(len < 3) continue; - // Split "key:value" into two separate entries to match update() pairing - char* colon = strchr(lineBuff, ':'); - if(colon) { - returnVector.push_back(std::string(lineBuff, colon - lineBuff)); - returnVector.push_back(std::string(colon + 1)); - } - } - fclose(pFile); - } else { - if (errno != ENOENT) - LOGI("OptionsFile::getOptionStrings failed to open '%s' for reading: %s", settingsPath.c_str(), strerror(errno)); - } - return returnVector; -} +#include "OptionsFile.hpp" +#include +#include +#include +#include + +#if defined(_WIN32) + #include +#else + #include + #include +#endif + +OptionsFile::OptionsFile() { +#ifdef __APPLE__ + settingsPath = "./Documents/options.txt"; +#elif defined(ANDROID) + settingsPath = "options.txt"; +#elif defined(__EMSCRIPTEN__) + settingsPath = "/games/com.mojang/options.txt"; +#else + settingsPath = "options.txt"; +#endif +} + +void OptionsFile::setOptionsPath(const std::string& path) { + settingsPath = path; +} + +std::string OptionsFile::getOptionsPath() const { + return settingsPath; +} +void OptionsFile::save(const StringVector& settings) { + FILE* pFile = fopen(settingsPath.c_str(), "w"); + + if (!pFile && errno == ENOENT) { + std::string dir = settingsPath; + size_t fpos = dir.find_last_of("/\\"); + if (fpos != std::string::npos) { + dir.resize(fpos); + + std::string toCreate; + for (size_t i = 0; i <= dir.size(); ++i) { + if (i == dir.size() || dir[i] == '/' || dir[i] == '\\') { + if (!toCreate.empty()) { +#if defined(_WIN32) + _mkdir(toCreate.c_str()); +#else + mkdir(toCreate.c_str(), 0755); +#endif + } + } + if (i < dir.size()) + toCreate.push_back(dir[i]); + } + } + + pFile = fopen(settingsPath.c_str(), "w"); + } + + if (!pFile) { + LOGI("OptionsFile::save failed: %s", strerror(errno)); + return; + } + + for (const auto& s : settings) { + fprintf(pFile, "%s\n", s.c_str()); + } + + fclose(pFile); +} + + +StringVector OptionsFile::getOptionStrings() { + StringVector returnVector; + FILE* pFile = fopen(settingsPath.c_str(), "r"); + if(pFile != NULL) { + char lineBuff[128]; + while(fgets(lineBuff, sizeof lineBuff, pFile)) { + // Strip trailing newline + size_t len = strlen(lineBuff); + while(len > 0 && (lineBuff[len-1] == '\n' || lineBuff[len-1] == '\r')) + lineBuff[--len] = '\0'; + if(len < 3) continue; + // Split "key:value" into two separate entries to match update() pairing + char* colon = strchr(lineBuff, ':'); + if(colon) { + returnVector.push_back(std::string(lineBuff, colon - lineBuff)); + returnVector.push_back(std::string(colon + 1)); + } + } + fclose(pFile); + } else { + if (errno != ENOENT) + LOGI("OptionsFile::getOptionStrings failed to open '%s' for reading: %s", settingsPath.c_str(), strerror(errno)); + } + return returnVector; +} diff --git a/src/client/OptionsFile.h b/src/client/OptionsFile.hpp similarity index 100% rename from src/client/OptionsFile.h rename to src/client/OptionsFile.hpp diff --git a/src/client/PixelCalc.h b/src/client/PixelCalc.hpp similarity index 100% rename from src/client/PixelCalc.h rename to src/client/PixelCalc.hpp diff --git a/src/client/Timer.h b/src/client/Timer.hpp similarity index 99% rename from src/client/Timer.h rename to src/client/Timer.hpp index da51ef4..265f567 100755 --- a/src/client/Timer.h +++ b/src/client/Timer.hpp @@ -1,7 +1,7 @@ #pragma once //package net.minecraft.client; -#include "../platform/time.h" +#include "platform/time.hpp" class Timer { diff --git a/src/client/gui/Font.cpp b/src/client/gui/Font.cpp index 3f88fc6..8911370 100755 --- a/src/client/gui/Font.cpp +++ b/src/client/gui/Font.cpp @@ -1,372 +1,372 @@ -#include "Font.h" - -//#include "SharedConstants.h" -#include "../Options.h" -#include "../renderer/Textures.h" -#include "../renderer/Tesselator.h" -#include "../../util/Mth.h" -#include - -Font::Font( Options* options, const std::string& name, Textures* textures ) -: options(options), - fontTexture(0), - fontName(name), - index(0), - count(0), - _textures(textures), - _x(0), _y(0), - _cols(16), _rows(16), - _charOffset(0), - lineHeight(DefaultLineHeight) -{ - init(options); -} - - -//Font::Font( Options* options, const std::string& name, Textures* textures, int imgW, int imgH, int x, int y, int cols, int rows, unsigned char charOffset ) -//: options(options), -// fontTexture(0), -// fontName(name), -// index(0), -// count(0), -// _textures(textures), -// _x(x), _y(y), -// _cols(cols), _rows(rows), -// _charOffset(charOffset) -//{ -// init(options); -//} - -void Font::onGraphicsReset() -{ - init(options); -} - -void Font::init( Options* options ) -{ - TextureId fontTexture = _textures->loadTexture(fontName); - const TextureData* tex = _textures->getTemporaryTextureData(fontTexture); - - if (!tex) - return; - - unsigned char* rawPixels = tex->data; - - const int numChars = _rows * _cols; - for (int i = 0; i < numChars; i++) { - int xt = i % _cols; - int yt = i / _cols; - - int x = 7; - for (; x >= 0; x--) { - int xPixel = _x + xt * 8 + x; - bool emptyColumn = true; - for (int y = 0; y < 8 && emptyColumn; y++) { - int yPixel = _y + (yt * 8 + y) * tex->w; - unsigned char pixelalpha = rawPixels[(xPixel + yPixel) << 2]; - if (pixelalpha > 0) emptyColumn = false; - } - if (!emptyColumn) { - break; - } - } - - if (i == ' ') x = 4 - 2; - charWidths[i] = x + 2; - fcharWidths[i] = (float) charWidths[i]; - } - -#ifdef USE_VBO - return; // this <1 -#endif - -#ifndef USE_VBO - listPos = glGenLists(256 + 32); - - Tesselator& t = Tesselator::instance; - for (int i = 0; i < 256; i++) { - glNewList(listPos + i, GL_COMPILE); - // @attn @huge @note: This is some dangerous code right here / Aron, added ^1 - t.begin(); - buildChar(i); - t.end(false, -1); - - glTranslatef2((GLfloat)charWidths[i], 0.0f, 0.0f); - glEndList(); - } - - for (int i = 0; i < 32; i++) { - int br = ((i >> 3) & 1) * 0x55; - int r = ((i >> 2) & 1) * 0xaa + br; - int g = ((i >> 1) & 1) * 0xaa + br; - int b = ((i >> 0) & 1) * 0xaa + br; - if (i == 6) { - r += 0x55; - } - bool darken = i >= 16; - - if (options->anaglyph3d) { - int cr = (r * 30 + g * 59 + b * 11) / 100; - int cg = (r * 30 + g * 70) / (100); - int cb = (r * 30 + b * 70) / (100); - - r = cr; - g = cg; - b = cb; - } - - // color = r << 16 | g << 8 | b; - if (darken) { - r /= 4; - g /= 4; - b /= 4; - } - - glNewList(listPos + 256 + i, GL_COMPILE); - glColor3f(r / 255.0f, g / 255.0f, b / 255.0f); - glEndList(); - } -#endif -} - -void Font::drawShadow( const std::string& str, float x, float y, int color ) -{ - draw(str, x + 1, y + 1, color, true); - draw(str, x, y, color); -} -void Font::drawShadow( const char* str, float x, float y, int color ) -{ - draw(str, x + 1, y + 1, color, true); - draw(str, x, y, color); -} - -void Font::draw( const std::string& str, float x, float y, int color ) -{ - draw(str, x, y, color, false); -} - -void Font::draw( const char* str, float x, float y, int color ) -{ - draw(str, x, y, color, false); -} - -void Font::draw( const char* str, float x, float y, int color, bool darken ) -{ -#ifdef USE_VBO - drawSlow(str, x, y, color, darken); -#endif -} - -void Font::draw( const std::string& str, float x, float y, int color, bool darken ) -{ -#ifdef USE_VBO - drawSlow(str, x, y, color, darken); - return; -#endif - - if (str.empty()) return; - - if (darken) { - int oldAlpha = color & 0xff000000; - color = (color & 0xfcfcfc) >> 2; - color += oldAlpha; - } - - _textures->loadAndBindTexture(fontName); - float r = ((color >> 16) & 0xff) / 255.0f; - float g = ((color >> 8) & 0xff) / 255.0f; - float b = ((color) & 0xff) / 255.0f; - float a = ((color >> 24) & 0xff) / 255.0f; - if (a == 0) a = 1; - glColor4f2(r, g, b, a); - - static const std::string hex("0123456789abcdef"); - - index = 0; - glPushMatrix2(); - glTranslatef2((GLfloat)x, (GLfloat)y, 0.0f); - for (unsigned int i = 0; i < str.length(); i++) { - while (str.length() > i + 1 && str[i] == '\xa7') { - int cc = hex.find((char)tolower(str[i + 1])); - if (cc < 0 || cc > 15) cc = 15; - lists[index++] = listPos + 256 + cc + (darken ? 16 : 0); - - if (index == 1024) { - count = index; - index = 0; -#ifndef USE_VBO - glCallLists(count, GL_UNSIGNED_INT, lists); -#endif - count = 1024; - } - - i += 2; - } - - if (i < str.length()) { - //int ch = SharedConstants.acceptableLetters.indexOf(str.charAt(i)); - char ch = str[i]; - if (ch >= 0) { - //ib.put(listPos + ch + 32); - lists[index++] = listPos + ch; - } - } - - if (index == 1024) { - count = index; - index = 0; -#ifndef USE_VBO - glCallLists(count, GL_UNSIGNED_INT, lists); -#endif - count = 1024; - } - } - count = index; - index = 0; -#ifndef USE_VBO - glCallLists(count, GL_UNSIGNED_INT, lists); -#endif - glPopMatrix2(); -} - -int Font::width( const std::string& str ) -{ - int maxLen = 0; - int len = 0; - - for (unsigned int i = 0; i < str.length(); i++) { - if (str[i] == '\xa7') { - i++; - } else { - //int ch = SharedConstants.acceptableLetters.indexOf(str.charAt(i)); - //if (ch >= 0) { - // len += charWidths[ch + 32]; - //} - if (str[i] == '\n') { - if (len > maxLen) maxLen = len; - len = 0; - } - else { - int charWidth = charWidths[ (unsigned char) str[i] ]; - len += charWidth; - } - } - } - return maxLen>len? maxLen : len; -} - -int Font::height( const std::string& str ) { - int h = 0; - bool hasLine = false; - for (unsigned int i = 0; i < str.length(); ++i) { - if (str[i] == '\n') hasLine = true; - else { - if (hasLine) h += lineHeight; - hasLine = false; - } - } - return h; -} - -std::string Font::sanitize( const std::string& str ) -{ - std::string sanitized(str.length() + 1, 0); - int j = 0; - - for (unsigned int i = 0; i < str.length(); i++) { - if (str[i] == '\xa7') { - i++; - //} else if (SharedConstants.acceptableLetters.indexOf(str.charAt(i)) >= 0) { - } else { - sanitized[j++] = str[i]; - } - } - return sanitized.erase(j); -} - -void Font::drawWordWrap( const std::string& str, float x, float y, float w, int col ) -{ - char* cstr = new char[str.length() + 1]; - strncpy(cstr, str.c_str(), str.length()); - cstr[str.length()] = 0; - - const char* lims = " \n\t\r"; - char* ptok = strtok(cstr, lims); - - std::vector words; - while (ptok != NULL) { - words.push_back( ptok ); - ptok = strtok(NULL, lims); - } - - delete[] cstr; - - int pos = 0; - while (pos < (int)words.size()) { - std::string line = words[pos++] + " "; - while (pos < (int)words.size() && width(line + words[pos]) < w) { - line += words[pos++] + " "; - } - drawShadow(line, x, y, col); - y += lineHeight; - } -} - -void Font::drawSlow( const std::string& str, float x, float y, int color, bool darken /*= false*/ ) { - drawSlow(str.c_str(), x, y, color, darken); -} -void Font::drawSlow( const char* str, float x, float y, int color, bool darken /*= false*/ ) -{ - if (!str) return; - - if (darken) { - int oldAlpha = color & 0xff000000; - color = (color & 0xfcfcfc) >> 2; - color += oldAlpha; - } - - _textures->loadAndBindTexture(fontName); - - Tesselator& t = Tesselator::instance; - t.begin(); - int alpha = (0xff000000 & color) >> 24; - if (!alpha) alpha = 0xff; - t.color((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, alpha); - - t.addOffset((float)x, (float)y, 0); - float xOffset = 0; - float yOffset = 0; - - while (unsigned char ch = *(str++)) { - if (ch == '\n') { - xOffset = 0; - yOffset += lineHeight; - } else { - buildChar(ch, xOffset, yOffset); - xOffset += fcharWidths[ch]; - } - } - t.draw(); - t.addOffset(-(float)x, -(float)y, 0); -} - -void Font::buildChar( unsigned char i, float x /*= 0*/, float y /*=0*/ ) -{ - Tesselator& t = Tesselator::instance; - - //i -= _charOffset; - //int ix = (i % _cols) * 8 + _x; - //int iy = (i / _cols) * 8 + _y; - float ix = (float)((i & 15) * 8); - float iy = (float)((i >> 4) * 8); - float s = 7.99f; - - float uo = (0.0f) / 128.0f; - float vo = (0.0f) / 128.0f; - - t.vertexUV(x, y + s, 0, ix / 128.0f + uo, (iy + s) / 128.0f + vo); - t.vertexUV(x + s, y + s, 0, (ix + s) / 128.0f + uo, (iy + s) / 128.0f + vo); - t.vertexUV(x + s, y, 0, (ix + s) / 128.0f + uo, iy / 128.0f + vo); - t.vertexUV(x, y, 0, ix / 128.0f + uo, iy / 128.0f + vo); -} - +#include "Font.hpp" + +//#include "SharedConstants.hpp" +#include "client/Options.hpp" +#include "client/renderer/Textures.hpp" +#include "client/renderer/Tesselator.hpp" +#include "util/Mth.hpp" +#include + +Font::Font( Options* options, const std::string& name, Textures* textures ) +: options(options), + fontTexture(0), + fontName(name), + index(0), + count(0), + _textures(textures), + _x(0), _y(0), + _cols(16), _rows(16), + _charOffset(0), + lineHeight(DefaultLineHeight) +{ + init(options); +} + + +//Font::Font( Options* options, const std::string& name, Textures* textures, int imgW, int imgH, int x, int y, int cols, int rows, unsigned char charOffset ) +//: options(options), +// fontTexture(0), +// fontName(name), +// index(0), +// count(0), +// _textures(textures), +// _x(x), _y(y), +// _cols(cols), _rows(rows), +// _charOffset(charOffset) +//{ +// init(options); +//} + +void Font::onGraphicsReset() +{ + init(options); +} + +void Font::init( Options* options ) +{ + TextureId fontTexture = _textures->loadTexture(fontName); + const TextureData* tex = _textures->getTemporaryTextureData(fontTexture); + + if (!tex) + return; + + unsigned char* rawPixels = tex->data; + + const int numChars = _rows * _cols; + for (int i = 0; i < numChars; i++) { + int xt = i % _cols; + int yt = i / _cols; + + int x = 7; + for (; x >= 0; x--) { + int xPixel = _x + xt * 8 + x; + bool emptyColumn = true; + for (int y = 0; y < 8 && emptyColumn; y++) { + int yPixel = _y + (yt * 8 + y) * tex->w; + unsigned char pixelalpha = rawPixels[(xPixel + yPixel) << 2]; + if (pixelalpha > 0) emptyColumn = false; + } + if (!emptyColumn) { + break; + } + } + + if (i == ' ') x = 4 - 2; + charWidths[i] = x + 2; + fcharWidths[i] = (float) charWidths[i]; + } + +#ifdef USE_VBO + return; // this <1 +#endif + +#ifndef USE_VBO + listPos = glGenLists(256 + 32); + + Tesselator& t = Tesselator::instance; + for (int i = 0; i < 256; i++) { + glNewList(listPos + i, GL_COMPILE); + // @attn @huge @note: This is some dangerous code right here / Aron, added ^1 + t.begin(); + buildChar(i); + t.end(false, -1); + + glTranslatef2((GLfloat)charWidths[i], 0.0f, 0.0f); + glEndList(); + } + + for (int i = 0; i < 32; i++) { + int br = ((i >> 3) & 1) * 0x55; + int r = ((i >> 2) & 1) * 0xaa + br; + int g = ((i >> 1) & 1) * 0xaa + br; + int b = ((i >> 0) & 1) * 0xaa + br; + if (i == 6) { + r += 0x55; + } + bool darken = i >= 16; + + if (options->anaglyph3d) { + int cr = (r * 30 + g * 59 + b * 11) / 100; + int cg = (r * 30 + g * 70) / (100); + int cb = (r * 30 + b * 70) / (100); + + r = cr; + g = cg; + b = cb; + } + + // color = r << 16 | g << 8 | b; + if (darken) { + r /= 4; + g /= 4; + b /= 4; + } + + glNewList(listPos + 256 + i, GL_COMPILE); + glColor3f(r / 255.0f, g / 255.0f, b / 255.0f); + glEndList(); + } +#endif +} + +void Font::drawShadow( const std::string& str, float x, float y, int color ) +{ + draw(str, x + 1, y + 1, color, true); + draw(str, x, y, color); +} +void Font::drawShadow( const char* str, float x, float y, int color ) +{ + draw(str, x + 1, y + 1, color, true); + draw(str, x, y, color); +} + +void Font::draw( const std::string& str, float x, float y, int color ) +{ + draw(str, x, y, color, false); +} + +void Font::draw( const char* str, float x, float y, int color ) +{ + draw(str, x, y, color, false); +} + +void Font::draw( const char* str, float x, float y, int color, bool darken ) +{ +#ifdef USE_VBO + drawSlow(str, x, y, color, darken); +#endif +} + +void Font::draw( const std::string& str, float x, float y, int color, bool darken ) +{ +#ifdef USE_VBO + drawSlow(str, x, y, color, darken); + return; +#endif + + if (str.empty()) return; + + if (darken) { + int oldAlpha = color & 0xff000000; + color = (color & 0xfcfcfc) >> 2; + color += oldAlpha; + } + + _textures->loadAndBindTexture(fontName); + float r = ((color >> 16) & 0xff) / 255.0f; + float g = ((color >> 8) & 0xff) / 255.0f; + float b = ((color) & 0xff) / 255.0f; + float a = ((color >> 24) & 0xff) / 255.0f; + if (a == 0) a = 1; + glColor4f2(r, g, b, a); + + static const std::string hex("0123456789abcdef"); + + index = 0; + glPushMatrix2(); + glTranslatef2((GLfloat)x, (GLfloat)y, 0.0f); + for (unsigned int i = 0; i < str.length(); i++) { + while (str.length() > i + 1 && str[i] == '\xa7') { + int cc = hex.find((char)tolower(str[i + 1])); + if (cc < 0 || cc > 15) cc = 15; + lists[index++] = listPos + 256 + cc + (darken ? 16 : 0); + + if (index == 1024) { + count = index; + index = 0; +#ifndef USE_VBO + glCallLists(count, GL_UNSIGNED_INT, lists); +#endif + count = 1024; + } + + i += 2; + } + + if (i < str.length()) { + //int ch = SharedConstants.acceptableLetters.indexOf(str.charAt(i)); + char ch = str[i]; + if (ch >= 0) { + //ib.put(listPos + ch + 32); + lists[index++] = listPos + ch; + } + } + + if (index == 1024) { + count = index; + index = 0; +#ifndef USE_VBO + glCallLists(count, GL_UNSIGNED_INT, lists); +#endif + count = 1024; + } + } + count = index; + index = 0; +#ifndef USE_VBO + glCallLists(count, GL_UNSIGNED_INT, lists); +#endif + glPopMatrix2(); +} + +int Font::width( const std::string& str ) +{ + int maxLen = 0; + int len = 0; + + for (unsigned int i = 0; i < str.length(); i++) { + if (str[i] == '\xa7') { + i++; + } else { + //int ch = SharedConstants.acceptableLetters.indexOf(str.charAt(i)); + //if (ch >= 0) { + // len += charWidths[ch + 32]; + //} + if (str[i] == '\n') { + if (len > maxLen) maxLen = len; + len = 0; + } + else { + int charWidth = charWidths[ (unsigned char) str[i] ]; + len += charWidth; + } + } + } + return maxLen>len? maxLen : len; +} + +int Font::height( const std::string& str ) { + int h = 0; + bool hasLine = false; + for (unsigned int i = 0; i < str.length(); ++i) { + if (str[i] == '\n') hasLine = true; + else { + if (hasLine) h += lineHeight; + hasLine = false; + } + } + return h; +} + +std::string Font::sanitize( const std::string& str ) +{ + std::string sanitized(str.length() + 1, 0); + int j = 0; + + for (unsigned int i = 0; i < str.length(); i++) { + if (str[i] == '\xa7') { + i++; + //} else if (SharedConstants.acceptableLetters.indexOf(str.charAt(i)) >= 0) { + } else { + sanitized[j++] = str[i]; + } + } + return sanitized.erase(j); +} + +void Font::drawWordWrap( const std::string& str, float x, float y, float w, int col ) +{ + char* cstr = new char[str.length() + 1]; + strncpy(cstr, str.c_str(), str.length()); + cstr[str.length()] = 0; + + const char* lims = " \n\t\r"; + char* ptok = strtok(cstr, lims); + + std::vector words; + while (ptok != NULL) { + words.push_back( ptok ); + ptok = strtok(NULL, lims); + } + + delete[] cstr; + + int pos = 0; + while (pos < (int)words.size()) { + std::string line = words[pos++] + " "; + while (pos < (int)words.size() && width(line + words[pos]) < w) { + line += words[pos++] + " "; + } + drawShadow(line, x, y, col); + y += lineHeight; + } +} + +void Font::drawSlow( const std::string& str, float x, float y, int color, bool darken /*= false*/ ) { + drawSlow(str.c_str(), x, y, color, darken); +} +void Font::drawSlow( const char* str, float x, float y, int color, bool darken /*= false*/ ) +{ + if (!str) return; + + if (darken) { + int oldAlpha = color & 0xff000000; + color = (color & 0xfcfcfc) >> 2; + color += oldAlpha; + } + + _textures->loadAndBindTexture(fontName); + + Tesselator& t = Tesselator::instance; + t.begin(); + int alpha = (0xff000000 & color) >> 24; + if (!alpha) alpha = 0xff; + t.color((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff, alpha); + + t.addOffset((float)x, (float)y, 0); + float xOffset = 0; + float yOffset = 0; + + while (unsigned char ch = *(str++)) { + if (ch == '\n') { + xOffset = 0; + yOffset += lineHeight; + } else { + buildChar(ch, xOffset, yOffset); + xOffset += fcharWidths[ch]; + } + } + t.draw(); + t.addOffset(-(float)x, -(float)y, 0); +} + +void Font::buildChar( unsigned char i, float x /*= 0*/, float y /*=0*/ ) +{ + Tesselator& t = Tesselator::instance; + + //i -= _charOffset; + //int ix = (i % _cols) * 8 + _x; + //int iy = (i / _cols) * 8 + _y; + float ix = (float)((i & 15) * 8); + float iy = (float)((i >> 4) * 8); + float s = 7.99f; + + float uo = (0.0f) / 128.0f; + float vo = (0.0f) / 128.0f; + + t.vertexUV(x, y + s, 0, ix / 128.0f + uo, (iy + s) / 128.0f + vo); + t.vertexUV(x + s, y + s, 0, (ix + s) / 128.0f + uo, (iy + s) / 128.0f + vo); + t.vertexUV(x + s, y, 0, (ix + s) / 128.0f + uo, iy / 128.0f + vo); + t.vertexUV(x, y, 0, ix / 128.0f + uo, iy / 128.0f + vo); +} + diff --git a/src/client/gui/Font.h b/src/client/gui/Font.hpp similarity index 97% rename from src/client/gui/Font.h rename to src/client/gui/Font.hpp index 6b70ae5..05827f0 100755 --- a/src/client/gui/Font.h +++ b/src/client/gui/Font.hpp @@ -5,7 +5,7 @@ #include #include -#include "../renderer/gles.h" +#include "client/renderer/gles.hpp" class Textures; class Options; diff --git a/src/client/gui/Gui.cpp b/src/client/gui/Gui.cpp index 95f39be..7a9a4ed 100755 --- a/src/client/gui/Gui.cpp +++ b/src/client/gui/Gui.cpp @@ -1,31 +1,31 @@ -#include "Gui.h" -#include "Font.h" -#include "MinecraftClient.h" -#include "client/Options.h" -#include "platform/input/Keyboard.h" -#include "screens/IngameBlockSelectionScreen.h" -#include "screens/ChatScreen.h" -#include "screens/ConsoleScreen.h" -#include -#include "../player/LocalPlayer.h" -#include "../renderer/Tesselator.h" -#include "../renderer/TileRenderer.h" -#include "../renderer/LevelRenderer.h" -#include "../renderer/GameRenderer.h" -#include "../renderer/entity/ItemRenderer.h" -#include "../player/input/IInputHolder.h" -#include "../gamemode/GameMode.h" -#include "../gamemode/CreativeMode.h" -#include "../renderer/Textures.h" -#include "../../AppConstants.h" -#include "../../world/entity/player/Inventory.h" -#include "../../world/level/material/Material.h" -#include "../../world/item/Item.h" -#include "../../world/item/ItemInstance.h" -#include "../../platform/input/Mouse.h" -#include "../../world/level/Level.h" -#include "../../world/PosTranslator.h" -#include "../../platform/time.h" +#include "Gui.hpp" +#include "Font.hpp" +#include "MinecraftClient.hpp" +#include "client/Options.hpp" +#include "platform/input/Keyboard.hpp" +#include "screens/IngameBlockSelectionScreen.hpp" +#include "screens/ChatScreen.hpp" +#include "screens/ConsoleScreen.hpp" +#include +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/TileRenderer.hpp" +#include "client/renderer/LevelRenderer.hpp" +#include "client/renderer/GameRenderer.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "client/player/input/IInputHolder.hpp" +#include "client/gamemode/GameMode.hpp" +#include "client/gamemode/CreativeMode.hpp" +#include "client/renderer/Textures.hpp" +#include "AppConstants.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/level/material/Material.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemInstance.hpp" +#include "platform/input/Mouse.hpp" +#include "world/level/Level.hpp" +#include "world/PosTranslator.hpp" +#include "platform/time.hpp" #include #include #include diff --git a/src/client/gui/Gui.h b/src/client/gui/Gui.hpp similarity index 93% rename from src/client/gui/Gui.h rename to src/client/gui/Gui.hpp index b5084ee..ca7e19b 100755 --- a/src/client/gui/Gui.h +++ b/src/client/gui/Gui.hpp @@ -2,12 +2,12 @@ //package net.minecraft.client.gui; -#include "GuiComponent.h" -#include "Font.h" -#include "../player/input/touchscreen/TouchAreaModel.h" -#include "../renderer/RenderChunk.h" -#include "../../util/Random.h" -#include "../IConfigListener.h" +#include "GuiComponent.hpp" +#include "Font.hpp" +#include "client/player/input/touchscreen/TouchAreaModel.hpp" +#include "client/renderer/RenderChunk.hpp" +#include "util/Random.hpp" +#include "client/IConfigListener.hpp" class MinecraftClient; class ItemInstance; diff --git a/src/client/gui/GuiComponent.cpp b/src/client/gui/GuiComponent.cpp index 884c96a..1d5735d 100755 --- a/src/client/gui/GuiComponent.cpp +++ b/src/client/gui/GuiComponent.cpp @@ -1,156 +1,156 @@ -#include "GuiComponent.h" - -#include "../renderer/Tesselator.h" -#include "../renderer/gles.h" -#include "Font.h" - - -GuiComponent::GuiComponent() -: blitOffset(0) -{ -} - -GuiComponent::~GuiComponent() -{ -} - -void GuiComponent::drawCenteredString( Font* font, const std::string& str, int x, int y, int color ) -{ - font->drawShadow(str, (float)(x - font->width(str) / 2), (float)(y - font->height(str) / 2), color); -} - -void GuiComponent::drawString( Font* font, const std::string& str, int x, int y, int color ) -{ - font->drawShadow(str, (float)x, (float)y /*- font->height(str)/2*/, color); -} - -void GuiComponent::blit( int x, int y, int sx, int sy, int w, int h, int sw/*=0*/, int sh/*=0*/ ) -{ - if (!sw) sw = w; - if (!sh) sh = h; - float us = 1 / 256.0f; - float vs = 1 / 256.0f; - Tesselator& t = Tesselator::instance; - t.begin(); - t.vertexUV((float)(x) , (float)(y + h), blitOffset, (float)(sx ) * us, (float)(sy + sh) * vs); - t.vertexUV((float)(x + w), (float)(y + h), blitOffset, (float)(sx + sw) * us, (float)(sy + sh) * vs); - t.vertexUV((float)(x + w), (float)(y) , blitOffset, (float)(sx + sw) * us, (float)(sy ) * vs); - t.vertexUV((float)(x) , (float)(y) , blitOffset, (float)(sx ) * us, (float)(sy ) * vs); - t.draw(); -} -void GuiComponent::blit( float x, float y, int sx, int sy, float w, float h, int sw/*=0*/, int sh/*=0*/ ) -{ - if (!sw) sw = (int)w; - if (!sh) sh = (int)h; - float us = 1 / 256.0f; - float vs = 1 / 256.0f; - Tesselator& t = Tesselator::instance; - t.begin(); - t.vertexUV(x , y + h, blitOffset, (float)(sx ) * us, (float)(sy + sh) * vs); - t.vertexUV(x + w, y + h, blitOffset, (float)(sx + sw) * us, (float)(sy + sh) * vs); - t.vertexUV(x + w, y , blitOffset, (float)(sx + sw) * us, (float)(sy ) * vs); - t.vertexUV(x , y , blitOffset, (float)(sx ) * us, (float)(sy ) * vs); - t.draw(); -} - -void GuiComponent::fill( int x0, int y0, int x1, int y1, int col ) { - fill((float)x0, (float)y0, (float)x1, (float)y1, col); -} -void GuiComponent::fill( float x0, float y0, float x1, float y1, int col ) -{ - //float a = ((col >> 24) & 0xff) / 255.0f; - //float r = ((col >> 16) & 0xff) / 255.0f; - //float g = ((col >> 8) & 0xff) / 255.0f; - //float b = ((col) & 0xff) / 255.0f; - //glColor4f2(r, g, b, a); - - Tesselator& t = Tesselator::instance; - glEnable2(GL_BLEND); - glDisable2(GL_TEXTURE_2D); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - //LOGI("col: %f, %f, %f, %f\n", r, g, b, a); - t.begin(); - const int color = (col&0xff00ff00) | ((col&0xff0000) >> 16) | ((col&0xff) << 16); - t.colorABGR(color); - t.vertex(x0, y1, 0); - t.vertex(x1, y1, 0); - t.vertex(x1, y0, 0); - t.vertex(x0, y0, 0); - t.draw(); - glEnable2(GL_TEXTURE_2D); - glDisable2(GL_BLEND); -} - -void GuiComponent::fillGradient( int x0, int y0, int x1, int y1, int col1, int col2 ) { - fillGradient((float)x0, (float)y0, (float)x1, (float)y1, col1, col2); -} -void GuiComponent::fillGradient( float x0, float y0, float x1, float y1, int col1, int col2 ) -{ - float a1 = ((col1 >> 24) & 0xff) / 255.0f; - float r1 = ((col1 >> 16) & 0xff) / 255.0f; - float g1 = ((col1 >> 8) & 0xff) / 255.0f; - float b1 = ((col1) & 0xff) / 255.0f; - - float a2 = ((col2 >> 24) & 0xff) / 255.0f; - float r2 = ((col2 >> 16) & 0xff) / 255.0f; - float g2 = ((col2 >> 8) & 0xff) / 255.0f; - float b2 = ((col2) & 0xff) / 255.0f; - glDisable2(GL_TEXTURE_2D); - glEnable2(GL_BLEND); - glDisable2(GL_ALPHA_TEST); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glShadeModel2(GL_SMOOTH); - - Tesselator& t = Tesselator::instance; - t.begin(); - t.color(r1, g1, b1, a1); - t.vertex(x1, y0, 0); - t.vertex(x0, y0, 0); - t.color(r2, g2, b2, a2); - t.vertex(x0, y1, 0); - t.vertex(x1, y1, 0); - t.draw(); - - glShadeModel2(GL_FLAT); - glDisable2(GL_BLEND); - glEnable2(GL_ALPHA_TEST); - glEnable2(GL_TEXTURE_2D); -} -void GuiComponent::fillHorizontalGradient( int x0, int y0, int x1, int y1, int col1, int col2 ) { - fillHorizontalGradient((float)x0, (float)y0, (float)x1, (float)y1, col1, col2); -} -void GuiComponent::fillHorizontalGradient( float x0, float y0, float x1, float y1, int col1, int col2 ) -{ - float a1 = ((col1 >> 24) & 0xff) / 255.0f; - float r1 = ((col1 >> 16) & 0xff) / 255.0f; - float g1 = ((col1 >> 8) & 0xff) / 255.0f; - float b1 = ((col1) & 0xff) / 255.0f; - - float a2 = ((col2 >> 24) & 0xff) / 255.0f; - float r2 = ((col2 >> 16) & 0xff) / 255.0f; - float g2 = ((col2 >> 8) & 0xff) / 255.0f; - float b2 = ((col2) & 0xff) / 255.0f; - glDisable2(GL_TEXTURE_2D); - glEnable2(GL_BLEND); - glDisable2(GL_ALPHA_TEST); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glShadeModel2(GL_SMOOTH); - - Tesselator& t = Tesselator::instance; - t.begin(); - t.color(r2, g2, b2, a2); - t.vertex(x1, y0, 0); - t.color(r1, g1, b1, a1); - t.vertex(x0, y0, 0); - t.color(r1, g1, b1, a1); - t.vertex(x0, y1, 0); - t.color(r2, g2, b2, a2); - t.vertex(x1, y1, 0); - t.draw(); - - glShadeModel2(GL_FLAT); - glDisable2(GL_BLEND); - glEnable2(GL_ALPHA_TEST); - glEnable2(GL_TEXTURE_2D); -} +#include "GuiComponent.hpp" + +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/gles.hpp" +#include "Font.hpp" + + +GuiComponent::GuiComponent() +: blitOffset(0) +{ +} + +GuiComponent::~GuiComponent() +{ +} + +void GuiComponent::drawCenteredString( Font* font, const std::string& str, int x, int y, int color ) +{ + font->drawShadow(str, (float)(x - font->width(str) / 2), (float)(y - font->height(str) / 2), color); +} + +void GuiComponent::drawString( Font* font, const std::string& str, int x, int y, int color ) +{ + font->drawShadow(str, (float)x, (float)y /*- font->height(str)/2*/, color); +} + +void GuiComponent::blit( int x, int y, int sx, int sy, int w, int h, int sw/*=0*/, int sh/*=0*/ ) +{ + if (!sw) sw = w; + if (!sh) sh = h; + float us = 1 / 256.0f; + float vs = 1 / 256.0f; + Tesselator& t = Tesselator::instance; + t.begin(); + t.vertexUV((float)(x) , (float)(y + h), blitOffset, (float)(sx ) * us, (float)(sy + sh) * vs); + t.vertexUV((float)(x + w), (float)(y + h), blitOffset, (float)(sx + sw) * us, (float)(sy + sh) * vs); + t.vertexUV((float)(x + w), (float)(y) , blitOffset, (float)(sx + sw) * us, (float)(sy ) * vs); + t.vertexUV((float)(x) , (float)(y) , blitOffset, (float)(sx ) * us, (float)(sy ) * vs); + t.draw(); +} +void GuiComponent::blit( float x, float y, int sx, int sy, float w, float h, int sw/*=0*/, int sh/*=0*/ ) +{ + if (!sw) sw = (int)w; + if (!sh) sh = (int)h; + float us = 1 / 256.0f; + float vs = 1 / 256.0f; + Tesselator& t = Tesselator::instance; + t.begin(); + t.vertexUV(x , y + h, blitOffset, (float)(sx ) * us, (float)(sy + sh) * vs); + t.vertexUV(x + w, y + h, blitOffset, (float)(sx + sw) * us, (float)(sy + sh) * vs); + t.vertexUV(x + w, y , blitOffset, (float)(sx + sw) * us, (float)(sy ) * vs); + t.vertexUV(x , y , blitOffset, (float)(sx ) * us, (float)(sy ) * vs); + t.draw(); +} + +void GuiComponent::fill( int x0, int y0, int x1, int y1, int col ) { + fill((float)x0, (float)y0, (float)x1, (float)y1, col); +} +void GuiComponent::fill( float x0, float y0, float x1, float y1, int col ) +{ + //float a = ((col >> 24) & 0xff) / 255.0f; + //float r = ((col >> 16) & 0xff) / 255.0f; + //float g = ((col >> 8) & 0xff) / 255.0f; + //float b = ((col) & 0xff) / 255.0f; + //glColor4f2(r, g, b, a); + + Tesselator& t = Tesselator::instance; + glEnable2(GL_BLEND); + glDisable2(GL_TEXTURE_2D); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + //LOGI("col: %f, %f, %f, %f\n", r, g, b, a); + t.begin(); + const int color = (col&0xff00ff00) | ((col&0xff0000) >> 16) | ((col&0xff) << 16); + t.colorABGR(color); + t.vertex(x0, y1, 0); + t.vertex(x1, y1, 0); + t.vertex(x1, y0, 0); + t.vertex(x0, y0, 0); + t.draw(); + glEnable2(GL_TEXTURE_2D); + glDisable2(GL_BLEND); +} + +void GuiComponent::fillGradient( int x0, int y0, int x1, int y1, int col1, int col2 ) { + fillGradient((float)x0, (float)y0, (float)x1, (float)y1, col1, col2); +} +void GuiComponent::fillGradient( float x0, float y0, float x1, float y1, int col1, int col2 ) +{ + float a1 = ((col1 >> 24) & 0xff) / 255.0f; + float r1 = ((col1 >> 16) & 0xff) / 255.0f; + float g1 = ((col1 >> 8) & 0xff) / 255.0f; + float b1 = ((col1) & 0xff) / 255.0f; + + float a2 = ((col2 >> 24) & 0xff) / 255.0f; + float r2 = ((col2 >> 16) & 0xff) / 255.0f; + float g2 = ((col2 >> 8) & 0xff) / 255.0f; + float b2 = ((col2) & 0xff) / 255.0f; + glDisable2(GL_TEXTURE_2D); + glEnable2(GL_BLEND); + glDisable2(GL_ALPHA_TEST); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glShadeModel2(GL_SMOOTH); + + Tesselator& t = Tesselator::instance; + t.begin(); + t.color(r1, g1, b1, a1); + t.vertex(x1, y0, 0); + t.vertex(x0, y0, 0); + t.color(r2, g2, b2, a2); + t.vertex(x0, y1, 0); + t.vertex(x1, y1, 0); + t.draw(); + + glShadeModel2(GL_FLAT); + glDisable2(GL_BLEND); + glEnable2(GL_ALPHA_TEST); + glEnable2(GL_TEXTURE_2D); +} +void GuiComponent::fillHorizontalGradient( int x0, int y0, int x1, int y1, int col1, int col2 ) { + fillHorizontalGradient((float)x0, (float)y0, (float)x1, (float)y1, col1, col2); +} +void GuiComponent::fillHorizontalGradient( float x0, float y0, float x1, float y1, int col1, int col2 ) +{ + float a1 = ((col1 >> 24) & 0xff) / 255.0f; + float r1 = ((col1 >> 16) & 0xff) / 255.0f; + float g1 = ((col1 >> 8) & 0xff) / 255.0f; + float b1 = ((col1) & 0xff) / 255.0f; + + float a2 = ((col2 >> 24) & 0xff) / 255.0f; + float r2 = ((col2 >> 16) & 0xff) / 255.0f; + float g2 = ((col2 >> 8) & 0xff) / 255.0f; + float b2 = ((col2) & 0xff) / 255.0f; + glDisable2(GL_TEXTURE_2D); + glEnable2(GL_BLEND); + glDisable2(GL_ALPHA_TEST); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glShadeModel2(GL_SMOOTH); + + Tesselator& t = Tesselator::instance; + t.begin(); + t.color(r2, g2, b2, a2); + t.vertex(x1, y0, 0); + t.color(r1, g1, b1, a1); + t.vertex(x0, y0, 0); + t.color(r1, g1, b1, a1); + t.vertex(x0, y1, 0); + t.color(r2, g2, b2, a2); + t.vertex(x1, y1, 0); + t.draw(); + + glShadeModel2(GL_FLAT); + glDisable2(GL_BLEND); + glEnable2(GL_ALPHA_TEST); + glEnable2(GL_TEXTURE_2D); +} diff --git a/src/client/gui/GuiComponent.h b/src/client/gui/GuiComponent.hpp similarity index 100% rename from src/client/gui/GuiComponent.h rename to src/client/gui/GuiComponent.hpp diff --git a/src/client/gui/Screen.cpp b/src/client/gui/Screen.cpp index d5a7994..1c5d249 100755 --- a/src/client/gui/Screen.cpp +++ b/src/client/gui/Screen.cpp @@ -1,291 +1,291 @@ -#include "Screen.h" -#include "components/Button.h" -#include "components/TextBox.h" -#include -#include "../renderer/Tesselator.h" -#include "../sound/SoundEngine.h" -#include "../../platform/input/Keyboard.h" -#include "../../platform/input/Mouse.h" -#include "../renderer/Textures.h" - -Screen::Screen() -: passEvents(false), - clickedButton(NULL), - tabButtonIndex(0), - width(1), - height(1), - minecraft(NULL), - font(NULL) -{ -} - -void Screen::render( int xm, int ym, float a ) -{ - for (unsigned int i = 0; i < buttons.size(); i++) { - Button* button = buttons[i]; - button->render(minecraft, xm, ym); - } - - // render any text boxes after buttons - for (unsigned int i = 0; i < textBoxes.size(); i++) { - TextBox* textbox = textBoxes[i]; - textbox->render(minecraft, xm, ym); - } -} - -void Screen::init( Minecraft* minecraft, int width, int height ) -{ - //particles = /*new*/ GuiParticles(minecraft); - this->minecraft = minecraft; - this->font = minecraft->font; - this->width = width; - this->height = height; - init(); - setupPositions(); - updateTabButtonSelection(); -} - -void Screen::init() -{ -} - -void Screen::setSize( int width, int height ) -{ - this->width = width; - this->height = height; - setupPositions(); -} - -bool Screen::handleBackEvent( bool isDown ) -{ - return false; -} - -void Screen::updateEvents() -{ - if (passEvents) - return; - - while (Mouse::next()) - mouseEvent(); - - while (Keyboard::next()) - keyboardEvent(); - while (Keyboard::nextTextChar()) - keyboardTextEvent(); -} - -void Screen::mouseEvent() -{ - const MouseAction& e = Mouse::getEvent(); - // forward wheel events to subclasses - if (e.action == MouseAction::ACTION_WHEEL) { - int xm = e.x * width / minecraft->width; - int ym = e.y * height / minecraft->height - 1; - mouseWheel(e.dx, e.dy, xm, ym); - return; - } - - if (!e.isButton()) - return; - - if (Mouse::getEventButtonState()) { - int xm = e.x * width / minecraft->width; - int ym = e.y * height / minecraft->height - 1; - mouseClicked(xm, ym, Mouse::getEventButton()); - } else { - int xm = e.x * width / minecraft->width; - int ym = e.y * height / minecraft->height - 1; - mouseReleased(xm, ym, Mouse::getEventButton()); - } -} - -void Screen::keyboardEvent() -{ - if (Keyboard::getEventKeyState()) { - //if (Keyboard.getEventKey() == Keyboard.KEY_F11) { - // minecraft->toggleFullScreen(); - // return; - //} - keyPressed(Keyboard::getEventKey()); - } -} -void Screen::keyboardTextEvent() -{ - charPressed(Keyboard::getChar()); -} -void Screen::renderBackground() -{ - renderBackground(0); -} - -void Screen::renderBackground( int vo ) -{ - if (minecraft->isLevelGenerated()) { - fillGradient(0, 0, width, height, 0xc0101010, 0xd0101010); - } else { - renderDirtBackground(vo); - } -} - -void Screen::renderDirtBackground( int vo ) -{ - //glDisable2(GL_LIGHTING); - glDisable2(GL_FOG); - Tesselator& t = Tesselator::instance; - minecraft->textures->loadAndBindTexture("gui/background.png"); - glColor4f2(1, 1, 1, 1); - float s = 32; - float fvo = (float) vo; - t.begin(); - t.color(0x404040); - t.vertexUV(0, (float)height, 0, 0, height / s + fvo); - t.vertexUV((float)width, (float)height, 0, width / s, (float)height / s + fvo); - t.vertexUV((float)width, 0, 0, (float)width / s, 0 + fvo); - t.vertexUV(0, 0, 0, 0, 0 + fvo); - t.draw(); -} - -bool Screen::isPauseScreen() -{ - return true; -} - -bool Screen::isErrorScreen() -{ - return false; -} - -bool Screen::isInGameScreen() -{ - return true; -} - -bool Screen::closeOnPlayerHurt() { - return false; -} - -void Screen::keyPressed( int eventKey ) -{ - if (eventKey == Keyboard::KEY_ESCAPE) { - minecraft->setScreen(NULL); - //minecraft->grabMouse(); - } - - // pass key events to any text boxes first - for (auto& textbox : textBoxes) { - textbox->keyPressed(minecraft, eventKey); - } - -#ifdef TABBING - if (minecraft->useTouchscreen()) - return; - - - // "Tabbing" the buttons (walking with keys) - const int tabButtonCount = tabButtons.size(); - if (!tabButtonCount) - return; - - Options& o = minecraft->options; - if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_NEXT)) - if (++tabButtonIndex == tabButtonCount) tabButtonIndex = 0; - if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_PREV)) - if (--tabButtonIndex == -1) tabButtonIndex = tabButtonCount-1; - if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_OK)) { - Button* button = tabButtons[tabButtonIndex]; - if (button->active) { - minecraft->soundEngine->playUI("random.click", 1, 1); - buttonClicked(button); - } - } - - updateTabButtonSelection(); -#endif -} - -void Screen::charPressed(char inputChar) { - for (auto& textbox : textBoxes) { - textbox->charPressed(minecraft, inputChar); - } -} - -void Screen::updateTabButtonSelection() -{ -#ifdef TABBING - if (minecraft->useTouchscreen()) - return; - - for (unsigned int i = 0; i < tabButtons.size(); ++i) - tabButtons[i]->selected = (i == tabButtonIndex); -#endif -} - -void Screen::mouseClicked( int x, int y, int buttonNum ) -{ - if (buttonNum == MouseAction::ACTION_LEFT) { - for (unsigned int i = 0; i < buttons.size(); ++i) { - Button* button = buttons[i]; - //LOGI("Hit-testing button: %p\n", button); - if (button->clicked(minecraft, x, y)) { - button->setPressed(); - - //LOGI("Hit-test successful: %p\n", button); - clickedButton = button; -/* -#if !defined(ANDROID) && !defined(__APPLE__) //if (!minecraft->isTouchscreen()) { - minecraft->soundEngine->playUI("random.click", 1, 1); - buttonClicked(button); -#endif } -*/ - } - } - } - - // let textboxes see the click regardless - for (auto& textbox : textBoxes) { - textbox->mouseClicked(minecraft, x, y, buttonNum); - } -} - -void Screen::mouseReleased( int x, int y, int buttonNum ) -{ - //LOGI("b_id: %d, (%p), text: %s\n", buttonNum, clickedButton, clickedButton?clickedButton->msg.c_str():""); - if (!clickedButton || buttonNum != MouseAction::ACTION_LEFT) return; - -#if 1 -//#if defined(ANDROID) || defined(__APPLE__) //if (minecraft->isTouchscreen()) { - for (unsigned int i = 0; i < buttons.size(); ++i) { - Button* button = buttons[i]; - if (clickedButton == button && button->clicked(minecraft, x, y)) { - buttonClicked(button); - minecraft->soundEngine->playUI("random.click", 1, 1); - clickedButton->released(x, y); - } - } -# else // } else { - clickedButton->released(x, y); -#endif // } - clickedButton = NULL; -} - -bool Screen::renderGameBehind() { - return true; -} - -bool Screen::hasClippingArea( IntRectangle& out ) -{ - return false; -} - -void Screen::lostFocus() { - for(std::vector::iterator it = textBoxes.begin(); it != textBoxes.end(); ++it) { - TextBox* tb = *it; - tb->loseFocus(minecraft); - } -} - -void Screen::toGUICoordinate( int& x, int& y ) { - x = x * width / minecraft->width; - y = y * height / minecraft->height - 1; -} +#include "Screen.hpp" +#include "components/Button.hpp" +#include "components/TextBox.hpp" +#include +#include "client/renderer/Tesselator.hpp" +#include "client/sound/SoundEngine.hpp" +#include "platform/input/Keyboard.hpp" +#include "platform/input/Mouse.hpp" +#include "client/renderer/Textures.hpp" + +Screen::Screen() +: passEvents(false), + clickedButton(NULL), + tabButtonIndex(0), + width(1), + height(1), + minecraft(NULL), + font(NULL) +{ +} + +void Screen::render( int xm, int ym, float a ) +{ + for (unsigned int i = 0; i < buttons.size(); i++) { + Button* button = buttons[i]; + button->render(minecraft, xm, ym); + } + + // render any text boxes after buttons + for (unsigned int i = 0; i < textBoxes.size(); i++) { + TextBox* textbox = textBoxes[i]; + textbox->render(minecraft, xm, ym); + } +} + +void Screen::init( Minecraft* minecraft, int width, int height ) +{ + //particles = /*new*/ GuiParticles(minecraft); + this->minecraft = minecraft; + this->font = minecraft->font; + this->width = width; + this->height = height; + init(); + setupPositions(); + updateTabButtonSelection(); +} + +void Screen::init() +{ +} + +void Screen::setSize( int width, int height ) +{ + this->width = width; + this->height = height; + setupPositions(); +} + +bool Screen::handleBackEvent( bool isDown ) +{ + return false; +} + +void Screen::updateEvents() +{ + if (passEvents) + return; + + while (Mouse::next()) + mouseEvent(); + + while (Keyboard::next()) + keyboardEvent(); + while (Keyboard::nextTextChar()) + keyboardTextEvent(); +} + +void Screen::mouseEvent() +{ + const MouseAction& e = Mouse::getEvent(); + // forward wheel events to subclasses + if (e.action == MouseAction::ACTION_WHEEL) { + int xm = e.x * width / minecraft->width; + int ym = e.y * height / minecraft->height - 1; + mouseWheel(e.dx, e.dy, xm, ym); + return; + } + + if (!e.isButton()) + return; + + if (Mouse::getEventButtonState()) { + int xm = e.x * width / minecraft->width; + int ym = e.y * height / minecraft->height - 1; + mouseClicked(xm, ym, Mouse::getEventButton()); + } else { + int xm = e.x * width / minecraft->width; + int ym = e.y * height / minecraft->height - 1; + mouseReleased(xm, ym, Mouse::getEventButton()); + } +} + +void Screen::keyboardEvent() +{ + if (Keyboard::getEventKeyState()) { + //if (Keyboard.getEventKey() == Keyboard.KEY_F11) { + // minecraft->toggleFullScreen(); + // return; + //} + keyPressed(Keyboard::getEventKey()); + } +} +void Screen::keyboardTextEvent() +{ + charPressed(Keyboard::getChar()); +} +void Screen::renderBackground() +{ + renderBackground(0); +} + +void Screen::renderBackground( int vo ) +{ + if (minecraft->isLevelGenerated()) { + fillGradient(0, 0, width, height, 0xc0101010, 0xd0101010); + } else { + renderDirtBackground(vo); + } +} + +void Screen::renderDirtBackground( int vo ) +{ + //glDisable2(GL_LIGHTING); + glDisable2(GL_FOG); + Tesselator& t = Tesselator::instance; + minecraft->textures->loadAndBindTexture("gui/background.png"); + glColor4f2(1, 1, 1, 1); + float s = 32; + float fvo = (float) vo; + t.begin(); + t.color(0x404040); + t.vertexUV(0, (float)height, 0, 0, height / s + fvo); + t.vertexUV((float)width, (float)height, 0, width / s, (float)height / s + fvo); + t.vertexUV((float)width, 0, 0, (float)width / s, 0 + fvo); + t.vertexUV(0, 0, 0, 0, 0 + fvo); + t.draw(); +} + +bool Screen::isPauseScreen() +{ + return true; +} + +bool Screen::isErrorScreen() +{ + return false; +} + +bool Screen::isInGameScreen() +{ + return true; +} + +bool Screen::closeOnPlayerHurt() { + return false; +} + +void Screen::keyPressed( int eventKey ) +{ + if (eventKey == Keyboard::KEY_ESCAPE) { + minecraft->setScreen(NULL); + //minecraft->grabMouse(); + } + + // pass key events to any text boxes first + for (auto& textbox : textBoxes) { + textbox->keyPressed(minecraft, eventKey); + } + +#ifdef TABBING + if (minecraft->useTouchscreen()) + return; + + + // "Tabbing" the buttons (walking with keys) + const int tabButtonCount = tabButtons.size(); + if (!tabButtonCount) + return; + + Options& o = minecraft->options; + if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_NEXT)) + if (++tabButtonIndex == tabButtonCount) tabButtonIndex = 0; + if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_PREV)) + if (--tabButtonIndex == -1) tabButtonIndex = tabButtonCount-1; + if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_OK)) { + Button* button = tabButtons[tabButtonIndex]; + if (button->active) { + minecraft->soundEngine->playUI("random.click", 1, 1); + buttonClicked(button); + } + } + + updateTabButtonSelection(); +#endif +} + +void Screen::charPressed(char inputChar) { + for (auto& textbox : textBoxes) { + textbox->charPressed(minecraft, inputChar); + } +} + +void Screen::updateTabButtonSelection() +{ +#ifdef TABBING + if (minecraft->useTouchscreen()) + return; + + for (unsigned int i = 0; i < tabButtons.size(); ++i) + tabButtons[i]->selected = (i == tabButtonIndex); +#endif +} + +void Screen::mouseClicked( int x, int y, int buttonNum ) +{ + if (buttonNum == MouseAction::ACTION_LEFT) { + for (unsigned int i = 0; i < buttons.size(); ++i) { + Button* button = buttons[i]; + //LOGI("Hit-testing button: %p\n", button); + if (button->clicked(minecraft, x, y)) { + button->setPressed(); + + //LOGI("Hit-test successful: %p\n", button); + clickedButton = button; +/* +#if !defined(ANDROID) && !defined(__APPLE__) //if (!minecraft->isTouchscreen()) { + minecraft->soundEngine->playUI("random.click", 1, 1); + buttonClicked(button); +#endif } +*/ + } + } + } + + // let textboxes see the click regardless + for (auto& textbox : textBoxes) { + textbox->mouseClicked(minecraft, x, y, buttonNum); + } +} + +void Screen::mouseReleased( int x, int y, int buttonNum ) +{ + //LOGI("b_id: %d, (%p), text: %s\n", buttonNum, clickedButton, clickedButton?clickedButton->msg.c_str():""); + if (!clickedButton || buttonNum != MouseAction::ACTION_LEFT) return; + +#if 1 +//#if defined(ANDROID) || defined(__APPLE__) //if (minecraft->isTouchscreen()) { + for (unsigned int i = 0; i < buttons.size(); ++i) { + Button* button = buttons[i]; + if (clickedButton == button && button->clicked(minecraft, x, y)) { + buttonClicked(button); + minecraft->soundEngine->playUI("random.click", 1, 1); + clickedButton->released(x, y); + } + } +# else // } else { + clickedButton->released(x, y); +#endif // } + clickedButton = NULL; +} + +bool Screen::renderGameBehind() { + return true; +} + +bool Screen::hasClippingArea( IntRectangle& out ) +{ + return false; +} + +void Screen::lostFocus() { + for(std::vector::iterator it = textBoxes.begin(); it != textBoxes.end(); ++it) { + TextBox* tb = *it; + tb->loseFocus(minecraft); + } +} + +void Screen::toGUICoordinate( int& x, int& y ) { + x = x * width / minecraft->width; + y = y * height / minecraft->height - 1; +} diff --git a/src/client/gui/Screen.h b/src/client/gui/Screen.hpp similarity index 98% rename from src/client/gui/Screen.h rename to src/client/gui/Screen.hpp index c0cda99..bd6053b 100755 --- a/src/client/gui/Screen.h +++ b/src/client/gui/Screen.hpp @@ -3,7 +3,7 @@ //package net.minecraft.client.gui; #include -#include "GuiComponent.h" +#include "GuiComponent.hpp" class Font; class Minecraft; diff --git a/src/client/gui/TweenData.h b/src/client/gui/TweenData.hpp similarity index 100% rename from src/client/gui/TweenData.h rename to src/client/gui/TweenData.hpp diff --git a/src/client/gui/components/Button.cpp b/src/client/gui/components/Button.cpp index 39022a7..a93962c 100755 --- a/src/client/gui/components/Button.cpp +++ b/src/client/gui/components/Button.cpp @@ -1,219 +1,219 @@ -#include "Button.h" -#include "../../Minecraft.h" -#include "../../renderer/Textures.h" - -Button::Button(int id, const std::string& msg) -: GuiElement(true, true, 0, 0, 200, 24), - id(id), - msg(msg), - selected(false), - _currentlyDown(false) -{ -} - -Button::Button( int id, int x, int y, const std::string& msg ) -: GuiElement(true, true, x, y, 200, 24), - id(id), - msg(msg), - selected(false), - _currentlyDown(false) -{ -} - -Button::Button( int id, int x, int y, int w, int h, const std::string& msg ) -: GuiElement(true, true, x, y, w, h), - id(id), - msg(msg), - selected(false), - _currentlyDown(false) -{ -} - -void Button::render( Minecraft* minecraft, int xm, int ym ) -{ - if (!visible) return; - - /* - minecraft->textures->loadAndBindTexture("gui/gui.png"); - glColor4f2(1, 1, 1, 1); - - //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); - int yImage = getYImage(hovered || selected); - - blit(x, y, 0, 46 + yImage * 20, w / 2, h, 0, 20); - blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); - */ - - renderBg(minecraft, xm, ym); - renderFace(minecraft, xm , ym); -} - -void Button::released( int mx, int my ) { - _currentlyDown = false; -} - -bool Button::clicked( Minecraft* minecraft, int mx, int my ) -{ - return active && mx >= x && my >= y && mx < x + width && my < y + height; -} - -void Button::setPressed() { - _currentlyDown = true; -} - -int Button::getYImage( bool hovered ) -{ - int res = 1; - if (!active) res = 0; - else if (hovered) res = 2; - return res; -} - -void Button::renderFace(Minecraft* mc, int xm, int ym) { - Font* font = mc->font; - if (!active) { - drawCenteredString(font, msg, x + width / 2, y + (height - 8) / 2, 0xffa0a0a0); - } else { - if (hovered(mc, xm, ym) || selected) { - drawCenteredString(font, msg, x + width / 2, y + (height - 8) / 2, 0xffffa0); - } else { - drawCenteredString(font, msg, x + width / 2, y + (height - 8) / 2, 0xe0e0e0); - } - } -} - -void Button::renderBg( Minecraft* minecraft, int xm, int ym ) -{ - minecraft->textures->loadAndBindTexture("gui/gui.png"); - glColor4f2(1, 1, 1, 1); - - //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); - int yImage = getYImage(selected || hovered(minecraft, xm, ym));; - - blit(x, y, 0, 46 + yImage * 20, width / 2, height, 0, 20); - blit(x + width / 2, y, 200 - width / 2, 46 + yImage * 20, width / 2, height, 0, 20); -} - -bool Button::hovered(Minecraft* minecraft, int xm , int ym) { - return minecraft->useTouchscreen()? (_currentlyDown && isInside(xm, ym)) : isInside(xm, ym); -} - -bool Button::isInside( int xm, int ym ) { - return xm >= x && ym >= y && xm < x + width && ym < y + height; -} - -// -// BlankButton -// -BlankButton::BlankButton(int id) -: super(id, "") -{ - visible = false; -} - -BlankButton::BlankButton(int id, int x, int y, int w, int h) -: super(id, x, y, w, h, "") -{ - visible = false; -} - -// -// The Touch-interface button -// -namespace Touch { - -TButton::TButton(int id, const std::string& msg) -: super(id, msg) -{ - width = 66; - height = 26; -} - -TButton::TButton( int id, int x, int y, const std::string& msg ) -: super(id, x, y, msg) -{ - width = 66; - height = 26; -} - -TButton::TButton( int id, int x, int y, int w, int h, const std::string& msg ) -: super(id, x, y, w, h, msg) -{ -} - -void TButton::renderBg( Minecraft* minecraft, int xm, int ym ) -{ - bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); - // bool hovered = active && (_currentlyDown && isInside(xm, ym)); - - minecraft->textures->loadAndBindTexture("gui/touchgui.png"); - - //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); - if (active) - glColor4f2(1, 1, 1, 1); - else - glColor4f2(0.5f, 0.5f, 0.5f, 1); - - blit(x, y, hovered?66:0, 0, width, height, 66, 26); - //blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); -} - - -// -// Header spacing in Touchscreen mode -// -THeader::THeader(int id, const std::string& msg) -: super(id, msg), - xText(-99999) -{ - active = false; - width = 66; - height = 26; -} - -THeader::THeader( int id, int x, int y, const std::string& msg ) -: super(id, x, y, msg), - xText(-99999) -{ - active = false; - width = 66; - height = 26; -} - -THeader::THeader( int id, int x, int y, int w, int h, const std::string& msg ) -: super(id, x, y, w, h, msg), - xText(-99999) -{ - active = false; -} - -void THeader::render( Minecraft* minecraft, int xm, int ym ) { - Font* font = minecraft->font; - renderBg(minecraft, xm, ym); - - int xx = x + width/2; - if (xText != -99999) - xx = xText; - drawCenteredString(font, msg, xx, y + (height - 8) / 2, 0xe0e0e0); -} - -void THeader::renderBg( Minecraft* minecraft, int xm, int ym ) -{ - minecraft->textures->loadAndBindTexture("gui/touchgui.png"); - - //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); - glColor4f2(1, 1, 1, 1); - - // Left cap - blit(x, y, 150, 26, 2, height-1, 2, 25); - // Middle - blit(x+2, y, 153, 26, width-3, height-1, 8, 25); - // Right cap - blit(x+width-2, y, 162, 26, 2, height-1, 2, 25); - // Shadow - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - blit(x, y+height-1, 153, 52, width, 3, 8, 3); -} - -}; +#include "Button.hpp" +#include "client/Minecraft.hpp" +#include "client/renderer/Textures.hpp" + +Button::Button(int id, const std::string& msg) +: GuiElement(true, true, 0, 0, 200, 24), + id(id), + msg(msg), + selected(false), + _currentlyDown(false) +{ +} + +Button::Button( int id, int x, int y, const std::string& msg ) +: GuiElement(true, true, x, y, 200, 24), + id(id), + msg(msg), + selected(false), + _currentlyDown(false) +{ +} + +Button::Button( int id, int x, int y, int w, int h, const std::string& msg ) +: GuiElement(true, true, x, y, w, h), + id(id), + msg(msg), + selected(false), + _currentlyDown(false) +{ +} + +void Button::render( Minecraft* minecraft, int xm, int ym ) +{ + if (!visible) return; + + /* + minecraft->textures->loadAndBindTexture("gui/gui.png"); + glColor4f2(1, 1, 1, 1); + + //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); + int yImage = getYImage(hovered || selected); + + blit(x, y, 0, 46 + yImage * 20, w / 2, h, 0, 20); + blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); + */ + + renderBg(minecraft, xm, ym); + renderFace(minecraft, xm , ym); +} + +void Button::released( int mx, int my ) { + _currentlyDown = false; +} + +bool Button::clicked( Minecraft* minecraft, int mx, int my ) +{ + return active && mx >= x && my >= y && mx < x + width && my < y + height; +} + +void Button::setPressed() { + _currentlyDown = true; +} + +int Button::getYImage( bool hovered ) +{ + int res = 1; + if (!active) res = 0; + else if (hovered) res = 2; + return res; +} + +void Button::renderFace(Minecraft* mc, int xm, int ym) { + Font* font = mc->font; + if (!active) { + drawCenteredString(font, msg, x + width / 2, y + (height - 8) / 2, 0xffa0a0a0); + } else { + if (hovered(mc, xm, ym) || selected) { + drawCenteredString(font, msg, x + width / 2, y + (height - 8) / 2, 0xffffa0); + } else { + drawCenteredString(font, msg, x + width / 2, y + (height - 8) / 2, 0xe0e0e0); + } + } +} + +void Button::renderBg( Minecraft* minecraft, int xm, int ym ) +{ + minecraft->textures->loadAndBindTexture("gui/gui.png"); + glColor4f2(1, 1, 1, 1); + + //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); + int yImage = getYImage(selected || hovered(minecraft, xm, ym));; + + blit(x, y, 0, 46 + yImage * 20, width / 2, height, 0, 20); + blit(x + width / 2, y, 200 - width / 2, 46 + yImage * 20, width / 2, height, 0, 20); +} + +bool Button::hovered(Minecraft* minecraft, int xm , int ym) { + return minecraft->useTouchscreen()? (_currentlyDown && isInside(xm, ym)) : isInside(xm, ym); +} + +bool Button::isInside( int xm, int ym ) { + return xm >= x && ym >= y && xm < x + width && ym < y + height; +} + +// +// BlankButton +// +BlankButton::BlankButton(int id) +: super(id, "") +{ + visible = false; +} + +BlankButton::BlankButton(int id, int x, int y, int w, int h) +: super(id, x, y, w, h, "") +{ + visible = false; +} + +// +// The Touch-interface button +// +namespace Touch { + +TButton::TButton(int id, const std::string& msg) +: super(id, msg) +{ + width = 66; + height = 26; +} + +TButton::TButton( int id, int x, int y, const std::string& msg ) +: super(id, x, y, msg) +{ + width = 66; + height = 26; +} + +TButton::TButton( int id, int x, int y, int w, int h, const std::string& msg ) +: super(id, x, y, w, h, msg) +{ +} + +void TButton::renderBg( Minecraft* minecraft, int xm, int ym ) +{ + bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); + // bool hovered = active && (_currentlyDown && isInside(xm, ym)); + + minecraft->textures->loadAndBindTexture("gui/touchgui.png"); + + //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); + if (active) + glColor4f2(1, 1, 1, 1); + else + glColor4f2(0.5f, 0.5f, 0.5f, 1); + + blit(x, y, hovered?66:0, 0, width, height, 66, 26); + //blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); +} + + +// +// Header spacing in Touchscreen mode +// +THeader::THeader(int id, const std::string& msg) +: super(id, msg), + xText(-99999) +{ + active = false; + width = 66; + height = 26; +} + +THeader::THeader( int id, int x, int y, const std::string& msg ) +: super(id, x, y, msg), + xText(-99999) +{ + active = false; + width = 66; + height = 26; +} + +THeader::THeader( int id, int x, int y, int w, int h, const std::string& msg ) +: super(id, x, y, w, h, msg), + xText(-99999) +{ + active = false; +} + +void THeader::render( Minecraft* minecraft, int xm, int ym ) { + Font* font = minecraft->font; + renderBg(minecraft, xm, ym); + + int xx = x + width/2; + if (xText != -99999) + xx = xText; + drawCenteredString(font, msg, xx, y + (height - 8) / 2, 0xe0e0e0); +} + +void THeader::renderBg( Minecraft* minecraft, int xm, int ym ) +{ + minecraft->textures->loadAndBindTexture("gui/touchgui.png"); + + //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); + glColor4f2(1, 1, 1, 1); + + // Left cap + blit(x, y, 150, 26, 2, height-1, 2, 25); + // Middle + blit(x+2, y, 153, 26, width-3, height-1, 8, 25); + // Right cap + blit(x+width-2, y, 162, 26, 2, height-1, 2, 25); + // Shadow + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + blit(x, y+height-1, 153, 52, width, 3, 8, 3); +} + +}; diff --git a/src/client/gui/components/Button.h b/src/client/gui/components/Button.hpp similarity index 97% rename from src/client/gui/components/Button.h rename to src/client/gui/components/Button.hpp index c06b0fe..3354969 100755 --- a/src/client/gui/components/Button.h +++ b/src/client/gui/components/Button.hpp @@ -3,8 +3,8 @@ //package net.minecraft.client.gui; #include -#include "GuiElement.h" -#include "../../Options.h" +#include "GuiElement.hpp" +#include "client/Options.hpp" class Font; class Minecraft; diff --git a/src/client/gui/components/GButton.cpp b/src/client/gui/components/GButton.cpp index 2ac8ade..988be4a 100755 --- a/src/client/gui/components/GButton.cpp +++ b/src/client/gui/components/GButton.cpp @@ -1 +1 @@ -#include "GuiElement.h" +#include "GuiElement.hpp" diff --git a/src/client/gui/components/GButton.h b/src/client/gui/components/GButton.hpp similarity index 98% rename from src/client/gui/components/GButton.h rename to src/client/gui/components/GButton.hpp index 758b4d3..f625e92 100755 --- a/src/client/gui/components/GButton.h +++ b/src/client/gui/components/GButton.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Button.h" +#include "Button.hpp" class GButton: public Button { typedef Button super; diff --git a/src/client/gui/components/GuiElement.cpp b/src/client/gui/components/GuiElement.cpp index 5f4804e..6dc75f1 100755 --- a/src/client/gui/components/GuiElement.cpp +++ b/src/client/gui/components/GuiElement.cpp @@ -1,20 +1,20 @@ -#include "GuiElement.h" - -GuiElement::GuiElement( bool active/*=false*/, bool visible/*=true*/, int x /*= 0*/, int y /*= 0*/, int width/*=24*/, int height/*=24*/ ) -: active(active), - visible(visible), - x(x), - y(y), - width(width), - height(height) { - -} - -bool GuiElement::pointInside( int x, int y ) { - if(x >= this->x && x < this->x + this->width) { - if(y >= this->y && y < this->y + this->height) { - return true; - } - } - return false; -} +#include "GuiElement.hpp" + +GuiElement::GuiElement( bool active/*=false*/, bool visible/*=true*/, int x /*= 0*/, int y /*= 0*/, int width/*=24*/, int height/*=24*/ ) +: active(active), + visible(visible), + x(x), + y(y), + width(width), + height(height) { + +} + +bool GuiElement::pointInside( int x, int y ) { + if(x >= this->x && x < this->x + this->width) { + if(y >= this->y && y < this->y + this->height) { + return true; + } + } + return false; +} diff --git a/src/client/gui/components/GuiElement.h b/src/client/gui/components/GuiElement.hpp similarity index 95% rename from src/client/gui/components/GuiElement.h rename to src/client/gui/components/GuiElement.hpp index 4df2b35..221aeba 100755 --- a/src/client/gui/components/GuiElement.h +++ b/src/client/gui/components/GuiElement.hpp @@ -1,5 +1,5 @@ #pragma once -#include "../GuiComponent.h" +#include "client/gui/GuiComponent.hpp" class Tesselator; class Minecraft; diff --git a/src/client/gui/components/GuiElementContainer.cpp b/src/client/gui/components/GuiElementContainer.cpp index 9cfbb09..795680e 100755 --- a/src/client/gui/components/GuiElementContainer.cpp +++ b/src/client/gui/components/GuiElementContainer.cpp @@ -1,66 +1,66 @@ -#include "GuiElementContainer.h" -#include -GuiElementContainer::GuiElementContainer( bool active/*=false*/, bool visible/*=true*/, int x /*= 0*/, int y /*= 0*/, int width/*=24*/, int height/*=24*/ ) -: GuiElement(active, visible, x, y, width, height) { - -} - -GuiElementContainer::~GuiElementContainer() { - while(!children.empty()) { - GuiElement* element = children.back(); - children.pop_back(); - delete element; - } -} - -void GuiElementContainer::render( Minecraft* minecraft, int xm, int ym ) { - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->render(minecraft, xm, ym); - } -} - -void GuiElementContainer::setupPositions() { - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->setupPositions(); - } -} - -void GuiElementContainer::addChild( GuiElement* element ) { - children.push_back(element); -} - -void GuiElementContainer::removeChild( GuiElement* element ) { - std::vector::iterator it = std::find(children.begin(), children.end(), element); - if(it != children.end()) - children.erase(it); -} - -void GuiElementContainer::tick( Minecraft* minecraft ) { - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->tick(minecraft); - } -} - -void GuiElementContainer::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->mouseClicked(minecraft, x, y, buttonNum); - } -} - -void GuiElementContainer::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->mouseReleased(minecraft, x, y, buttonNum); - } -} - -void GuiElementContainer::keyPressed(Minecraft* minecraft, int key) { - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->keyPressed(minecraft, key); - } -} - -void GuiElementContainer::charPressed(Minecraft* minecraft, char key) { - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->charPressed(minecraft, key); - } +#include "GuiElementContainer.hpp" +#include +GuiElementContainer::GuiElementContainer( bool active/*=false*/, bool visible/*=true*/, int x /*= 0*/, int y /*= 0*/, int width/*=24*/, int height/*=24*/ ) +: GuiElement(active, visible, x, y, width, height) { + +} + +GuiElementContainer::~GuiElementContainer() { + while(!children.empty()) { + GuiElement* element = children.back(); + children.pop_back(); + delete element; + } +} + +void GuiElementContainer::render( Minecraft* minecraft, int xm, int ym ) { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->render(minecraft, xm, ym); + } +} + +void GuiElementContainer::setupPositions() { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->setupPositions(); + } +} + +void GuiElementContainer::addChild( GuiElement* element ) { + children.push_back(element); +} + +void GuiElementContainer::removeChild( GuiElement* element ) { + std::vector::iterator it = std::find(children.begin(), children.end(), element); + if(it != children.end()) + children.erase(it); +} + +void GuiElementContainer::tick( Minecraft* minecraft ) { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->tick(minecraft); + } +} + +void GuiElementContainer::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->mouseClicked(minecraft, x, y, buttonNum); + } +} + +void GuiElementContainer::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->mouseReleased(minecraft, x, y, buttonNum); + } +} + +void GuiElementContainer::keyPressed(Minecraft* minecraft, int key) { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->keyPressed(minecraft, key); + } +} + +void GuiElementContainer::charPressed(Minecraft* minecraft, char key) { + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->charPressed(minecraft, key); + } } \ No newline at end of file diff --git a/src/client/gui/components/GuiElementContainer.h b/src/client/gui/components/GuiElementContainer.hpp similarity index 96% rename from src/client/gui/components/GuiElementContainer.h rename to src/client/gui/components/GuiElementContainer.hpp index 2808163..bbe9c7f 100755 --- a/src/client/gui/components/GuiElementContainer.h +++ b/src/client/gui/components/GuiElementContainer.hpp @@ -1,5 +1,5 @@ #pragma once -#include "GuiElement.h" +#include "GuiElement.hpp" #include class Tesselator; class Minecraft; diff --git a/src/client/gui/components/ImageButton.cpp b/src/client/gui/components/ImageButton.cpp index 3d95acc..586ea72 100755 --- a/src/client/gui/components/ImageButton.cpp +++ b/src/client/gui/components/ImageButton.cpp @@ -1,135 +1,135 @@ -#include "ImageButton.h" -#include "../../renderer/Tesselator.h" -#include "../../Minecraft.h" -#include "../../../platform/log.h" -#include "../../../util/Mth.h" -#include "../../renderer/Textures.h" -#include - - -ImageButton::ImageButton(int id, const std::string& msg) -: super(id, msg) -{ - setupDefault(); -} - -ImageButton::ImageButton(int id, const std::string& msg, const ImageDef& imagedef) -: super(id, msg), - _imageDef(imagedef) -{ - setupDefault(); -} - -void ImageButton::setupDefault() { - width = 48; - height = 48; - scaleWhenPressed = true; -} - -void ImageButton::setImageDef(const ImageDef& imageDef, bool setButtonSize) { - _imageDef = imageDef; - if (setButtonSize) { - width = (int)_imageDef.width; - height = (int)_imageDef.height; - } -} - -void ImageButton::render(Minecraft* minecraft, int xm, int ym) { - if (!visible) return; - - Font* font = minecraft->font; - - //minecraft->textures->loadAndBindTexture("gui/gui.png"); - glColor4f2(1, 1, 1, 1); - - bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); - bool IsSecondImage = isSecondImage(hovered); - - //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); - //int yImage = getYImage(hovered || selected); - - //blit(x, y, 0, 46 + yImage * 20, w / 2, h, 0, 20); - //blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); - - renderBg(minecraft, xm, ym); - - TextureId texId = (_imageDef.name.length() > 0)? minecraft->textures->loadAndBindTexture(_imageDef.name) : Textures::InvalidId; - if ( Textures::isTextureIdValid(texId) ) { - const ImageDef& d = _imageDef; - Tesselator& t = Tesselator::instance; - - t.begin(); - if (!active) t.color(0xff808080); - //else if (hovered||selected) t.color(0xffffffff); - //else t.color(0xffe0e0e0); - else t.color(0xffffffff); - - float hx = ((float) d.width) * 0.5f; - float hy = ((float) d.height) * 0.5f; - const float cx = ((float)x+d.x) + hx; - const float cy = ((float)y+d.y) + hy; - if (scaleWhenPressed && hovered) { - hx *= 0.95f; - hy *= 0.95f; - } - - const IntRectangle* src = _imageDef.getSrc(); - if (src) { - const TextureData* d = minecraft->textures->getTemporaryTextureData(texId); - if (d != NULL) { - float u0 = (src->x+(IsSecondImage?src->w:0)) / (float)d->w; - float u1 = (src->x+(IsSecondImage?2*src->w:src->w)) / (float)d->w; - float v0 = src->y / (float)d->h; - float v1 = (src->y+src->h) / (float)d->h; - t.vertexUV(cx-hx, cy-hy, blitOffset, u0, v0); - t.vertexUV(cx-hx, cy+hy, blitOffset, u0, v1); - t.vertexUV(cx+hx, cy+hy, blitOffset, u1, v1); - t.vertexUV(cx+hx, cy-hy, blitOffset, u1, v0); - } - } else { - t.vertexUV(cx-hx, cy-hy, blitOffset, 0, 0); - t.vertexUV(cx-hx, cy+hy, blitOffset, 0, 1); - t.vertexUV(cx+hx, cy+hy, blitOffset, 1, 1); - t.vertexUV(cx+hx, cy-hy, blitOffset, 1, 0); - } - t.draw(); - } - //blit(0, 0, 0, 0, 64, 64, 256, 256); - - //LOGI("%d %d\n", x+d.x, x+d.x+d.w); - - if (!active) { - drawCenteredString(font, msg, x + width / 2, y + 16/*(h - 16)*/, 0xffa0a0a0); - } else { - if (hovered || selected) { - drawCenteredString(font, msg, x + width / 2, y + 17/*(h - 16)*/, 0xffffa0); - } else { - drawCenteredString(font, msg, x + width / 2, y + 16/*(h - 48)*/, 0xe0e0e0); - } - } -} - - -// -// A toggleable Button -// -OptionButton::OptionButton(OptionId option) : m_optId(option), super(ButtonId, "") {} - -void OptionButton::toggle(Options* options) { - options->toggle(m_optId); - - // Update graphics here - updateImage(options); -} - -void OptionButton::updateImage(Options* options) { - _secondImage = options->getBooleanValue(m_optId); -} - -void OptionButton::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { - if(buttonNum == MouseAction::ACTION_LEFT) { - if(clicked(minecraft, x, y)) { - toggle(&minecraft->options); - } - } -} +#include "ImageButton.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/Minecraft.hpp" +#include "platform/log.hpp" +#include "util/Mth.hpp" +#include "client/renderer/Textures.hpp" +#include + + +ImageButton::ImageButton(int id, const std::string& msg) +: super(id, msg) +{ + setupDefault(); +} + +ImageButton::ImageButton(int id, const std::string& msg, const ImageDef& imagedef) +: super(id, msg), + _imageDef(imagedef) +{ + setupDefault(); +} + +void ImageButton::setupDefault() { + width = 48; + height = 48; + scaleWhenPressed = true; +} + +void ImageButton::setImageDef(const ImageDef& imageDef, bool setButtonSize) { + _imageDef = imageDef; + if (setButtonSize) { + width = (int)_imageDef.width; + height = (int)_imageDef.height; + } +} + +void ImageButton::render(Minecraft* minecraft, int xm, int ym) { + if (!visible) return; + + Font* font = minecraft->font; + + //minecraft->textures->loadAndBindTexture("gui/gui.png"); + glColor4f2(1, 1, 1, 1); + + bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); + bool IsSecondImage = isSecondImage(hovered); + + //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); + //int yImage = getYImage(hovered || selected); + + //blit(x, y, 0, 46 + yImage * 20, w / 2, h, 0, 20); + //blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); + + renderBg(minecraft, xm, ym); + + TextureId texId = (_imageDef.name.length() > 0)? minecraft->textures->loadAndBindTexture(_imageDef.name) : Textures::InvalidId; + if ( Textures::isTextureIdValid(texId) ) { + const ImageDef& d = _imageDef; + Tesselator& t = Tesselator::instance; + + t.begin(); + if (!active) t.color(0xff808080); + //else if (hovered||selected) t.color(0xffffffff); + //else t.color(0xffe0e0e0); + else t.color(0xffffffff); + + float hx = ((float) d.width) * 0.5f; + float hy = ((float) d.height) * 0.5f; + const float cx = ((float)x+d.x) + hx; + const float cy = ((float)y+d.y) + hy; + if (scaleWhenPressed && hovered) { + hx *= 0.95f; + hy *= 0.95f; + } + + const IntRectangle* src = _imageDef.getSrc(); + if (src) { + const TextureData* d = minecraft->textures->getTemporaryTextureData(texId); + if (d != NULL) { + float u0 = (src->x+(IsSecondImage?src->w:0)) / (float)d->w; + float u1 = (src->x+(IsSecondImage?2*src->w:src->w)) / (float)d->w; + float v0 = src->y / (float)d->h; + float v1 = (src->y+src->h) / (float)d->h; + t.vertexUV(cx-hx, cy-hy, blitOffset, u0, v0); + t.vertexUV(cx-hx, cy+hy, blitOffset, u0, v1); + t.vertexUV(cx+hx, cy+hy, blitOffset, u1, v1); + t.vertexUV(cx+hx, cy-hy, blitOffset, u1, v0); + } + } else { + t.vertexUV(cx-hx, cy-hy, blitOffset, 0, 0); + t.vertexUV(cx-hx, cy+hy, blitOffset, 0, 1); + t.vertexUV(cx+hx, cy+hy, blitOffset, 1, 1); + t.vertexUV(cx+hx, cy-hy, blitOffset, 1, 0); + } + t.draw(); + } + //blit(0, 0, 0, 0, 64, 64, 256, 256); + + //LOGI("%d %d\n", x+d.x, x+d.x+d.w); + + if (!active) { + drawCenteredString(font, msg, x + width / 2, y + 16/*(h - 16)*/, 0xffa0a0a0); + } else { + if (hovered || selected) { + drawCenteredString(font, msg, x + width / 2, y + 17/*(h - 16)*/, 0xffffa0); + } else { + drawCenteredString(font, msg, x + width / 2, y + 16/*(h - 48)*/, 0xe0e0e0); + } + } +} + + +// +// A toggleable Button +// +OptionButton::OptionButton(OptionId option) : m_optId(option), super(ButtonId, "") {} + +void OptionButton::toggle(Options* options) { + options->toggle(m_optId); + + // Update graphics here + updateImage(options); +} + +void OptionButton::updateImage(Options* options) { + _secondImage = options->getBooleanValue(m_optId); +} + +void OptionButton::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { + if(buttonNum == MouseAction::ACTION_LEFT) { + if(clicked(minecraft, x, y)) { + toggle(&minecraft->options); + } + } +} diff --git a/src/client/gui/components/ImageButton.h b/src/client/gui/components/ImageButton.hpp similarity index 98% rename from src/client/gui/components/ImageButton.h rename to src/client/gui/components/ImageButton.hpp index e0ec9f8..5782ba6 100755 --- a/src/client/gui/components/ImageButton.h +++ b/src/client/gui/components/ImageButton.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Button.h" +#include "Button.hpp" typedef struct IntRectangle { IntRectangle() diff --git a/src/client/gui/components/InventoryPane.cpp b/src/client/gui/components/InventoryPane.cpp index 1ee9334..a120173 100755 --- a/src/client/gui/components/InventoryPane.cpp +++ b/src/client/gui/components/InventoryPane.cpp @@ -1,206 +1,206 @@ -#include "InventoryPane.h" -#include "../Gui.h" -#include "../../Minecraft.h" -#include "../../player/input/touchscreen/TouchAreaModel.h" -#include "../../renderer/entity/ItemRenderer.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/Textures.h" -#include "../../../world/item/ItemInstance.h" -#include "../../../world/entity/player/Inventory.h" - -namespace Touch { - -static const int By = 6; // Border Frame height - -InventoryPane::InventoryPane( IInventoryPaneCallback* screen, Minecraft* mc, const IntRectangle& rect, int paneWidth, float clickMarginH, int numItems, int itemSize, int itemBorderSize) -: screen(screen), - mc(mc), - paneWidth(paneWidth), - rect(rect), - super( - SF_LockX|/*SF_Scissor|*/SF_ShowScrollbar|SF_NoHoldSelect, - rect, // Pane rect - IntRectangle(0, 0, itemSize, itemSize), // Item rect - 0, numItems, Gui::GuiScale), - BorderPixels(itemBorderSize), - lastItemIndex(-1), - lastItemTicks(-1), - fillMarginX(2), - fillMarginY(4), - markerType(1), - markerIndex(-1), - markerShare(0), - renderDecorations(true) -{ - _clickArea = new RectangleArea(0, 0, 0, 0); - area._x0 = rect.x - clickMarginH; - area._x1 = rect.x + rect.w + clickMarginH; - area._y0 -= By; - area._y1 += By; - - /* - const int left = bbox.x + (bbox.w - paneWidth) / 2; - bg.x = left; - bg.w = left + paneWidth; // @note: read as x1, not width - bg.y = bbox.y - fillMarginY; - bg.h = bbox.y + bbox.h + fillMarginY; // @note: read as y1, not width - */ -} - -InventoryPane::~InventoryPane() { - delete _clickArea; -} - -void InventoryPane::renderBatch( std::vector& items, float alpha ) -{ - //fill(bg.x, bg.y, bg.w, bg.h, 0xff333333); - fill((float)(bbox.x-fillMarginX-1), (float)(bbox.y-fillMarginY), (float)(bbox.x + bbox.w + fillMarginX+1), (float)(bbox.y + bbox.h + fillMarginY), 0xff333333); - //fill(0.0f, (float)(bbox.y-fillMarginY), 400.0f, (float)(bbox.y + bbox.h + fillMarginY), 0xff333333);//(float)(bbox.x-fillMarginX), (float)(bbox.y-fillMarginY), (float)(bbox.x + bbox.w + fillMarginX), (float)(bbox.y + bbox.h + fillMarginY), 0xff333333); - glEnable2(GL_BLEND); - glDisable2(GL_ALPHA_TEST); - std::vector inventoryItems = screen->getItems(this); - - glEnable2(GL_SCISSOR_TEST); - GLuint x = (GLuint)(screenScale * bbox.x); - GLuint y = mc->height - (GLuint)(screenScale * (bbox.y + bbox.h)); - GLuint w = (GLuint)(screenScale * bbox.w); - GLuint h = (GLuint)(screenScale * bbox.h); - glScissor(x, y, w, h); - - Tesselator& t = Tesselator::instance; - - t.beginOverride(); - t.colorABGR(0xffffffff); - for (unsigned int i = 0; i < items.size(); ++i) { - GridItem& item = items[i]; - blit(item.xf, item.yf, 200, 46, (float)itemBbox.w, (float)itemBbox.h, 16, 16); - } - mc->textures->loadAndBindTexture("gui/gui.png"); - t.endOverrideAndDraw(); - - GridItem* marked = NULL; - float mxx, myy; - - t.beginOverride(); - for (unsigned int i = 0; i < items.size(); ++i) { - GridItem& item = items[i]; - int j = item.id; - const ItemInstance* citem = inventoryItems[j]; - if (!citem) continue; - - bool allowed = true; - - t.enableColor(); - //#ifdef DEMO_MODE //@huge @attn - if (!screen->isAllowed(j)) { allowed = false; t.color( 64, 64, 64); } - else - //#endif - if (lastItemTicks > 0 && lastItemIndex == j) { - int gv = 255 - lastItemTicks * 15; - t.color(gv, gv, gv, (allowed && citem->count <= 0)?0x60:0xff); - } else { - t.color(255, 255, 255, (allowed && citem->count <= 0)?0x60:0xff); - } - t.noColor(); - float xx = Gui::floorAlignToScreenPixel(item.xf + BorderPixels + 4); - float yy = Gui::floorAlignToScreenPixel(item.yf + BorderPixels + 4); - ItemRenderer::renderGuiItem(NULL, mc->textures, citem, xx, yy, 16, 16, false); - - if (j == markerIndex && markerShare >= 0) - marked = &item, mxx = xx, myy = yy; - - } - t.endOverrideAndDraw(); - - if (marked) { - glDisable2(GL_TEXTURE_2D); - const float yy0 = myy - 5.0f; - const float yy1 = yy0 + 2; - fill(mxx, yy0, mxx + 16.0f, yy1, 0xff606060); - fill(mxx, yy0, mxx + markerShare * 16.0f, yy1, markerType==1?0xff00ff00:0xff476543); - glEnable2(GL_BLEND); - glEnable2(GL_TEXTURE_2D); - } - - - if (!mc->isCreativeMode()) { - const float ikText = Gui::InvGuiScale + Gui::InvGuiScale; - const float kText = 0.5f * Gui::GuiScale; - t.beginOverride(); - t.scale2d(ikText, ikText); - for (unsigned int i = 0; i < items.size(); ++i) { - GridItem& item = items[i]; - const ItemInstance* citem = inventoryItems[item.id]; - if (!citem) continue; - - char buf[64] = {0}; - /*int c = */ Gui::itemCountItoa(buf, citem->count); - - float tx = Gui::floorAlignToScreenPixel(kText * (item.xf + BorderPixels + 3)); - float ty = Gui::floorAlignToScreenPixel(kText * (item.yf + BorderPixels + 3)); - mc->gui.renderSlotText(citem, tx, ty, true, true); - } - t.resetScale(); - glEnable2(GL_BLEND); - t.endOverrideAndDraw(); - } - - if (renderDecorations) { - t.beginOverride(); - for (unsigned int i = 0; i < items.size(); ++i) { - GridItem& item = items[i]; - const ItemInstance* citem = inventoryItems[item.id]; - if (!citem || citem->isNull()) continue; - - if (citem->isDamaged()) { - ItemRenderer::renderGuiItemDecorations(citem, item.xf + 8, item.yf + 12); - } - } - - glDisable2(GL_TEXTURE_2D); - t.endOverrideAndDraw(); - glEnable2(GL_TEXTURE_2D); - } - glDisable2(GL_SCISSOR_TEST); - - //fillGradient(bbox.x - 1, bbox.y, bbox.x + bbox.w + 1, bbox.y + 20, 0x99000000, 0x00000000); - //fillGradient(bbox.x - 1, bbox.y + bbox.h - 20, bbox.x + bbox.w + 1, bbox.y + bbox.h, 0x00000000, 0x99000000); - fillGradient(bg.x - fillMarginX, bbox.y, bg.w + fillMarginX, bbox.y + 20, 0x99000000, 0x00000000); - fillGradient(bg.x - fillMarginX, bbox.y + bbox.h - 20, bg.w + fillMarginX, bbox.y + bbox.h, 0x00000000, 0x99000000); - - drawScrollBar(hScroll); - drawScrollBar(vScroll); -} - -bool InventoryPane::onSelect( int gridId, bool selected ) -{ - //screen->onItemSelected(gridId); - if (screen->isAllowed(gridId)) - if (screen->addItem(this, gridId)) { - lastItemIndex = gridId; - lastItemTicks = 7; - } - - return false; -} - -void InventoryPane::drawScrollBar( ScrollBar& sb ) { - if (sb.alpha <= 0) - return; - - const int color = ((int)(255.0f * sb.alpha) << 24) | 0xaaaaaa; - const float xx = (float)(bbox.x + bbox.w); - fill(xx - sb.w, sb.y, xx, sb.y + sb.h, color); -} - -void InventoryPane::tick() -{ - --lastItemTicks; - super::tick(); -} - -void InventoryPane::setRenderDecorations( bool value ) { - renderDecorations = value; -} - -} +#include "InventoryPane.hpp" +#include "client/gui/Gui.hpp" +#include "client/Minecraft.hpp" +#include "client/player/input/touchscreen/TouchAreaModel.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/entity/player/Inventory.hpp" + +namespace Touch { + +static const int By = 6; // Border Frame height + +InventoryPane::InventoryPane( IInventoryPaneCallback* screen, Minecraft* mc, const IntRectangle& rect, int paneWidth, float clickMarginH, int numItems, int itemSize, int itemBorderSize) +: screen(screen), + mc(mc), + paneWidth(paneWidth), + rect(rect), + super( + SF_LockX|/*SF_Scissor|*/SF_ShowScrollbar|SF_NoHoldSelect, + rect, // Pane rect + IntRectangle(0, 0, itemSize, itemSize), // Item rect + 0, numItems, Gui::GuiScale), + BorderPixels(itemBorderSize), + lastItemIndex(-1), + lastItemTicks(-1), + fillMarginX(2), + fillMarginY(4), + markerType(1), + markerIndex(-1), + markerShare(0), + renderDecorations(true) +{ + _clickArea = new RectangleArea(0, 0, 0, 0); + area._x0 = rect.x - clickMarginH; + area._x1 = rect.x + rect.w + clickMarginH; + area._y0 -= By; + area._y1 += By; + + /* + const int left = bbox.x + (bbox.w - paneWidth) / 2; + bg.x = left; + bg.w = left + paneWidth; // @note: read as x1, not width + bg.y = bbox.y - fillMarginY; + bg.h = bbox.y + bbox.h + fillMarginY; // @note: read as y1, not width + */ +} + +InventoryPane::~InventoryPane() { + delete _clickArea; +} + +void InventoryPane::renderBatch( std::vector& items, float alpha ) +{ + //fill(bg.x, bg.y, bg.w, bg.h, 0xff333333); + fill((float)(bbox.x-fillMarginX-1), (float)(bbox.y-fillMarginY), (float)(bbox.x + bbox.w + fillMarginX+1), (float)(bbox.y + bbox.h + fillMarginY), 0xff333333); + //fill(0.0f, (float)(bbox.y-fillMarginY), 400.0f, (float)(bbox.y + bbox.h + fillMarginY), 0xff333333);//(float)(bbox.x-fillMarginX), (float)(bbox.y-fillMarginY), (float)(bbox.x + bbox.w + fillMarginX), (float)(bbox.y + bbox.h + fillMarginY), 0xff333333); + glEnable2(GL_BLEND); + glDisable2(GL_ALPHA_TEST); + std::vector inventoryItems = screen->getItems(this); + + glEnable2(GL_SCISSOR_TEST); + GLuint x = (GLuint)(screenScale * bbox.x); + GLuint y = mc->height - (GLuint)(screenScale * (bbox.y + bbox.h)); + GLuint w = (GLuint)(screenScale * bbox.w); + GLuint h = (GLuint)(screenScale * bbox.h); + glScissor(x, y, w, h); + + Tesselator& t = Tesselator::instance; + + t.beginOverride(); + t.colorABGR(0xffffffff); + for (unsigned int i = 0; i < items.size(); ++i) { + GridItem& item = items[i]; + blit(item.xf, item.yf, 200, 46, (float)itemBbox.w, (float)itemBbox.h, 16, 16); + } + mc->textures->loadAndBindTexture("gui/gui.png"); + t.endOverrideAndDraw(); + + GridItem* marked = NULL; + float mxx, myy; + + t.beginOverride(); + for (unsigned int i = 0; i < items.size(); ++i) { + GridItem& item = items[i]; + int j = item.id; + const ItemInstance* citem = inventoryItems[j]; + if (!citem) continue; + + bool allowed = true; + + t.enableColor(); + //#ifdef DEMO_MODE //@huge @attn + if (!screen->isAllowed(j)) { allowed = false; t.color( 64, 64, 64); } + else + //#endif + if (lastItemTicks > 0 && lastItemIndex == j) { + int gv = 255 - lastItemTicks * 15; + t.color(gv, gv, gv, (allowed && citem->count <= 0)?0x60:0xff); + } else { + t.color(255, 255, 255, (allowed && citem->count <= 0)?0x60:0xff); + } + t.noColor(); + float xx = Gui::floorAlignToScreenPixel(item.xf + BorderPixels + 4); + float yy = Gui::floorAlignToScreenPixel(item.yf + BorderPixels + 4); + ItemRenderer::renderGuiItem(NULL, mc->textures, citem, xx, yy, 16, 16, false); + + if (j == markerIndex && markerShare >= 0) + marked = &item, mxx = xx, myy = yy; + + } + t.endOverrideAndDraw(); + + if (marked) { + glDisable2(GL_TEXTURE_2D); + const float yy0 = myy - 5.0f; + const float yy1 = yy0 + 2; + fill(mxx, yy0, mxx + 16.0f, yy1, 0xff606060); + fill(mxx, yy0, mxx + markerShare * 16.0f, yy1, markerType==1?0xff00ff00:0xff476543); + glEnable2(GL_BLEND); + glEnable2(GL_TEXTURE_2D); + } + + + if (!mc->isCreativeMode()) { + const float ikText = Gui::InvGuiScale + Gui::InvGuiScale; + const float kText = 0.5f * Gui::GuiScale; + t.beginOverride(); + t.scale2d(ikText, ikText); + for (unsigned int i = 0; i < items.size(); ++i) { + GridItem& item = items[i]; + const ItemInstance* citem = inventoryItems[item.id]; + if (!citem) continue; + + char buf[64] = {0}; + /*int c = */ Gui::itemCountItoa(buf, citem->count); + + float tx = Gui::floorAlignToScreenPixel(kText * (item.xf + BorderPixels + 3)); + float ty = Gui::floorAlignToScreenPixel(kText * (item.yf + BorderPixels + 3)); + mc->gui.renderSlotText(citem, tx, ty, true, true); + } + t.resetScale(); + glEnable2(GL_BLEND); + t.endOverrideAndDraw(); + } + + if (renderDecorations) { + t.beginOverride(); + for (unsigned int i = 0; i < items.size(); ++i) { + GridItem& item = items[i]; + const ItemInstance* citem = inventoryItems[item.id]; + if (!citem || citem->isNull()) continue; + + if (citem->isDamaged()) { + ItemRenderer::renderGuiItemDecorations(citem, item.xf + 8, item.yf + 12); + } + } + + glDisable2(GL_TEXTURE_2D); + t.endOverrideAndDraw(); + glEnable2(GL_TEXTURE_2D); + } + glDisable2(GL_SCISSOR_TEST); + + //fillGradient(bbox.x - 1, bbox.y, bbox.x + bbox.w + 1, bbox.y + 20, 0x99000000, 0x00000000); + //fillGradient(bbox.x - 1, bbox.y + bbox.h - 20, bbox.x + bbox.w + 1, bbox.y + bbox.h, 0x00000000, 0x99000000); + fillGradient(bg.x - fillMarginX, bbox.y, bg.w + fillMarginX, bbox.y + 20, 0x99000000, 0x00000000); + fillGradient(bg.x - fillMarginX, bbox.y + bbox.h - 20, bg.w + fillMarginX, bbox.y + bbox.h, 0x00000000, 0x99000000); + + drawScrollBar(hScroll); + drawScrollBar(vScroll); +} + +bool InventoryPane::onSelect( int gridId, bool selected ) +{ + //screen->onItemSelected(gridId); + if (screen->isAllowed(gridId)) + if (screen->addItem(this, gridId)) { + lastItemIndex = gridId; + lastItemTicks = 7; + } + + return false; +} + +void InventoryPane::drawScrollBar( ScrollBar& sb ) { + if (sb.alpha <= 0) + return; + + const int color = ((int)(255.0f * sb.alpha) << 24) | 0xaaaaaa; + const float xx = (float)(bbox.x + bbox.w); + fill(xx - sb.w, sb.y, xx, sb.y + sb.h, color); +} + +void InventoryPane::tick() +{ + --lastItemTicks; + super::tick(); +} + +void InventoryPane::setRenderDecorations( bool value ) { + renderDecorations = value; +} + +} diff --git a/src/client/gui/components/InventoryPane.h b/src/client/gui/components/InventoryPane.hpp similarity index 95% rename from src/client/gui/components/InventoryPane.h rename to src/client/gui/components/InventoryPane.hpp index 22bc79a..e6955f5 100755 --- a/src/client/gui/components/InventoryPane.h +++ b/src/client/gui/components/InventoryPane.hpp @@ -1,7 +1,7 @@ #pragma once -#include "ScrollingPane.h" -#include "ImageButton.h" +#include "ScrollingPane.hpp" +#include "ImageButton.hpp" class Minecraft; class ItemInstance; diff --git a/src/client/gui/components/ItemPane.cpp b/src/client/gui/components/ItemPane.cpp index e0ae8d2..cd2ac9f 100755 --- a/src/client/gui/components/ItemPane.cpp +++ b/src/client/gui/components/ItemPane.cpp @@ -1,148 +1,148 @@ -#include "ItemPane.h" -#include "../Gui.h" -#include "../../renderer/gles.h" -#include "../../renderer/Tesselator.h" -#include "NinePatch.h" -#include "../../renderer/entity/ItemRenderer.h" - -const int rgbActive = 0xfff0f0f0; -const int rgbInactive = 0xc0635558; -const int rgbInactiveShadow = 0xc0aaaaaa; - -ItemPane::ItemPane( IItemPaneCallback* screen, - Textures* textures, - const IntRectangle& rect, - int numItems, - int guiHeight, - int physicalScreenHeight, - bool isVertical /*= true*/) -: super( - (isVertical?SF_LockX:SF_LockY)/*|SF_Scissor*/|SF_ShowScrollbar, - rect, // Pane rect - isVertical?IntRectangle(0, 0, rect.w, 22) // Item rect if vertical - :IntRectangle(0, 0, 32, rect.h), // Item rect if horizontal - isVertical?1:numItems, numItems, Gui::GuiScale), - screen(screen), - textures(textures), - physicalScreenHeight(physicalScreenHeight), - guiSlotItem(NULL), - guiSlotItemSelected(NULL), - isVertical(isVertical) -{ - // Expand the area to make it easier to scroll - area._x0 -= 4; - area._x1 += 4; - area._y0 = 0; - area._y1 = (float)guiHeight; - - // GUI - NinePatchFactory builder(textures, "gui/spritesheet.png"); - guiSlotItem = builder.createSymmetrical(IntRectangle(20, 32, 8, 8), 2, 2); - guiSlotItemSelected = builder.createSymmetrical(IntRectangle(28, 32, 8, 8), 2, 2); - guiSlotItem->setSize((float)rect.w + 4, 22); - guiSlotItemSelected->setSize((float)rect.w + 4, 22); -} - -ItemPane::~ItemPane() { - delete guiSlotItem; - delete guiSlotItemSelected; -} - -void ItemPane::renderBatch( std::vector& items, float alpha ) -{ - //fill(bbox.x, bbox.y, bbox.x + bbox.w, bbox.y + bbox.h, 0xff666666); - const std::vector& cat = screen->getItems(this); - if (cat.empty()) return; - - glEnable2(GL_SCISSOR_TEST); - GLuint x = (GLuint)(screenScale * bbox.x); - GLuint y = physicalScreenHeight - (GLuint)(screenScale * (bbox.y + bbox.h)); - GLuint w = (GLuint)(screenScale * bbox.w); - GLuint h = (GLuint)(screenScale * bbox.h); - glScissor(x, y, w, h); - - Tesselator& t = Tesselator::instance; - - t.beginOverride(); - for (unsigned int i = 0; i < items.size(); ++i) { - GridItem& item = items[i]; - (item.selected? guiSlotItemSelected : guiSlotItem)->draw(t, Gui::floorAlignToScreenPixel(item.xf-1), Gui::floorAlignToScreenPixel(item.yf)); - } - t.endOverrideAndDraw(); - - t.beginOverride(); - for (unsigned int i = 0; i < items.size(); ++i) { - GridItem& item = items[i]; - CItem* citem = cat[item.id]; - - ItemRenderer::renderGuiItem(NULL, textures, &citem->item, - Gui::floorAlignToScreenPixel(item.xf + itemBbox.w - 16), - Gui::floorAlignToScreenPixel(2 + item.yf), 16, 16, false); - } - t.endOverrideAndDraw(); - - t.beginOverride(); - for (unsigned int i = 0; i < items.size(); ++i) { - GridItem& item = items[i]; - CItem* citem = cat[item.id]; - - char buf[64] = {0}; - int c = Gui::itemCountItoa(buf, citem->inventoryCount); - - float xf = item.xf - 1; - if (citem->canCraft()) { - f->drawShadow(citem->text, - Gui::floorAlignToScreenPixel(xf + 2), - Gui::floorAlignToScreenPixel(item.yf + 6), rgbActive); - t.scale2d(0.6667f, 0.6667f); - f->drawShadow(buf, - Gui::floorAlignToScreenPixel(1.5f * (xf + itemBbox.w - c*4)), - Gui::floorAlignToScreenPixel(1.5f * (item.yf + itemBbox.h - 8)), rgbActive); - t.resetScale(); - } else { - f->draw(citem->text, - Gui::floorAlignToScreenPixel(xf + 3), - Gui::floorAlignToScreenPixel(item.yf + 7), rgbInactiveShadow); - f->draw(citem->text, - Gui::floorAlignToScreenPixel(xf + 2), - Gui::floorAlignToScreenPixel(item.yf + 6), rgbInactive); - t.scale2d(0.6667f, 0.6667f); - f->draw(buf, - Gui::floorAlignToScreenPixel(1.5f * (xf + itemBbox.w - c*4)), - Gui::floorAlignToScreenPixel(1.5f * (item.yf + itemBbox.h - 8)), rgbInactive); - t.resetScale(); - } - } - t.endOverrideAndDraw(); - - //fillGradient(bbox.x, bbox.y, bbox.x + bbox.w, 20, 0x00000000, 0x80ff0000) - if (isVertical) { - fillGradient(bbox.x, bbox.y, bbox.x + bbox.w, bbox.y + 28, 0xbb000000, 0x00000000); - fillGradient(bbox.x, bbox.y + bbox.h - 28, bbox.x + bbox.w, bbox.y + bbox.h, 0x00000000, 0xbb000000);//0xbb2A272B); - } else { - fillHorizontalGradient(bbox.x, bbox.y, bbox.x + 28, bbox.y + bbox.h, 0xbb000000, 0x00000000); - fillHorizontalGradient(bbox.x + bbox.w - 28, bbox.y, bbox.x + bbox.w, bbox.y + bbox.h, 0x00000000, 0xbb000000);//0xbb2A272B); - } - - //LOGI("scroll: %f - %f, %f :: %f, %f\n", hScroll.alpha, hScroll.x, hScroll.y, hScroll.w, hScroll.h); - glDisable2(GL_SCISSOR_TEST); - - drawScrollBar(hScroll); - drawScrollBar(vScroll); -} - -bool ItemPane::onSelect( int gridId, bool selected ) -{ - if (selected) - screen->onItemSelected(this, gridId); - - return selected; -} - -void ItemPane::drawScrollBar( ScrollBar& sb ) { - if (sb.alpha <= 0) - return; - - int color = ((int)(255.0f * sb.alpha) << 24) | 0xffffff; - fill(2 + sb.x, sb.y, 2 + sb.x + sb.w, sb.y + sb.h, color); -} +#include "ItemPane.hpp" +#include "client/gui/Gui.hpp" +#include "client/renderer/gles.hpp" +#include "client/renderer/Tesselator.hpp" +#include "NinePatch.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" + +const int rgbActive = 0xfff0f0f0; +const int rgbInactive = 0xc0635558; +const int rgbInactiveShadow = 0xc0aaaaaa; + +ItemPane::ItemPane( IItemPaneCallback* screen, + Textures* textures, + const IntRectangle& rect, + int numItems, + int guiHeight, + int physicalScreenHeight, + bool isVertical /*= true*/) +: super( + (isVertical?SF_LockX:SF_LockY)/*|SF_Scissor*/|SF_ShowScrollbar, + rect, // Pane rect + isVertical?IntRectangle(0, 0, rect.w, 22) // Item rect if vertical + :IntRectangle(0, 0, 32, rect.h), // Item rect if horizontal + isVertical?1:numItems, numItems, Gui::GuiScale), + screen(screen), + textures(textures), + physicalScreenHeight(physicalScreenHeight), + guiSlotItem(NULL), + guiSlotItemSelected(NULL), + isVertical(isVertical) +{ + // Expand the area to make it easier to scroll + area._x0 -= 4; + area._x1 += 4; + area._y0 = 0; + area._y1 = (float)guiHeight; + + // GUI + NinePatchFactory builder(textures, "gui/spritesheet.png"); + guiSlotItem = builder.createSymmetrical(IntRectangle(20, 32, 8, 8), 2, 2); + guiSlotItemSelected = builder.createSymmetrical(IntRectangle(28, 32, 8, 8), 2, 2); + guiSlotItem->setSize((float)rect.w + 4, 22); + guiSlotItemSelected->setSize((float)rect.w + 4, 22); +} + +ItemPane::~ItemPane() { + delete guiSlotItem; + delete guiSlotItemSelected; +} + +void ItemPane::renderBatch( std::vector& items, float alpha ) +{ + //fill(bbox.x, bbox.y, bbox.x + bbox.w, bbox.y + bbox.h, 0xff666666); + const std::vector& cat = screen->getItems(this); + if (cat.empty()) return; + + glEnable2(GL_SCISSOR_TEST); + GLuint x = (GLuint)(screenScale * bbox.x); + GLuint y = physicalScreenHeight - (GLuint)(screenScale * (bbox.y + bbox.h)); + GLuint w = (GLuint)(screenScale * bbox.w); + GLuint h = (GLuint)(screenScale * bbox.h); + glScissor(x, y, w, h); + + Tesselator& t = Tesselator::instance; + + t.beginOverride(); + for (unsigned int i = 0; i < items.size(); ++i) { + GridItem& item = items[i]; + (item.selected? guiSlotItemSelected : guiSlotItem)->draw(t, Gui::floorAlignToScreenPixel(item.xf-1), Gui::floorAlignToScreenPixel(item.yf)); + } + t.endOverrideAndDraw(); + + t.beginOverride(); + for (unsigned int i = 0; i < items.size(); ++i) { + GridItem& item = items[i]; + CItem* citem = cat[item.id]; + + ItemRenderer::renderGuiItem(NULL, textures, &citem->item, + Gui::floorAlignToScreenPixel(item.xf + itemBbox.w - 16), + Gui::floorAlignToScreenPixel(2 + item.yf), 16, 16, false); + } + t.endOverrideAndDraw(); + + t.beginOverride(); + for (unsigned int i = 0; i < items.size(); ++i) { + GridItem& item = items[i]; + CItem* citem = cat[item.id]; + + char buf[64] = {0}; + int c = Gui::itemCountItoa(buf, citem->inventoryCount); + + float xf = item.xf - 1; + if (citem->canCraft()) { + f->drawShadow(citem->text, + Gui::floorAlignToScreenPixel(xf + 2), + Gui::floorAlignToScreenPixel(item.yf + 6), rgbActive); + t.scale2d(0.6667f, 0.6667f); + f->drawShadow(buf, + Gui::floorAlignToScreenPixel(1.5f * (xf + itemBbox.w - c*4)), + Gui::floorAlignToScreenPixel(1.5f * (item.yf + itemBbox.h - 8)), rgbActive); + t.resetScale(); + } else { + f->draw(citem->text, + Gui::floorAlignToScreenPixel(xf + 3), + Gui::floorAlignToScreenPixel(item.yf + 7), rgbInactiveShadow); + f->draw(citem->text, + Gui::floorAlignToScreenPixel(xf + 2), + Gui::floorAlignToScreenPixel(item.yf + 6), rgbInactive); + t.scale2d(0.6667f, 0.6667f); + f->draw(buf, + Gui::floorAlignToScreenPixel(1.5f * (xf + itemBbox.w - c*4)), + Gui::floorAlignToScreenPixel(1.5f * (item.yf + itemBbox.h - 8)), rgbInactive); + t.resetScale(); + } + } + t.endOverrideAndDraw(); + + //fillGradient(bbox.x, bbox.y, bbox.x + bbox.w, 20, 0x00000000, 0x80ff0000) + if (isVertical) { + fillGradient(bbox.x, bbox.y, bbox.x + bbox.w, bbox.y + 28, 0xbb000000, 0x00000000); + fillGradient(bbox.x, bbox.y + bbox.h - 28, bbox.x + bbox.w, bbox.y + bbox.h, 0x00000000, 0xbb000000);//0xbb2A272B); + } else { + fillHorizontalGradient(bbox.x, bbox.y, bbox.x + 28, bbox.y + bbox.h, 0xbb000000, 0x00000000); + fillHorizontalGradient(bbox.x + bbox.w - 28, bbox.y, bbox.x + bbox.w, bbox.y + bbox.h, 0x00000000, 0xbb000000);//0xbb2A272B); + } + + //LOGI("scroll: %f - %f, %f :: %f, %f\n", hScroll.alpha, hScroll.x, hScroll.y, hScroll.w, hScroll.h); + glDisable2(GL_SCISSOR_TEST); + + drawScrollBar(hScroll); + drawScrollBar(vScroll); +} + +bool ItemPane::onSelect( int gridId, bool selected ) +{ + if (selected) + screen->onItemSelected(this, gridId); + + return selected; +} + +void ItemPane::drawScrollBar( ScrollBar& sb ) { + if (sb.alpha <= 0) + return; + + int color = ((int)(255.0f * sb.alpha) << 24) | 0xffffff; + fill(2 + sb.x, sb.y, 2 + sb.x + sb.w, sb.y + sb.h, color); +} diff --git a/src/client/gui/components/ItemPane.h b/src/client/gui/components/ItemPane.hpp similarity index 96% rename from src/client/gui/components/ItemPane.h rename to src/client/gui/components/ItemPane.hpp index db2dfd9..5ecc10b 100755 --- a/src/client/gui/components/ItemPane.h +++ b/src/client/gui/components/ItemPane.hpp @@ -2,8 +2,8 @@ #include #include -#include "ScrollingPane.h" -#include "../../../world/item/ItemInstance.h" +#include "ScrollingPane.hpp" +#include "world/item/ItemInstance.hpp" class Font; class Textures; diff --git a/src/client/gui/components/KeyOption.cpp b/src/client/gui/components/KeyOption.cpp index 36b4c7f..70dc61a 100644 --- a/src/client/gui/components/KeyOption.cpp +++ b/src/client/gui/components/KeyOption.cpp @@ -1,5 +1,5 @@ -#include "KeyOption.h" -#include +#include "KeyOption.hpp" +#include KeyOption::KeyOption(Minecraft* minecraft, OptionId optId) : Touch::TButton((int)optId, Keyboard::getKeyName(minecraft->options.getIntValue(optId))) {} diff --git a/src/client/gui/components/KeyOption.h b/src/client/gui/components/KeyOption.hpp similarity index 86% rename from src/client/gui/components/KeyOption.h rename to src/client/gui/components/KeyOption.hpp index fabdc7a..71a64cd 100644 --- a/src/client/gui/components/KeyOption.h +++ b/src/client/gui/components/KeyOption.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Button.h" -#include +#include "Button.hpp" +#include class KeyOption : public Touch::TButton { public: diff --git a/src/client/gui/components/LargeImageButton.cpp b/src/client/gui/components/LargeImageButton.cpp index db1f599..070781e 100755 --- a/src/client/gui/components/LargeImageButton.cpp +++ b/src/client/gui/components/LargeImageButton.cpp @@ -1,104 +1,104 @@ -#include "LargeImageButton.h" -#include "../../renderer/Tesselator.h" -#include "../../Minecraft.h" -#include "../../../util/Mth.h" -#include "../../../platform/log.h" -#include "../../../util/Mth.h" -#include "../../renderer/Textures.h" - - -LargeImageButton::LargeImageButton(int id, const std::string& msg) -: super(id, msg) -{ - setupDefault(); -} - -LargeImageButton::LargeImageButton(int id, const std::string& msg, ImageDef& imagedef) -: super(id, msg) -{ - _imageDef = imagedef; - setupDefault(); -} - -void LargeImageButton::setupDefault() { - _buttonScale = 1; - width = 72; - height = 72; -} - -void LargeImageButton::render(Minecraft* minecraft, int xm, int ym) { - if (!visible) return; - - Font* font = minecraft->font; - - //minecraft->textures->loadAndBindTexture("gui/gui.png"); - glColor4f2(1, 1, 1, 1); - bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); - - //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); - //int yImage = getYImage(hovered || selected); - - //blit(x, y, 0, 46 + yImage * 20, w / 2, h, 0, 20); - //blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); - - renderBg(minecraft, xm, ym); - - TextureId texId = (_imageDef.name.length() > 0)? minecraft->textures->loadAndBindTexture(_imageDef.name) : Textures::InvalidId; - if ( Textures::isTextureIdValid(texId) ) { - const ImageDef& d = _imageDef; - Tesselator& t = Tesselator::instance; - - t.begin(); - if (!active) t.color(0xff808080); - //else if (hovered||selected) t.color(0xffffffff); - //else t.color(0xffe0e0e0); - else t.color(0xffffffff); - - float hx = ((float) d.width) * 0.5f; - float hy = ((float) d.height) * 0.5f; - const float cx = ((float)x+d.x) + hx; - const float cy = ((float)y+d.y) + hy; - - if (hovered) - _buttonScale = Mth::Max(0.95f, _buttonScale-0.025f); - else - _buttonScale = Mth::Min(1.00f, _buttonScale+0.025f); - - hx *= _buttonScale; - hy *= _buttonScale; - - const IntRectangle* src = _imageDef.getSrc(); - if (src) { - const TextureData* d = minecraft->textures->getTemporaryTextureData(texId); - if (d != NULL) { - float u0 = (src->x+(hovered?src->w:0)) / (float)d->w; - float u1 = (src->x+(hovered?2*src->w:src->w)) / (float)d->w; - float v0 = src->y / (float)d->h; - float v1 = (src->y+src->h) / (float)d->h; - t.vertexUV(cx-hx, cy-hy, blitOffset, u0, v0); - t.vertexUV(cx-hx, cy+hy, blitOffset, u0, v1); - t.vertexUV(cx+hx, cy+hy, blitOffset, u1, v1); - t.vertexUV(cx+hx, cy-hy, blitOffset, u1, v0); - } - } else { - t.vertexUV(cx-hx, cy-hy, blitOffset, 0, 0); - t.vertexUV(cx-hx, cy+hy, blitOffset, 0, 1); - t.vertexUV(cx+hx, cy+hy, blitOffset, 1, 1); - t.vertexUV(cx+hx, cy-hy, blitOffset, 1, 0); - } - t.draw(); - } - //blit(0, 0, 0, 0, 64, 64, 256, 256); - - //LOGI("%d %d\n", x+d.x, x+d.x+d.w); - - if (!active) { - drawCenteredString(font, msg, x + width / 2, y + 11/*(h - 16)*/, 0xffa0a0a0); - } else { - if (hovered || selected) { - drawCenteredString(font, msg, x + width / 2, y + 11/*(h - 16)*/, 0xffffa0); - } else { - drawCenteredString(font, msg, x + width / 2, y + 11/*(h - 48)*/, 0xe0e0e0); - } - } -} +#include "LargeImageButton.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/Minecraft.hpp" +#include "util/Mth.hpp" +#include "platform/log.hpp" +#include "util/Mth.hpp" +#include "client/renderer/Textures.hpp" + + +LargeImageButton::LargeImageButton(int id, const std::string& msg) +: super(id, msg) +{ + setupDefault(); +} + +LargeImageButton::LargeImageButton(int id, const std::string& msg, ImageDef& imagedef) +: super(id, msg) +{ + _imageDef = imagedef; + setupDefault(); +} + +void LargeImageButton::setupDefault() { + _buttonScale = 1; + width = 72; + height = 72; +} + +void LargeImageButton::render(Minecraft* minecraft, int xm, int ym) { + if (!visible) return; + + Font* font = minecraft->font; + + //minecraft->textures->loadAndBindTexture("gui/gui.png"); + glColor4f2(1, 1, 1, 1); + bool hovered = active && (minecraft->useTouchscreen()? (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); + + //printf("ButtonId: %d - Hovered? %d (cause: %d, %d, %d, %d, <> %d, %d)\n", id, hovered, x, y, x+w, y+h, xm, ym); + //int yImage = getYImage(hovered || selected); + + //blit(x, y, 0, 46 + yImage * 20, w / 2, h, 0, 20); + //blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h, 0, 20); + + renderBg(minecraft, xm, ym); + + TextureId texId = (_imageDef.name.length() > 0)? minecraft->textures->loadAndBindTexture(_imageDef.name) : Textures::InvalidId; + if ( Textures::isTextureIdValid(texId) ) { + const ImageDef& d = _imageDef; + Tesselator& t = Tesselator::instance; + + t.begin(); + if (!active) t.color(0xff808080); + //else if (hovered||selected) t.color(0xffffffff); + //else t.color(0xffe0e0e0); + else t.color(0xffffffff); + + float hx = ((float) d.width) * 0.5f; + float hy = ((float) d.height) * 0.5f; + const float cx = ((float)x+d.x) + hx; + const float cy = ((float)y+d.y) + hy; + + if (hovered) + _buttonScale = Mth::Max(0.95f, _buttonScale-0.025f); + else + _buttonScale = Mth::Min(1.00f, _buttonScale+0.025f); + + hx *= _buttonScale; + hy *= _buttonScale; + + const IntRectangle* src = _imageDef.getSrc(); + if (src) { + const TextureData* d = minecraft->textures->getTemporaryTextureData(texId); + if (d != NULL) { + float u0 = (src->x+(hovered?src->w:0)) / (float)d->w; + float u1 = (src->x+(hovered?2*src->w:src->w)) / (float)d->w; + float v0 = src->y / (float)d->h; + float v1 = (src->y+src->h) / (float)d->h; + t.vertexUV(cx-hx, cy-hy, blitOffset, u0, v0); + t.vertexUV(cx-hx, cy+hy, blitOffset, u0, v1); + t.vertexUV(cx+hx, cy+hy, blitOffset, u1, v1); + t.vertexUV(cx+hx, cy-hy, blitOffset, u1, v0); + } + } else { + t.vertexUV(cx-hx, cy-hy, blitOffset, 0, 0); + t.vertexUV(cx-hx, cy+hy, blitOffset, 0, 1); + t.vertexUV(cx+hx, cy+hy, blitOffset, 1, 1); + t.vertexUV(cx+hx, cy-hy, blitOffset, 1, 0); + } + t.draw(); + } + //blit(0, 0, 0, 0, 64, 64, 256, 256); + + //LOGI("%d %d\n", x+d.x, x+d.x+d.w); + + if (!active) { + drawCenteredString(font, msg, x + width / 2, y + 11/*(h - 16)*/, 0xffa0a0a0); + } else { + if (hovered || selected) { + drawCenteredString(font, msg, x + width / 2, y + 11/*(h - 16)*/, 0xffffa0); + } else { + drawCenteredString(font, msg, x + width / 2, y + 11/*(h - 48)*/, 0xe0e0e0); + } + } +} diff --git a/src/client/gui/components/LargeImageButton.h b/src/client/gui/components/LargeImageButton.hpp similarity index 92% rename from src/client/gui/components/LargeImageButton.h rename to src/client/gui/components/LargeImageButton.hpp index 1078b8b..0c2f42d 100755 --- a/src/client/gui/components/LargeImageButton.h +++ b/src/client/gui/components/LargeImageButton.hpp @@ -1,6 +1,6 @@ #pragma once -#include "ImageButton.h" +#include "ImageButton.hpp" class LargeImageButton: public ImageButton { diff --git a/src/client/gui/components/NinePatch.cpp b/src/client/gui/components/NinePatch.cpp index a82b937..2cd757a 100755 --- a/src/client/gui/components/NinePatch.cpp +++ b/src/client/gui/components/NinePatch.cpp @@ -1,141 +1,141 @@ -#include "NinePatch.h" - -NinePatchDescription::NinePatchDescription( float x, float y, float x1, float x2, float x3, float y1, float y2, float y3, float w, float e, float n, float s ) : u0(x), u1(x + x1), u2(x + x2), u3(x + x3), - v0(y), v1(y + y1), v2(y + y2), v3(y + y3), - w(w), e(e), n(n), s(s), - imgW(-1), - imgH(-1) { - -} - -NinePatchDescription& NinePatchDescription::transformUVForImage( const TextureData& d ) { - return transformUVForImageSize(d.w, d.h); -} - -NinePatchDescription& NinePatchDescription::transformUVForImageSize( int w, int h ) { - if (imgW < 0) - imgW = imgH = 1; - - const float us = (float) imgW / w; // @todo: prepare for normal blit? (e.g. mult by 256) - const float vs = (float) imgH / h; - u0 *= us; u1 *= us; u2 *= us; u3 *= us; - v0 *= vs; v1 *= vs; v2 *= vs; v3 *= vs; - - imgW = w; - imgH = h; - - return *this; -} - -NinePatchDescription NinePatchDescription::createSymmetrical( int texWidth, int texHeight, const IntRectangle& src, int xCutAt, int yCutAt ) { - NinePatchDescription patch((float)src.x, (float)src.y,// width and height of src - (float)xCutAt, (float)(src.w-xCutAt), (float)src.w, // u tex coordinates - (float)yCutAt, (float)(src.h-yCutAt), (float)src.h, // v tex coordinates - (float)xCutAt, (float)xCutAt, (float)yCutAt, (float)yCutAt); // border width and heights - if (texWidth > 0) patch.transformUVForImageSize(texWidth, texHeight); - return patch; -} - -NinePatchLayer::NinePatchLayer(const NinePatchDescription& desc, const std::string& imageName, Textures* textures, float w, float h) - : desc(desc), - imageName(imageName), - textures(textures), - w(-1), h(-1), - excluded(0) -{ - setSize(w, h); -} - -void NinePatchLayer::setSize( float w, float h ) { - if (w == this->w && h == this->h) - return; - - this->w = w; - this->h = h; - - for (int i = 0; i < 9; ++i) - buildQuad(i); -} - -void NinePatchLayer::draw( Tesselator& t, float x, float y ) { - textures->loadAndBindTexture(imageName); - t.begin(); - t.addOffset(x, y, 0); - for (int i = 0, b = 1; i < 9; ++i, b += b) - if ((b & excluded) == 0) - d(t, quads[i]); - t.addOffset(-x, -y, 0); - t.draw(); -} - -NinePatchLayer* NinePatchLayer::exclude( int excludeId ) { - return setExcluded(excluded | (1 << excludeId)); -} - -NinePatchLayer* NinePatchLayer::setExcluded( int exludeBits ) { - excluded = exludeBits; - return this; -} - -void NinePatchLayer::buildQuad( int qid ) { - //@attn; fix - CachedQuad& q = quads[qid]; - const int yid = qid / 3; - const int xid = qid - 3 * yid; - q.u0 = (&desc.u0)[xid]; - q.u1 = (&desc.u0)[xid + 1]; - q.v0 = (&desc.v0)[yid]; - q.v1 = (&desc.v0)[yid + 1]; - q.z = 0; - getPatchInfo(xid, yid, q.x0, q.x1, q.y0, q.y1); - /* q.x0 = w * (q.u0 - desc.u0); - q.y0 = h * (q.v0 - desc.v0); - q.x1 = w * (q.u1 - desc.u0); - q.y1 = h * (q.v1 - desc.v0); - */ -} - -void NinePatchLayer::getPatchInfo( int xc, int yc, float& x0, float& x1, float& y0, float& y1 ) { - if (xc == 0) { x0 = 0; x1 = desc.w; } - else if (xc == 1) { x0 = desc.w; x1 = w - desc.e; } - else if (xc == 2) { x0 = w-desc.e; x1 = w; } - if (yc == 0) { y0 = 0; y1 = desc.n; } - else if (yc == 1) { y0 = desc.n; y1 = h - desc.s; } - else if (yc == 2) { y0 = h-desc.s; y1 = h; } -} - -void NinePatchLayer::d( Tesselator& t, const CachedQuad& q ) { - /* - t.vertexUV(x , y + h, blitOffset, (float)(sx ), (float)(sy + sh)); - t.vertexUV(x + w, y + h, blitOffset, (float)(sx + sw), (float)(sy + sh)); - t.vertexUV(x + w, y , blitOffset, (float)(sx + sw), (float)(sy )); - t.vertexUV(x , y , blitOffset, (float)(sx ), (float)(sy )); - */ - - t.vertexUV(q.x0, q.y1, q.z, q.u0, q.v1); - t.vertexUV(q.x1, q.y1, q.z, q.u1, q.v1); - t.vertexUV(q.x1, q.y0, q.z, q.u1, q.v0); - t.vertexUV(q.x0, q.y0, q.z, q.u0, q.v0); -} - -NinePatchFactory::NinePatchFactory( Textures* textures, const std::string& imageName ) : textures(textures), - imageName(imageName), - width(1), - height(1) { - TextureId id = textures->loadTexture(imageName); - if (id != Textures::InvalidId) { - const TextureData* data = textures->getTemporaryTextureData(id); - if (data) { // This should never be false - width = data->w; - height = data->h; - } - } else { - LOGE("Error @ NinePatchFactory::ctor - Couldn't find texture: %s\n", imageName.c_str()); - } -} - -NinePatchLayer* NinePatchFactory::createSymmetrical( const IntRectangle& src, int xCutAt, int yCutAt, float w /*= 32.0f*/, float h /*= 32.0f*/ ) { - return new NinePatchLayer( - NinePatchDescription::createSymmetrical(width, height, src, xCutAt, yCutAt), - imageName, textures, w, h); -} +#include "NinePatch.hpp" + +NinePatchDescription::NinePatchDescription( float x, float y, float x1, float x2, float x3, float y1, float y2, float y3, float w, float e, float n, float s ) : u0(x), u1(x + x1), u2(x + x2), u3(x + x3), + v0(y), v1(y + y1), v2(y + y2), v3(y + y3), + w(w), e(e), n(n), s(s), + imgW(-1), + imgH(-1) { + +} + +NinePatchDescription& NinePatchDescription::transformUVForImage( const TextureData& d ) { + return transformUVForImageSize(d.w, d.h); +} + +NinePatchDescription& NinePatchDescription::transformUVForImageSize( int w, int h ) { + if (imgW < 0) + imgW = imgH = 1; + + const float us = (float) imgW / w; // @todo: prepare for normal blit? (e.g. mult by 256) + const float vs = (float) imgH / h; + u0 *= us; u1 *= us; u2 *= us; u3 *= us; + v0 *= vs; v1 *= vs; v2 *= vs; v3 *= vs; + + imgW = w; + imgH = h; + + return *this; +} + +NinePatchDescription NinePatchDescription::createSymmetrical( int texWidth, int texHeight, const IntRectangle& src, int xCutAt, int yCutAt ) { + NinePatchDescription patch((float)src.x, (float)src.y,// width and height of src + (float)xCutAt, (float)(src.w-xCutAt), (float)src.w, // u tex coordinates + (float)yCutAt, (float)(src.h-yCutAt), (float)src.h, // v tex coordinates + (float)xCutAt, (float)xCutAt, (float)yCutAt, (float)yCutAt); // border width and heights + if (texWidth > 0) patch.transformUVForImageSize(texWidth, texHeight); + return patch; +} + +NinePatchLayer::NinePatchLayer(const NinePatchDescription& desc, const std::string& imageName, Textures* textures, float w, float h) + : desc(desc), + imageName(imageName), + textures(textures), + w(-1), h(-1), + excluded(0) +{ + setSize(w, h); +} + +void NinePatchLayer::setSize( float w, float h ) { + if (w == this->w && h == this->h) + return; + + this->w = w; + this->h = h; + + for (int i = 0; i < 9; ++i) + buildQuad(i); +} + +void NinePatchLayer::draw( Tesselator& t, float x, float y ) { + textures->loadAndBindTexture(imageName); + t.begin(); + t.addOffset(x, y, 0); + for (int i = 0, b = 1; i < 9; ++i, b += b) + if ((b & excluded) == 0) + d(t, quads[i]); + t.addOffset(-x, -y, 0); + t.draw(); +} + +NinePatchLayer* NinePatchLayer::exclude( int excludeId ) { + return setExcluded(excluded | (1 << excludeId)); +} + +NinePatchLayer* NinePatchLayer::setExcluded( int exludeBits ) { + excluded = exludeBits; + return this; +} + +void NinePatchLayer::buildQuad( int qid ) { + //@attn; fix + CachedQuad& q = quads[qid]; + const int yid = qid / 3; + const int xid = qid - 3 * yid; + q.u0 = (&desc.u0)[xid]; + q.u1 = (&desc.u0)[xid + 1]; + q.v0 = (&desc.v0)[yid]; + q.v1 = (&desc.v0)[yid + 1]; + q.z = 0; + getPatchInfo(xid, yid, q.x0, q.x1, q.y0, q.y1); + /* q.x0 = w * (q.u0 - desc.u0); + q.y0 = h * (q.v0 - desc.v0); + q.x1 = w * (q.u1 - desc.u0); + q.y1 = h * (q.v1 - desc.v0); + */ +} + +void NinePatchLayer::getPatchInfo( int xc, int yc, float& x0, float& x1, float& y0, float& y1 ) { + if (xc == 0) { x0 = 0; x1 = desc.w; } + else if (xc == 1) { x0 = desc.w; x1 = w - desc.e; } + else if (xc == 2) { x0 = w-desc.e; x1 = w; } + if (yc == 0) { y0 = 0; y1 = desc.n; } + else if (yc == 1) { y0 = desc.n; y1 = h - desc.s; } + else if (yc == 2) { y0 = h-desc.s; y1 = h; } +} + +void NinePatchLayer::d( Tesselator& t, const CachedQuad& q ) { + /* + t.vertexUV(x , y + h, blitOffset, (float)(sx ), (float)(sy + sh)); + t.vertexUV(x + w, y + h, blitOffset, (float)(sx + sw), (float)(sy + sh)); + t.vertexUV(x + w, y , blitOffset, (float)(sx + sw), (float)(sy )); + t.vertexUV(x , y , blitOffset, (float)(sx ), (float)(sy )); + */ + + t.vertexUV(q.x0, q.y1, q.z, q.u0, q.v1); + t.vertexUV(q.x1, q.y1, q.z, q.u1, q.v1); + t.vertexUV(q.x1, q.y0, q.z, q.u1, q.v0); + t.vertexUV(q.x0, q.y0, q.z, q.u0, q.v0); +} + +NinePatchFactory::NinePatchFactory( Textures* textures, const std::string& imageName ) : textures(textures), + imageName(imageName), + width(1), + height(1) { + TextureId id = textures->loadTexture(imageName); + if (id != Textures::InvalidId) { + const TextureData* data = textures->getTemporaryTextureData(id); + if (data) { // This should never be false + width = data->w; + height = data->h; + } + } else { + LOGE("Error @ NinePatchFactory::ctor - Couldn't find texture: %s\n", imageName.c_str()); + } +} + +NinePatchLayer* NinePatchFactory::createSymmetrical( const IntRectangle& src, int xCutAt, int yCutAt, float w /*= 32.0f*/, float h /*= 32.0f*/ ) { + return new NinePatchLayer( + NinePatchDescription::createSymmetrical(width, height, src, xCutAt, yCutAt), + imageName, textures, w, h); +} diff --git a/src/client/gui/components/NinePatch.h b/src/client/gui/components/NinePatch.hpp similarity index 90% rename from src/client/gui/components/NinePatch.h rename to src/client/gui/components/NinePatch.hpp index 1e55e07..98663b9 100755 --- a/src/client/gui/components/NinePatch.h +++ b/src/client/gui/components/NinePatch.hpp @@ -1,10 +1,10 @@ #pragma once -#include "ImageButton.h" -#include "../../renderer/TextureData.h" -#include "../../renderer/Textures.h" -#include "../../renderer/Tesselator.h" -#include "../../Minecraft.h" +#include "ImageButton.hpp" +#include "client/renderer/TextureData.hpp" +#include "client/renderer/Textures.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/Minecraft.hpp" class Tesselator; diff --git a/src/client/gui/components/OptionsGroup.cpp b/src/client/gui/components/OptionsGroup.cpp index 54212d5..f762fe4 100755 --- a/src/client/gui/components/OptionsGroup.cpp +++ b/src/client/gui/components/OptionsGroup.cpp @@ -1,115 +1,115 @@ -#include "OptionsGroup.h" -#include "../../Minecraft.h" -#include "ImageButton.h" -#include "OptionsItem.h" -#include "Slider.h" -#include "../../../locale/I18n.h" -#include "TextOption.h" -#include "KeyOption.h" - -OptionsGroup::OptionsGroup( std::string labelID ) { - label = I18n::get(labelID); -} - -void OptionsGroup::setupPositions() { - // First we write the header and then we add the items - int curY = y + 18; - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->width = width - 5; - - (*it)->y = curY; - (*it)->x = x + 10; - (*it)->setupPositions(); - curY += (*it)->height + 3; - } - height = curY; -} - -void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) { - float padX = 10.0f; - float padY = 5.0f; - - minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false); - - super::render(minecraft, xm, ym); -} - -OptionsGroup& OptionsGroup::addOptionItem(OptionId optId, Minecraft* minecraft ) { - auto option = minecraft->options.getOpt(optId); - - if (option == nullptr) return *this; - - // TODO: do a options key class to check it faster via dynamic_cast - if (option->getStringId().find("options.key") != std::string::npos) createKey(optId, minecraft); - else if (dynamic_cast(option)) createToggle(optId, minecraft); - else if (dynamic_cast(option)) createProgressSlider(optId, minecraft); - else if (dynamic_cast(option)) createStepSlider(optId, minecraft); - else if (dynamic_cast(option)) createTextbox(optId, minecraft); - - return *this; -} - -// TODO: wrap this copypaste shit into templates - -void OptionsGroup::createToggle(OptionId optId, Minecraft* minecraft ) { - ImageDef def; - - def.setSrc(IntRectangle(160, 206, 39, 20)); - def.name = "gui/touchgui.png"; - def.width = 39 * 0.7f; - def.height = 20 * 0.7f; - - OptionButton* element = new OptionButton(optId); - element->setImageDef(def, true); - element->updateImage(&minecraft->options); - - std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); - - OptionsItem* item = new OptionsItem(optId, itemLabel, element); - - addChild(item); - setupPositions(); -} - -void OptionsGroup::createProgressSlider(OptionId optId, Minecraft* minecraft ) { - Slider* element = new SliderFloat(minecraft, optId); - element->width = 100; - element->height = 20; - - std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); - OptionsItem* item = new OptionsItem(optId, itemLabel, element); - addChild(item); - setupPositions(); -} - -void OptionsGroup::createStepSlider(OptionId optId, Minecraft* minecraft ) { - Slider* element = new SliderInt(minecraft, optId); - element->width = 100; - element->height = 20; - std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); - OptionsItem* item = new OptionsItem(optId, itemLabel, element); - addChild(item); - setupPositions(); -} - -void OptionsGroup::createTextbox(OptionId optId, Minecraft* minecraft) { - TextBox* element = new TextOption(minecraft, optId); - element->width = 100; - element->height = 20; - - std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); - OptionsItem* item = new OptionsItem(optId, itemLabel, element); - addChild(item); - setupPositions(); -} - -void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) { - KeyOption* element = new KeyOption(minecraft, optId); - element->width = 50; - element->height = 20; - - std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); - OptionsItem* item = new OptionsItem(optId, itemLabel, element); - addChild(item); - setupPositions(); +#include "OptionsGroup.hpp" +#include "client/Minecraft.hpp" +#include "ImageButton.hpp" +#include "OptionsItem.hpp" +#include "Slider.hpp" +#include "locale/I18n.hpp" +#include "TextOption.hpp" +#include "KeyOption.hpp" + +OptionsGroup::OptionsGroup( std::string labelID ) { + label = I18n::get(labelID); +} + +void OptionsGroup::setupPositions() { + // First we write the header and then we add the items + int curY = y + 18; + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->width = width - 5; + + (*it)->y = curY; + (*it)->x = x + 10; + (*it)->setupPositions(); + curY += (*it)->height + 3; + } + height = curY; +} + +void OptionsGroup::render( Minecraft* minecraft, int xm, int ym ) { + float padX = 10.0f; + float padY = 5.0f; + + minecraft->font->draw(label, (float)x + padX, (float)y + padY, 0xffffffff, false); + + super::render(minecraft, xm, ym); +} + +OptionsGroup& OptionsGroup::addOptionItem(OptionId optId, Minecraft* minecraft ) { + auto option = minecraft->options.getOpt(optId); + + if (option == nullptr) return *this; + + // TODO: do a options key class to check it faster via dynamic_cast + if (option->getStringId().find("options.key") != std::string::npos) createKey(optId, minecraft); + else if (dynamic_cast(option)) createToggle(optId, minecraft); + else if (dynamic_cast(option)) createProgressSlider(optId, minecraft); + else if (dynamic_cast(option)) createStepSlider(optId, minecraft); + else if (dynamic_cast(option)) createTextbox(optId, minecraft); + + return *this; +} + +// TODO: wrap this copypaste shit into templates + +void OptionsGroup::createToggle(OptionId optId, Minecraft* minecraft ) { + ImageDef def; + + def.setSrc(IntRectangle(160, 206, 39, 20)); + def.name = "gui/touchgui.png"; + def.width = 39 * 0.7f; + def.height = 20 * 0.7f; + + OptionButton* element = new OptionButton(optId); + element->setImageDef(def, true); + element->updateImage(&minecraft->options); + + std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); + + OptionsItem* item = new OptionsItem(optId, itemLabel, element); + + addChild(item); + setupPositions(); +} + +void OptionsGroup::createProgressSlider(OptionId optId, Minecraft* minecraft ) { + Slider* element = new SliderFloat(minecraft, optId); + element->width = 100; + element->height = 20; + + std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); + OptionsItem* item = new OptionsItem(optId, itemLabel, element); + addChild(item); + setupPositions(); +} + +void OptionsGroup::createStepSlider(OptionId optId, Minecraft* minecraft ) { + Slider* element = new SliderInt(minecraft, optId); + element->width = 100; + element->height = 20; + std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); + OptionsItem* item = new OptionsItem(optId, itemLabel, element); + addChild(item); + setupPositions(); +} + +void OptionsGroup::createTextbox(OptionId optId, Minecraft* minecraft) { + TextBox* element = new TextOption(minecraft, optId); + element->width = 100; + element->height = 20; + + std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); + OptionsItem* item = new OptionsItem(optId, itemLabel, element); + addChild(item); + setupPositions(); +} + +void OptionsGroup::createKey(OptionId optId, Minecraft* minecraft) { + KeyOption* element = new KeyOption(minecraft, optId); + element->width = 50; + element->height = 20; + + std::string itemLabel = I18n::get(minecraft->options.getOpt(optId)->getStringId()); + OptionsItem* item = new OptionsItem(optId, itemLabel, element); + addChild(item); + setupPositions(); } \ No newline at end of file diff --git a/src/client/gui/components/OptionsGroup.h b/src/client/gui/components/OptionsGroup.hpp similarity index 88% rename from src/client/gui/components/OptionsGroup.h rename to src/client/gui/components/OptionsGroup.hpp index b5cf467..8f05ba0 100755 --- a/src/client/gui/components/OptionsGroup.h +++ b/src/client/gui/components/OptionsGroup.hpp @@ -3,9 +3,9 @@ //package net.minecraft.client.gui; #include -#include "GuiElementContainer.h" -#include "ScrollingPane.h" -#include "../../Options.h" +#include "GuiElementContainer.hpp" +#include "ScrollingPane.hpp" +#include "client/Options.hpp" class Font; class Minecraft; diff --git a/src/client/gui/components/OptionsItem.cpp b/src/client/gui/components/OptionsItem.cpp index 1ee48e3..6c17822 100755 --- a/src/client/gui/components/OptionsItem.cpp +++ b/src/client/gui/components/OptionsItem.cpp @@ -1,42 +1,42 @@ -#include "OptionsItem.h" -#include "../../Minecraft.h" -#include "../../../locale/I18n.h" -#include "../../../util/Mth.h" -OptionsItem::OptionsItem( OptionId optionId, std::string label, GuiElement* element ) -: GuiElementContainer(false, true, 0, 0, 24, 12), - m_optionId(optionId), - m_label(label) { - addChild(element); -} - -void OptionsItem::setupPositions() { - int currentHeight = 0; - for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { - (*it)->x = x + width - (*it)->width - 15; - (*it)->y = y + currentHeight; - currentHeight += (*it)->height; - } - height = currentHeight; -} - -void OptionsItem::render( Minecraft* minecraft, int xm, int ym ) { - int yOffset = (height - 8) / 2; - std::string text = m_label; - if (m_optionId == OPTIONS_GUI_SCALE) { - int value = minecraft->options.getIntValue(OPTIONS_GUI_SCALE); - std::string scaleText; - switch (value) { - case 0: scaleText = I18n::get("options.guiScale.auto"); break; - case 1: scaleText = I18n::get("options.guiScale.small"); break; - case 2: scaleText = I18n::get("options.guiScale.medium"); break; - case 3: scaleText = I18n::get("options.guiScale.large"); break; - case 4: scaleText = I18n::get("options.guiScale.larger"); break; - case 5: scaleText = I18n::get("options.guiScale.largest"); break; - default: scaleText = I18n::get("options.guiScale.auto"); break; - } - text += ": " + scaleText; - } - - minecraft->font->draw(text, (float)x, (float)y + yOffset, 0x909090, false); - super::render(minecraft, xm, ym); +#include "OptionsItem.hpp" +#include "client/Minecraft.hpp" +#include "locale/I18n.hpp" +#include "util/Mth.hpp" +OptionsItem::OptionsItem( OptionId optionId, std::string label, GuiElement* element ) +: GuiElementContainer(false, true, 0, 0, 24, 12), + m_optionId(optionId), + m_label(label) { + addChild(element); +} + +void OptionsItem::setupPositions() { + int currentHeight = 0; + for(std::vector::iterator it = children.begin(); it != children.end(); ++it) { + (*it)->x = x + width - (*it)->width - 15; + (*it)->y = y + currentHeight; + currentHeight += (*it)->height; + } + height = currentHeight; +} + +void OptionsItem::render( Minecraft* minecraft, int xm, int ym ) { + int yOffset = (height - 8) / 2; + std::string text = m_label; + if (m_optionId == OPTIONS_GUI_SCALE) { + int value = minecraft->options.getIntValue(OPTIONS_GUI_SCALE); + std::string scaleText; + switch (value) { + case 0: scaleText = I18n::get("options.guiScale.auto"); break; + case 1: scaleText = I18n::get("options.guiScale.small"); break; + case 2: scaleText = I18n::get("options.guiScale.medium"); break; + case 3: scaleText = I18n::get("options.guiScale.large"); break; + case 4: scaleText = I18n::get("options.guiScale.larger"); break; + case 5: scaleText = I18n::get("options.guiScale.largest"); break; + default: scaleText = I18n::get("options.guiScale.auto"); break; + } + text += ": " + scaleText; + } + + minecraft->font->draw(text, (float)x, (float)y + yOffset, 0x909090, false); + super::render(minecraft, xm, ym); } \ No newline at end of file diff --git a/src/client/gui/components/OptionsItem.h b/src/client/gui/components/OptionsItem.hpp similarity index 78% rename from src/client/gui/components/OptionsItem.h rename to src/client/gui/components/OptionsItem.hpp index 84ae5cb..e2374c0 100755 --- a/src/client/gui/components/OptionsItem.h +++ b/src/client/gui/components/OptionsItem.hpp @@ -2,9 +2,9 @@ #include #include -#include "GuiElementContainer.h" -#include "../../../world/item/ItemInstance.h" -#include "../../../client/Options.h" +#include "GuiElementContainer.hpp" +#include "world/item/ItemInstance.hpp" +#include "client/Options.hpp" class Font; class Textures; class NinePatchLayer; diff --git a/src/client/gui/components/RolledSelectionListH.cpp b/src/client/gui/components/RolledSelectionListH.cpp index 012c7dc..141215d 100755 --- a/src/client/gui/components/RolledSelectionListH.cpp +++ b/src/client/gui/components/RolledSelectionListH.cpp @@ -1,299 +1,299 @@ -#include "RolledSelectionListH.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/gles.h" -#include "../../../platform/input/Mouse.h" -#include "../../../platform/input/Multitouch.h" -#include "../../../util/Mth.h" -#include "../../renderer/Textures.h" -#include "MinecraftClient.h" - - -RolledSelectionListH::RolledSelectionListH( MinecraftClient& minecraft, int width, int height, int x0, int x1, int y0, int y1, int itemWidth ) -: minecraft(minecraft), - width(width), - height(height), - x0((float)x0), - x1((float)x1), - y0((float)y0), - y1((float)y1), - itemWidth(itemWidth), - selectionX(-1), - lastSelectionTime(0), - lastSelection(-1), - renderSelection(true), - doRenderHeader(false), - headerWidth(0), - dragState(DRAG_OUTSIDE), - xDrag(0.0f), - xo(0.0f), - xoo(0.0f), - xInertia(0.0f), - _componentSelected(false), - _renderTopBorder(true), - _renderBottomBorder(true), - _lastxoo(0), - _xinertia(0) -{ - xo = xoo = (float)(itemWidth-width) * 0.5f; - _lastxoo = xoo; -} - -void RolledSelectionListH::setRenderSelection( bool _renderSelection ) -{ - renderSelection = _renderSelection; -} - -void RolledSelectionListH::setComponentSelected(bool selected) { - _componentSelected = selected; -} - -void RolledSelectionListH::setRenderHeader( bool _renderHeader, int _headerHeight ) -{ - doRenderHeader = _renderHeader; - headerWidth = _headerHeight; - - if (!doRenderHeader) { - headerWidth = 0; - } -} - -int RolledSelectionListH::getMaxPosition() -{ - return getNumberOfItems() * itemWidth + headerWidth; -} - -int RolledSelectionListH::getItemAtPosition( int x, int y ) -{ - int clickSlotPos = (int)(x - x0 - headerWidth + (int) xo - 4); - int isInsideY = y >= y0 && y <= y1; - return isInsideY? getItemAtXPositionRaw(clickSlotPos) : -1; -} - -int RolledSelectionListH::getItemAtXPositionRaw(int x) { - int slot = x / itemWidth; - bool isInsideX = slot >= 0 && x >= 0 && slot < getNumberOfItems(); - return isInsideX? slot : -1; -} - -bool RolledSelectionListH::capXPosition() -{ - const float MinX = (float)(itemWidth-width)/2; - const float MaxX = MinX + (getNumberOfItems()-1) * itemWidth; - if (xo < MinX) { xo = MinX; xInertia = 0; return true; } - if (xo > MaxX) { xo = MaxX; xInertia = 0; return true; } - return false; -} - -void RolledSelectionListH::tick() { - - //if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) - { - _xinertia = _lastxoo - xoo; - } - _lastxoo = xoo; - xoo = xo - xInertia; -} - -float RolledSelectionListH::getPos(float alpha) { - return xoo - xInertia * alpha; -} - -void RolledSelectionListH::render( int xm, int ym, float a ) -{ - renderBackground(); - - int itemCount = getNumberOfItems(); - - //float yy0 = height / 2.0f + 124; - //float yy1 = yy0 + 6; - - if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { - touched(); - //LOGI("DOWN ym: %d\n", ym); - if (ym >= y0 && ym <= y1) { - if (dragState == NO_DRAG) { - lastSelectionTime = getTimeMs(); - lastSelection = getItemAtPosition(xm, height/2); - //float localX = (float)(xm*Gui::InvGuiScale - x0 - xo + lastSelection * itemWidth + headerWidth); - selectStart(lastSelection, 0, 0);//localX, ym-y0); - selectionX = xm; - } - else if (dragState >= 0) { - xo -= (xm - xDrag); - xoo = xo; - } - dragState = DRAG_NORMAL; - //const int* ids; - //LOGI("mtouch: %d\n", Multitouch::getActivePointerIds(&ids)); - } - } else { - if (dragState >= 0) { - if (dragState >= 0) { - xInertia = _xinertia < 0? Mth::Max(-20.0f, _xinertia) : Mth::Min(20.0f, _xinertia); - } - //LOGI("Inertia: %f. Time: %d, delta-x: %d, (xm, sel: %d, %d)\n", xInertia, getTimeMs() - lastSelectionTime, std::abs(selectionX - xm), xm, selectionX); - // kill small inertia values when releasing scrollist - if (std::abs(xInertia) <= 2.0001f) { - xInertia = 0.0f; - } - - if (std::abs(xInertia) <= 10 && getTimeMs() - lastSelectionTime < 300) - { - int slot = getItemAtPosition(xm, height/2); - //LOGI("slot: %d, lt: %d. diff: %d - %d\n", slot, lastSelection, selectionX, xm); - if (slot >= 0 && slot == lastSelection && std::abs(selectionX - xm) < 10) - selectItem(slot, false); - else - selectCancel(); - } else { - selectCancel(); - } - } - - // if (slot >= 0 && std::abs(selectionX - xm) < itemWidth) - // { - // bool doubleClick = false; - // selectItem(slot, doubleClick); - // //xInertia = 0.0f; - // } - //} - dragState = NO_DRAG; - - xo = getPos(a); - } - xDrag = (float)xm; - - capXPosition(); - - Tesselator& t = Tesselator::instance; - - float by0 = _renderTopBorder? y0 : 0; - float by1 = _renderBottomBorder? y1 : height; - - //LOGI("x: %f\n", xo); - - minecraft.textures().loadAndBindTexture("gui/background.png"); - glColor4f2(1.0f, 1, 1, 1); - float s = 32; - t.begin(); - t.color(0x202020); - t.vertexUV(x0, by1, 0, (x0 + (int) xo) / s, by1 / s); - t.vertexUV(x1, by1, 0, (x1 + (int) xo) / s, by1 / s); - t.vertexUV(x1, by0, 0, (x1 + (int) xo) / s, by0 / s); - t.vertexUV(x0, by0, 0, (x0 + (int) xo) / s, by0 / s); - t.draw(); - - const int HalfHeight = 48; - - if (getNumberOfItems() == 0) xo = 0; - - int rowY = (int)(height / 2 - HalfHeight + 8); - int rowBaseX = (int)(x0 /*+ 4*/ - (int) xo); - - if (doRenderHeader) { - renderHeader(rowBaseX, rowY, t); - } - - for (int i = 0; i < itemCount; i++) { - - float x = (float)(rowBaseX + (i) * itemWidth + headerWidth); - float h = (float)itemWidth; - - if (x > x1 || (x + h) < x0) { - continue; - } - - if (renderSelection && isSelectedItem(i)) { - float y0 = height / 2.0f - HalfHeight - 4; //@kindle-res:+2 - float y1 = height / 2.0f + HalfHeight - 4; //@kindle-res:-6 - glColor4f2(1, 1, 1, 1); - glDisable2(GL_TEXTURE_2D); - - int ew = 0; - int color = 0x808080; - if (_componentSelected) { - ew = 0; - color = 0x7F89BF; - } - t.begin(); - t.color(color); - t.vertex(x - 1 - ew, y0 - ew, 0); - t.vertex(x - 1 - ew, y1 + ew, 0); - t.vertex(x + h + 1 + ew, y1 + ew, 0); - t.vertex(x + h + 1 + ew, y0 - ew, 0); - - t.color(0x000000); - t.vertex(x, y0 + 1, 0); - t.vertex(x, y1 - 1, 0); - t.vertex(x + h, y1 - 1, 0); - t.vertex(x + h, y0 + 1, 0); - - t.draw(); - glEnable2(GL_TEXTURE_2D); - } - renderItem(i, (int)x, rowY, (int)h, t); - } - - glDisable2(GL_DEPTH_TEST); - - if (_renderTopBorder) - renderHoleBackground(0, y0, 255, 255); - if (_renderBottomBorder) - renderHoleBackground(y1, (float)height, 255, 255); - - //glEnable2(GL_BLEND); - //glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glDisable2(GL_ALPHA_TEST); - //glShadeModel2(GL_SMOOTH); - - //glDisable2(GL_TEXTURE_2D); - - //const int d = 4; - //t.begin(); - //t.color(0x000000, 0); - //t.vertexUV(y0, x0 + d, 0, 0, 1); - //t.vertexUV(y1, x0 + d, 0, 1, 1); - //t.color(0x000000, 255); - //t.vertexUV(y1, x0, 0, 1, 0); - //t.vertexUV(y0, x0, 0, 0, 0); - //t.draw(); - - //t.begin(); - //t.color(0x000000, 255); - //t.vertexUV(y0, x1, 0, 0, 1); - //t.vertexUV(y1, x1, 0, 1, 1); - //t.color(0x000000, 0); - //t.vertexUV(y1, x1 - d, 0, 1, 0); - //t.vertexUV(y0, x1 - d, 0, 0, 0); - //t.draw(); - - //renderDecorations(xm, ym); - - //glEnable2(GL_TEXTURE_2D); - glEnable2(GL_DEPTH_TEST); - - //glShadeModel2(GL_FLAT); - //glEnable2(GL_ALPHA_TEST); - //glDisable2(GL_BLEND); -} - -void RolledSelectionListH::renderHoleBackground( /*float x0, float x1,*/ float y0, float y1, int a0, int a1 ) -{ - Tesselator& t = Tesselator::instance; - minecraft.textures().loadAndBindTexture("gui/background.png"); - glColor4f2(1.0f, 1, 1, 1); - float s = 32; - t.begin(); - t.color(0x505050, a1); - t.vertexUV(0, y1, 0, 0, y1 / s); - t.vertexUV((float)width, y1, 0, width / s, y1 / s); - t.color(0x505050, a0); - t.vertexUV((float)width, y0, 0, width / s, y0 / s); - t.vertexUV(0, y0, 0, 0, y0 / s); - t.draw(); - //printf("x, y, x1, y1: %d, %d, %d, %d\n", 0, (int)y0, width, (int)y1); -} - -void RolledSelectionListH::touched() -{ -} +#include "RolledSelectionListH.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/gles.hpp" +#include "platform/input/Mouse.hpp" +#include "platform/input/Multitouch.hpp" +#include "util/Mth.hpp" +#include "client/renderer/Textures.hpp" +#include "MinecraftClient.hpp" + + +RolledSelectionListH::RolledSelectionListH( MinecraftClient& minecraft, int width, int height, int x0, int x1, int y0, int y1, int itemWidth ) +: minecraft(minecraft), + width(width), + height(height), + x0((float)x0), + x1((float)x1), + y0((float)y0), + y1((float)y1), + itemWidth(itemWidth), + selectionX(-1), + lastSelectionTime(0), + lastSelection(-1), + renderSelection(true), + doRenderHeader(false), + headerWidth(0), + dragState(DRAG_OUTSIDE), + xDrag(0.0f), + xo(0.0f), + xoo(0.0f), + xInertia(0.0f), + _componentSelected(false), + _renderTopBorder(true), + _renderBottomBorder(true), + _lastxoo(0), + _xinertia(0) +{ + xo = xoo = (float)(itemWidth-width) * 0.5f; + _lastxoo = xoo; +} + +void RolledSelectionListH::setRenderSelection( bool _renderSelection ) +{ + renderSelection = _renderSelection; +} + +void RolledSelectionListH::setComponentSelected(bool selected) { + _componentSelected = selected; +} + +void RolledSelectionListH::setRenderHeader( bool _renderHeader, int _headerHeight ) +{ + doRenderHeader = _renderHeader; + headerWidth = _headerHeight; + + if (!doRenderHeader) { + headerWidth = 0; + } +} + +int RolledSelectionListH::getMaxPosition() +{ + return getNumberOfItems() * itemWidth + headerWidth; +} + +int RolledSelectionListH::getItemAtPosition( int x, int y ) +{ + int clickSlotPos = (int)(x - x0 - headerWidth + (int) xo - 4); + int isInsideY = y >= y0 && y <= y1; + return isInsideY? getItemAtXPositionRaw(clickSlotPos) : -1; +} + +int RolledSelectionListH::getItemAtXPositionRaw(int x) { + int slot = x / itemWidth; + bool isInsideX = slot >= 0 && x >= 0 && slot < getNumberOfItems(); + return isInsideX? slot : -1; +} + +bool RolledSelectionListH::capXPosition() +{ + const float MinX = (float)(itemWidth-width)/2; + const float MaxX = MinX + (getNumberOfItems()-1) * itemWidth; + if (xo < MinX) { xo = MinX; xInertia = 0; return true; } + if (xo > MaxX) { xo = MaxX; xInertia = 0; return true; } + return false; +} + +void RolledSelectionListH::tick() { + + //if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) + { + _xinertia = _lastxoo - xoo; + } + _lastxoo = xoo; + xoo = xo - xInertia; +} + +float RolledSelectionListH::getPos(float alpha) { + return xoo - xInertia * alpha; +} + +void RolledSelectionListH::render( int xm, int ym, float a ) +{ + renderBackground(); + + int itemCount = getNumberOfItems(); + + //float yy0 = height / 2.0f + 124; + //float yy1 = yy0 + 6; + + if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { + touched(); + //LOGI("DOWN ym: %d\n", ym); + if (ym >= y0 && ym <= y1) { + if (dragState == NO_DRAG) { + lastSelectionTime = getTimeMs(); + lastSelection = getItemAtPosition(xm, height/2); + //float localX = (float)(xm*Gui::InvGuiScale - x0 - xo + lastSelection * itemWidth + headerWidth); + selectStart(lastSelection, 0, 0);//localX, ym-y0); + selectionX = xm; + } + else if (dragState >= 0) { + xo -= (xm - xDrag); + xoo = xo; + } + dragState = DRAG_NORMAL; + //const int* ids; + //LOGI("mtouch: %d\n", Multitouch::getActivePointerIds(&ids)); + } + } else { + if (dragState >= 0) { + if (dragState >= 0) { + xInertia = _xinertia < 0? Mth::Max(-20.0f, _xinertia) : Mth::Min(20.0f, _xinertia); + } + //LOGI("Inertia: %f. Time: %d, delta-x: %d, (xm, sel: %d, %d)\n", xInertia, getTimeMs() - lastSelectionTime, std::abs(selectionX - xm), xm, selectionX); + // kill small inertia values when releasing scrollist + if (std::abs(xInertia) <= 2.0001f) { + xInertia = 0.0f; + } + + if (std::abs(xInertia) <= 10 && getTimeMs() - lastSelectionTime < 300) + { + int slot = getItemAtPosition(xm, height/2); + //LOGI("slot: %d, lt: %d. diff: %d - %d\n", slot, lastSelection, selectionX, xm); + if (slot >= 0 && slot == lastSelection && std::abs(selectionX - xm) < 10) + selectItem(slot, false); + else + selectCancel(); + } else { + selectCancel(); + } + } + + // if (slot >= 0 && std::abs(selectionX - xm) < itemWidth) + // { + // bool doubleClick = false; + // selectItem(slot, doubleClick); + // //xInertia = 0.0f; + // } + //} + dragState = NO_DRAG; + + xo = getPos(a); + } + xDrag = (float)xm; + + capXPosition(); + + Tesselator& t = Tesselator::instance; + + float by0 = _renderTopBorder? y0 : 0; + float by1 = _renderBottomBorder? y1 : height; + + //LOGI("x: %f\n", xo); + + minecraft.textures().loadAndBindTexture("gui/background.png"); + glColor4f2(1.0f, 1, 1, 1); + float s = 32; + t.begin(); + t.color(0x202020); + t.vertexUV(x0, by1, 0, (x0 + (int) xo) / s, by1 / s); + t.vertexUV(x1, by1, 0, (x1 + (int) xo) / s, by1 / s); + t.vertexUV(x1, by0, 0, (x1 + (int) xo) / s, by0 / s); + t.vertexUV(x0, by0, 0, (x0 + (int) xo) / s, by0 / s); + t.draw(); + + const int HalfHeight = 48; + + if (getNumberOfItems() == 0) xo = 0; + + int rowY = (int)(height / 2 - HalfHeight + 8); + int rowBaseX = (int)(x0 /*+ 4*/ - (int) xo); + + if (doRenderHeader) { + renderHeader(rowBaseX, rowY, t); + } + + for (int i = 0; i < itemCount; i++) { + + float x = (float)(rowBaseX + (i) * itemWidth + headerWidth); + float h = (float)itemWidth; + + if (x > x1 || (x + h) < x0) { + continue; + } + + if (renderSelection && isSelectedItem(i)) { + float y0 = height / 2.0f - HalfHeight - 4; //@kindle-res:+2 + float y1 = height / 2.0f + HalfHeight - 4; //@kindle-res:-6 + glColor4f2(1, 1, 1, 1); + glDisable2(GL_TEXTURE_2D); + + int ew = 0; + int color = 0x808080; + if (_componentSelected) { + ew = 0; + color = 0x7F89BF; + } + t.begin(); + t.color(color); + t.vertex(x - 1 - ew, y0 - ew, 0); + t.vertex(x - 1 - ew, y1 + ew, 0); + t.vertex(x + h + 1 + ew, y1 + ew, 0); + t.vertex(x + h + 1 + ew, y0 - ew, 0); + + t.color(0x000000); + t.vertex(x, y0 + 1, 0); + t.vertex(x, y1 - 1, 0); + t.vertex(x + h, y1 - 1, 0); + t.vertex(x + h, y0 + 1, 0); + + t.draw(); + glEnable2(GL_TEXTURE_2D); + } + renderItem(i, (int)x, rowY, (int)h, t); + } + + glDisable2(GL_DEPTH_TEST); + + if (_renderTopBorder) + renderHoleBackground(0, y0, 255, 255); + if (_renderBottomBorder) + renderHoleBackground(y1, (float)height, 255, 255); + + //glEnable2(GL_BLEND); + //glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glDisable2(GL_ALPHA_TEST); + //glShadeModel2(GL_SMOOTH); + + //glDisable2(GL_TEXTURE_2D); + + //const int d = 4; + //t.begin(); + //t.color(0x000000, 0); + //t.vertexUV(y0, x0 + d, 0, 0, 1); + //t.vertexUV(y1, x0 + d, 0, 1, 1); + //t.color(0x000000, 255); + //t.vertexUV(y1, x0, 0, 1, 0); + //t.vertexUV(y0, x0, 0, 0, 0); + //t.draw(); + + //t.begin(); + //t.color(0x000000, 255); + //t.vertexUV(y0, x1, 0, 0, 1); + //t.vertexUV(y1, x1, 0, 1, 1); + //t.color(0x000000, 0); + //t.vertexUV(y1, x1 - d, 0, 1, 0); + //t.vertexUV(y0, x1 - d, 0, 0, 0); + //t.draw(); + + //renderDecorations(xm, ym); + + //glEnable2(GL_TEXTURE_2D); + glEnable2(GL_DEPTH_TEST); + + //glShadeModel2(GL_FLAT); + //glEnable2(GL_ALPHA_TEST); + //glDisable2(GL_BLEND); +} + +void RolledSelectionListH::renderHoleBackground( /*float x0, float x1,*/ float y0, float y1, int a0, int a1 ) +{ + Tesselator& t = Tesselator::instance; + minecraft.textures().loadAndBindTexture("gui/background.png"); + glColor4f2(1.0f, 1, 1, 1); + float s = 32; + t.begin(); + t.color(0x505050, a1); + t.vertexUV(0, y1, 0, 0, y1 / s); + t.vertexUV((float)width, y1, 0, width / s, y1 / s); + t.color(0x505050, a0); + t.vertexUV((float)width, y0, 0, width / s, y0 / s); + t.vertexUV(0, y0, 0, 0, y0 / s); + t.draw(); + //printf("x, y, x1, y1: %d, %d, %d, %d\n", 0, (int)y0, width, (int)y1); +} + +void RolledSelectionListH::touched() +{ +} diff --git a/src/client/gui/components/RolledSelectionListH.h b/src/client/gui/components/RolledSelectionListH.hpp similarity index 97% rename from src/client/gui/components/RolledSelectionListH.h rename to src/client/gui/components/RolledSelectionListH.hpp index a6dea76..88c5739 100755 --- a/src/client/gui/components/RolledSelectionListH.h +++ b/src/client/gui/components/RolledSelectionListH.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../GuiComponent.h" +#include "client/gui/GuiComponent.hpp" class MinecraftClient; class Tesselator; diff --git a/src/client/gui/components/RolledSelectionListV.cpp b/src/client/gui/components/RolledSelectionListV.cpp index e42d9bd..6d5b815 100755 --- a/src/client/gui/components/RolledSelectionListV.cpp +++ b/src/client/gui/components/RolledSelectionListV.cpp @@ -1,352 +1,352 @@ -#include "RolledSelectionListV.h" -#include "../../Minecraft.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/gles.h" -#include "../../../platform/input/Mouse.h" -#include "../../../util/Mth.h" -#include "../../renderer/Textures.h" - - -RolledSelectionListV::RolledSelectionListV( Minecraft* minecraft_, int width_, int height_, int x0_, int x1_, int y0_, int y1_, int itemHeight_ ) -: minecraft(minecraft_), - width(width_), - height(height_), - x0((float)x0_), - x1((float)x1_), - y0((float)y0_), - y1((float)y1_), - itemHeight(itemHeight_), - selectionY(-1), - lastSelectionTime(0), - lastSelection(-1), - renderSelection(true), - doRenderHeader(false), - headerHeight(0), - dragState(DRAG_OUTSIDE), - yDrag(0.0f), - yo(0.0f), - yoo(0.0f), - yInertia(0.0f), - _componentSelected(false), - _renderDirtBackground(true), - _renderTopBorder(true), - _renderBottomBorder(true), - _lastyoo(0), - _yinertia(0), - _stickPixels(0), - _lastxm(0), - _lastym(0) -{ - yo = yoo = 0;//(float)(-itemHeight) * 0.5f; - _lastyoo = yoo; -} - -void RolledSelectionListV::setRenderSelection( bool _renderSelection ) -{ - renderSelection = _renderSelection; -} - -void RolledSelectionListV::setComponentSelected(bool selected) { - _componentSelected = selected; -} - -void RolledSelectionListV::setRenderHeader( bool _renderHeader, int _headerHeight ) -{ - doRenderHeader = _renderHeader; - headerHeight = _headerHeight; - - if (!doRenderHeader) { - headerHeight = 0; - } -} - -int RolledSelectionListV::getMaxPosition() -{ - return getNumberOfItems() * itemHeight + headerHeight; -} - -int RolledSelectionListV::getItemAtPosition( int x, int y ) -{ - int clickSlotPos = (int)(y - y0 - headerHeight + (int) yo - 4); - int isInsideX = x >= x0 && x <= x1; - return isInsideX? getItemAtYPositionRaw(clickSlotPos) : -1; -} - -int RolledSelectionListV::getItemAtYPositionRaw(int y) { - int slot = y / itemHeight; - bool isInsideX = slot >= 0 && y >= 0 && slot < getNumberOfItems(); - return isInsideX? slot : -1; -} - -bool RolledSelectionListV::capYPosition() -{ - float max = getMaxPosition() - (y1 - y0 - 4); - if (max < 0) max /= 2; - if (yo < 0) yo = 0; - if (yo > max) yo = max; - return false; -/* - const float MinY = -itemHeight/2;//(float)(itemHeight-height)/2; - const float MaxY = MinY + (getNumberOfItems()-1) * itemHeight; - if (yo < MinY) { yo = MinY; yInertia = 0; return true; } - if (yo > MaxY) { yo = MaxY; yInertia = 0; return true; } - return false; - */ -} - -void RolledSelectionListV::tick() { - - if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) - { - _yinertia = _lastyoo - yoo; - } - _lastyoo = yoo; - - //yInertia = Mth::absDecrease(yInertia, 1.0f, 0); - - yoo = yo - yInertia; - - //LOGI("tick: %f, %f, %f\n", yo, yInertia, _yinertia); -} - -float RolledSelectionListV::getPos(float alpha) { - return yoo - yInertia * alpha; -} - -void RolledSelectionListV::render( int xm, int ym, float a ) -{ - _lastxm = xm; - _lastym = ym; - renderBackground(); - - int itemCount = getNumberOfItems(); - - //float yy0 = height / 2.0f + 124; - //float yy1 = yy0 + 6; - - if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { - touched(); - //LOGI("DOWN ym: %d\n", ym); - if (ym >= y0 && ym <= y1) { - if (dragState == NO_DRAG) { - lastSelectionTime = getTimeMs(); - lastSelection = convertSelection( getItemAtPosition(width/2, ym), xm, ym ); - selectStart(lastSelection); - //LOGI("Sel : %d\n", lastSelection); - selectionY = ym; - _stickPixels = 10; - } - else if (dragState >= 0) { - float delta = (ym - yDrag); - float absDelta = Mth::abs(delta); - if (absDelta > _stickPixels) { - _stickPixels = 0; - delta -= delta>0? _stickPixels : -_stickPixels; - } else { - delta = 0; - _stickPixels -= absDelta; - } - yo -= delta; - yoo = yo; - } - dragState = DRAG_NORMAL; - } - } else { - if (dragState >= 0) { - if (dragState >= 0) { - yInertia = _yinertia < 0? Mth::Max(-10.0f, _yinertia) : Mth::Min(10.0f, _yinertia); - } - // kill small inertia values when releasing scrollist - if (std::abs(yInertia) <= 2.0001f) { - yInertia = 0.0f; - } - - if (std::abs(yInertia) <= 10 /*&& getTimeMs() - lastSelectionTime < 300 */) - { - //float clickSlotPos = (ym - x0 - headerHeight + (int) yo - 4); - int slot = convertSelection( getItemAtPosition(width/2, ym), xm, ym); - //LOGI("slot: %d, lt: %d. diff: %d - %d\n", slot, lastSelection, selectionX, xm); - if (xm >= x0 && xm <= x1 && slot >= 0 && slot == lastSelection && std::abs(selectionY - ym) < 10) - selectItem(slot, false); - } else { - selectCancel(); - } - } - - // if (slot >= 0 && std::abs(selectionX - xm) < itemWidth) - // { - // bool doubleClick = false; - // selectItem(slot, doubleClick); - // //xInertia = 0.0f; - // } - //} - dragState = NO_DRAG; - - yo = getPos(a); - } - yDrag = (float)ym; - - evaluate(xm, ym); - capYPosition(); - - Tesselator& t = Tesselator::instance; - - const int HalfWidth = 48; - int rowX = (int)(width / 2 - HalfWidth + 8); - int rowBaseY = (int)(y0 + 4 - (int) yo); - - if (_renderDirtBackground) - renderDirtBackground(); - - if (getNumberOfItems() == 0) yo = 0; - - //int rowY = (int)(height / 2 - HalfHeight + 8); - if (doRenderHeader) { - const int HalfWidth = 48; - int rowX = (int)(width / 2 - HalfWidth + 8); - int rowBaseY = (int)(y0 + 4 - (int) yo); - renderHeader(rowX, rowBaseY, t); - } - - onPreRender(); - for (int i = 0; i < itemCount; i++) { - - float y = (float)(rowBaseY + (i) * itemHeight + headerHeight); - float h = itemHeight - 4.0f; - - if (y > y1 || (y + h) < y0) { - continue; - } - - if (renderSelection && isSelectedItem(i)) { - //float y0 = height / 2.0f - HalfHeight - 4; - //float y1 = height / 2.0f + HalfHeight - 4; - //glColor4f2(1, 1, 1, 1); - //glDisable2(GL_TEXTURE_2D); - - //int ew = 0; - //int color = 0x808080; - //if (_componentSelected) { - // ew = 0; - // color = 0x7F89BF; - //} - //t.begin(); - //t.color(color); - //t.vertex(x - 2 - ew, y0 - ew, 0); - //t.vertex(x - 2 - ew, y1 + ew, 0); - //t.vertex(x + h + 2 + ew, y1 + ew, 0); - //t.vertex(x + h + 2 + ew, y0 - ew, 0); - - //t.color(0x000000); - //t.vertex(x - 1, y0 + 1, 0); - //t.vertex(x - 1, y1 - 1, 0); - //t.vertex(x + h + 1, y1 - 1, 0); - //t.vertex(x + h + 1, y0 + 1, 0); - - //t.draw(); - //glEnable2(GL_TEXTURE_2D); - } - renderItem(i, rowX, (int)y, (int)h, t); - } - onPostRender(); - - glDisable2(GL_DEPTH_TEST); - - if (_renderTopBorder) - renderHoleBackground(0, y0, 255, 255); - if (_renderBottomBorder) - renderHoleBackground(y1, (float)height, 255, 255); - renderForeground(); - - //glEnable2(GL_BLEND); - //glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - //glDisable2(GL_ALPHA_TEST); - //glShadeModel2(GL_SMOOTH); - - //glDisable2(GL_TEXTURE_2D); - - //const int d = 4; - //t.begin(); - //t.color(0x000000, 0); - //t.vertexUV(y0, x0 + d, 0, 0, 1); - //t.vertexUV(y1, x0 + d, 0, 1, 1); - //t.color(0x000000, 255); - //t.vertexUV(y1, x0, 0, 1, 0); - //t.vertexUV(y0, x0, 0, 0, 0); - //t.draw(); - - //t.begin(); - //t.color(0x000000, 255); - //t.vertexUV(y0, x1, 0, 0, 1); - //t.vertexUV(y1, x1, 0, 1, 1); - //t.color(0x000000, 0); - //t.vertexUV(y1, x1 - d, 0, 1, 0); - //t.vertexUV(y0, x1 - d, 0, 0, 0); - //t.draw(); - - //renderDecorations(xm, ym); - - //glEnable2(GL_TEXTURE_2D); - //glEnable2(GL_DEPTH_TEST); - - //glShadeModel2(GL_FLAT); - //glEnable2(GL_ALPHA_TEST); - //glDisable2(GL_BLEND); -} - -void RolledSelectionListV::renderHoleBackground( /*float x0, float x1,*/ float y0, float y1, int a0, int a1 ) -{ - Tesselator& t = Tesselator::instance; - minecraft->textures->loadAndBindTexture("gui/background.png"); - glColor4f2(1.0f, 1, 1, 1); - float s = 32; - t.begin(); - t.color(0x505050, a1); - t.vertexUV(0, y1, 0, 0, y1 / s); - t.vertexUV((float)width, y1, 0, width / s, y1 / s); - t.color(0x505050, a0); - t.vertexUV((float)width, y0, 0, width / s, y0 / s); - t.vertexUV(0, y0, 0, 0, y0 / s); - t.draw(); - //printf("x, y, x1, y1: %d, %d, %d, %d\n", 0, (int)y0, width, (int)y1); -} - -void RolledSelectionListV::touched() -{ -} - -void RolledSelectionListV::evaluate(int xm, int ym) -{ - if (std::abs(selectionY - ym) >= 10) { - lastSelection = -1; - selectCancel(); - } -} - -void RolledSelectionListV::onPreRender() -{ -} - -void RolledSelectionListV::onPostRender() -{ -} - -void RolledSelectionListV::renderDirtBackground() -{ - float by0 = _renderTopBorder? y0 : 0; - float by1 = _renderBottomBorder? y1 : height; - - minecraft->textures->loadAndBindTexture("gui/background.png"); - glColor4f2(1.0f, 1, 1, 1); - float s = 32; - const float uvy = (float)((int) yo); - Tesselator& t = Tesselator::instance; - t.begin(); - t.color(0x202020); - t.vertexUV(x0, by1, 0, x0 / s, (by1+uvy) / s); - t.vertexUV(x1, by1, 0, x1 / s, (by1+uvy) / s); - t.vertexUV(x1, by0, 0, x1 / s, (by0+uvy) / s); - t.vertexUV(x0, by0, 0, x0 / s, (by0+uvy) / s); - t.draw(); - //LOGI("%f, %f - %f, %f\n", x0, by0, x1, by1); -} +#include "RolledSelectionListV.hpp" +#include "client/Minecraft.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/gles.hpp" +#include "platform/input/Mouse.hpp" +#include "util/Mth.hpp" +#include "client/renderer/Textures.hpp" + + +RolledSelectionListV::RolledSelectionListV( Minecraft* minecraft_, int width_, int height_, int x0_, int x1_, int y0_, int y1_, int itemHeight_ ) +: minecraft(minecraft_), + width(width_), + height(height_), + x0((float)x0_), + x1((float)x1_), + y0((float)y0_), + y1((float)y1_), + itemHeight(itemHeight_), + selectionY(-1), + lastSelectionTime(0), + lastSelection(-1), + renderSelection(true), + doRenderHeader(false), + headerHeight(0), + dragState(DRAG_OUTSIDE), + yDrag(0.0f), + yo(0.0f), + yoo(0.0f), + yInertia(0.0f), + _componentSelected(false), + _renderDirtBackground(true), + _renderTopBorder(true), + _renderBottomBorder(true), + _lastyoo(0), + _yinertia(0), + _stickPixels(0), + _lastxm(0), + _lastym(0) +{ + yo = yoo = 0;//(float)(-itemHeight) * 0.5f; + _lastyoo = yoo; +} + +void RolledSelectionListV::setRenderSelection( bool _renderSelection ) +{ + renderSelection = _renderSelection; +} + +void RolledSelectionListV::setComponentSelected(bool selected) { + _componentSelected = selected; +} + +void RolledSelectionListV::setRenderHeader( bool _renderHeader, int _headerHeight ) +{ + doRenderHeader = _renderHeader; + headerHeight = _headerHeight; + + if (!doRenderHeader) { + headerHeight = 0; + } +} + +int RolledSelectionListV::getMaxPosition() +{ + return getNumberOfItems() * itemHeight + headerHeight; +} + +int RolledSelectionListV::getItemAtPosition( int x, int y ) +{ + int clickSlotPos = (int)(y - y0 - headerHeight + (int) yo - 4); + int isInsideX = x >= x0 && x <= x1; + return isInsideX? getItemAtYPositionRaw(clickSlotPos) : -1; +} + +int RolledSelectionListV::getItemAtYPositionRaw(int y) { + int slot = y / itemHeight; + bool isInsideX = slot >= 0 && y >= 0 && slot < getNumberOfItems(); + return isInsideX? slot : -1; +} + +bool RolledSelectionListV::capYPosition() +{ + float max = getMaxPosition() - (y1 - y0 - 4); + if (max < 0) max /= 2; + if (yo < 0) yo = 0; + if (yo > max) yo = max; + return false; +/* + const float MinY = -itemHeight/2;//(float)(itemHeight-height)/2; + const float MaxY = MinY + (getNumberOfItems()-1) * itemHeight; + if (yo < MinY) { yo = MinY; yInertia = 0; return true; } + if (yo > MaxY) { yo = MaxY; yInertia = 0; return true; } + return false; + */ +} + +void RolledSelectionListV::tick() { + + if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) + { + _yinertia = _lastyoo - yoo; + } + _lastyoo = yoo; + + //yInertia = Mth::absDecrease(yInertia, 1.0f, 0); + + yoo = yo - yInertia; + + //LOGI("tick: %f, %f, %f\n", yo, yInertia, _yinertia); +} + +float RolledSelectionListV::getPos(float alpha) { + return yoo - yInertia * alpha; +} + +void RolledSelectionListV::render( int xm, int ym, float a ) +{ + _lastxm = xm; + _lastym = ym; + renderBackground(); + + int itemCount = getNumberOfItems(); + + //float yy0 = height / 2.0f + 124; + //float yy1 = yy0 + 6; + + if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { + touched(); + //LOGI("DOWN ym: %d\n", ym); + if (ym >= y0 && ym <= y1) { + if (dragState == NO_DRAG) { + lastSelectionTime = getTimeMs(); + lastSelection = convertSelection( getItemAtPosition(width/2, ym), xm, ym ); + selectStart(lastSelection); + //LOGI("Sel : %d\n", lastSelection); + selectionY = ym; + _stickPixels = 10; + } + else if (dragState >= 0) { + float delta = (ym - yDrag); + float absDelta = Mth::abs(delta); + if (absDelta > _stickPixels) { + _stickPixels = 0; + delta -= delta>0? _stickPixels : -_stickPixels; + } else { + delta = 0; + _stickPixels -= absDelta; + } + yo -= delta; + yoo = yo; + } + dragState = DRAG_NORMAL; + } + } else { + if (dragState >= 0) { + if (dragState >= 0) { + yInertia = _yinertia < 0? Mth::Max(-10.0f, _yinertia) : Mth::Min(10.0f, _yinertia); + } + // kill small inertia values when releasing scrollist + if (std::abs(yInertia) <= 2.0001f) { + yInertia = 0.0f; + } + + if (std::abs(yInertia) <= 10 /*&& getTimeMs() - lastSelectionTime < 300 */) + { + //float clickSlotPos = (ym - x0 - headerHeight + (int) yo - 4); + int slot = convertSelection( getItemAtPosition(width/2, ym), xm, ym); + //LOGI("slot: %d, lt: %d. diff: %d - %d\n", slot, lastSelection, selectionX, xm); + if (xm >= x0 && xm <= x1 && slot >= 0 && slot == lastSelection && std::abs(selectionY - ym) < 10) + selectItem(slot, false); + } else { + selectCancel(); + } + } + + // if (slot >= 0 && std::abs(selectionX - xm) < itemWidth) + // { + // bool doubleClick = false; + // selectItem(slot, doubleClick); + // //xInertia = 0.0f; + // } + //} + dragState = NO_DRAG; + + yo = getPos(a); + } + yDrag = (float)ym; + + evaluate(xm, ym); + capYPosition(); + + Tesselator& t = Tesselator::instance; + + const int HalfWidth = 48; + int rowX = (int)(width / 2 - HalfWidth + 8); + int rowBaseY = (int)(y0 + 4 - (int) yo); + + if (_renderDirtBackground) + renderDirtBackground(); + + if (getNumberOfItems() == 0) yo = 0; + + //int rowY = (int)(height / 2 - HalfHeight + 8); + if (doRenderHeader) { + const int HalfWidth = 48; + int rowX = (int)(width / 2 - HalfWidth + 8); + int rowBaseY = (int)(y0 + 4 - (int) yo); + renderHeader(rowX, rowBaseY, t); + } + + onPreRender(); + for (int i = 0; i < itemCount; i++) { + + float y = (float)(rowBaseY + (i) * itemHeight + headerHeight); + float h = itemHeight - 4.0f; + + if (y > y1 || (y + h) < y0) { + continue; + } + + if (renderSelection && isSelectedItem(i)) { + //float y0 = height / 2.0f - HalfHeight - 4; + //float y1 = height / 2.0f + HalfHeight - 4; + //glColor4f2(1, 1, 1, 1); + //glDisable2(GL_TEXTURE_2D); + + //int ew = 0; + //int color = 0x808080; + //if (_componentSelected) { + // ew = 0; + // color = 0x7F89BF; + //} + //t.begin(); + //t.color(color); + //t.vertex(x - 2 - ew, y0 - ew, 0); + //t.vertex(x - 2 - ew, y1 + ew, 0); + //t.vertex(x + h + 2 + ew, y1 + ew, 0); + //t.vertex(x + h + 2 + ew, y0 - ew, 0); + + //t.color(0x000000); + //t.vertex(x - 1, y0 + 1, 0); + //t.vertex(x - 1, y1 - 1, 0); + //t.vertex(x + h + 1, y1 - 1, 0); + //t.vertex(x + h + 1, y0 + 1, 0); + + //t.draw(); + //glEnable2(GL_TEXTURE_2D); + } + renderItem(i, rowX, (int)y, (int)h, t); + } + onPostRender(); + + glDisable2(GL_DEPTH_TEST); + + if (_renderTopBorder) + renderHoleBackground(0, y0, 255, 255); + if (_renderBottomBorder) + renderHoleBackground(y1, (float)height, 255, 255); + renderForeground(); + + //glEnable2(GL_BLEND); + //glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + //glDisable2(GL_ALPHA_TEST); + //glShadeModel2(GL_SMOOTH); + + //glDisable2(GL_TEXTURE_2D); + + //const int d = 4; + //t.begin(); + //t.color(0x000000, 0); + //t.vertexUV(y0, x0 + d, 0, 0, 1); + //t.vertexUV(y1, x0 + d, 0, 1, 1); + //t.color(0x000000, 255); + //t.vertexUV(y1, x0, 0, 1, 0); + //t.vertexUV(y0, x0, 0, 0, 0); + //t.draw(); + + //t.begin(); + //t.color(0x000000, 255); + //t.vertexUV(y0, x1, 0, 0, 1); + //t.vertexUV(y1, x1, 0, 1, 1); + //t.color(0x000000, 0); + //t.vertexUV(y1, x1 - d, 0, 1, 0); + //t.vertexUV(y0, x1 - d, 0, 0, 0); + //t.draw(); + + //renderDecorations(xm, ym); + + //glEnable2(GL_TEXTURE_2D); + //glEnable2(GL_DEPTH_TEST); + + //glShadeModel2(GL_FLAT); + //glEnable2(GL_ALPHA_TEST); + //glDisable2(GL_BLEND); +} + +void RolledSelectionListV::renderHoleBackground( /*float x0, float x1,*/ float y0, float y1, int a0, int a1 ) +{ + Tesselator& t = Tesselator::instance; + minecraft->textures->loadAndBindTexture("gui/background.png"); + glColor4f2(1.0f, 1, 1, 1); + float s = 32; + t.begin(); + t.color(0x505050, a1); + t.vertexUV(0, y1, 0, 0, y1 / s); + t.vertexUV((float)width, y1, 0, width / s, y1 / s); + t.color(0x505050, a0); + t.vertexUV((float)width, y0, 0, width / s, y0 / s); + t.vertexUV(0, y0, 0, 0, y0 / s); + t.draw(); + //printf("x, y, x1, y1: %d, %d, %d, %d\n", 0, (int)y0, width, (int)y1); +} + +void RolledSelectionListV::touched() +{ +} + +void RolledSelectionListV::evaluate(int xm, int ym) +{ + if (std::abs(selectionY - ym) >= 10) { + lastSelection = -1; + selectCancel(); + } +} + +void RolledSelectionListV::onPreRender() +{ +} + +void RolledSelectionListV::onPostRender() +{ +} + +void RolledSelectionListV::renderDirtBackground() +{ + float by0 = _renderTopBorder? y0 : 0; + float by1 = _renderBottomBorder? y1 : height; + + minecraft->textures->loadAndBindTexture("gui/background.png"); + glColor4f2(1.0f, 1, 1, 1); + float s = 32; + const float uvy = (float)((int) yo); + Tesselator& t = Tesselator::instance; + t.begin(); + t.color(0x202020); + t.vertexUV(x0, by1, 0, x0 / s, (by1+uvy) / s); + t.vertexUV(x1, by1, 0, x1 / s, (by1+uvy) / s); + t.vertexUV(x1, by0, 0, x1 / s, (by0+uvy) / s); + t.vertexUV(x0, by0, 0, x0 / s, (by0+uvy) / s); + t.draw(); + //LOGI("%f, %f - %f, %f\n", x0, by0, x1, by1); +} diff --git a/src/client/gui/components/RolledSelectionListV.h b/src/client/gui/components/RolledSelectionListV.hpp similarity index 98% rename from src/client/gui/components/RolledSelectionListV.h rename to src/client/gui/components/RolledSelectionListV.hpp index a0338e8..f535fed 100755 --- a/src/client/gui/components/RolledSelectionListV.h +++ b/src/client/gui/components/RolledSelectionListV.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../GuiComponent.h" +#include "client/gui/GuiComponent.hpp" class Minecraft; class Tesselator; diff --git a/src/client/gui/components/ScrolledSelectionList.cpp b/src/client/gui/components/ScrolledSelectionList.cpp index 55a643f..95aff90 100755 --- a/src/client/gui/components/ScrolledSelectionList.cpp +++ b/src/client/gui/components/ScrolledSelectionList.cpp @@ -1,296 +1,296 @@ -#include "ScrolledSelectionList.h" -#include "../../Minecraft.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/gles.h" -#include "../../../platform/input/Mouse.h" -#include "../../renderer/Textures.h" - -static int Abs(int d) { - return d >= 0? d : -d; -} - -ScrolledSelectionList::ScrolledSelectionList( Minecraft* _minecraft, int _width, int _height, int _y0, int _y1, int _itemHeight ) -: minecraft(_minecraft), - width(_width), - height(_height), - y0((float)_y0), - y1((float)_y1), - itemHeight(_itemHeight), - x0(0.0f), - x1((float)_width), - selectionY(-1), - lastSelectionTime(0), - renderSelection(true), - doRenderHeader(false), - headerHeight(0), - dragState(DRAG_OUTSIDE), - yDrag(0.0f), - yo(0.0f), - yInertia(0.0f) -{ -} - -void ScrolledSelectionList::setRenderSelection( bool _renderSelection ) -{ - renderSelection = _renderSelection; -} - -void ScrolledSelectionList::setRenderHeader( bool _renderHeader, int _headerHeight ) -{ - doRenderHeader = _renderHeader; - headerHeight = _headerHeight; - - if (!doRenderHeader) { - headerHeight = 0; - } -} - -int ScrolledSelectionList::getMaxPosition() -{ - return getNumberOfItems() * itemHeight + headerHeight; -} - -int ScrolledSelectionList::getItemAtPosition( int x, int y ) -{ - int x0 = width / 2 - (92 + 16 + 2); - int x1 = width / 2 + (92 + 16 + 2); - - int clickSlotPos = (int)(y - y0 - headerHeight + (int) yo - 4); - int slot = clickSlotPos / itemHeight; - if (x >= x0 && x <= x1 && slot >= 0 && clickSlotPos >= 0 && slot < getNumberOfItems()) { - return slot; - } - return -1; -} - -void ScrolledSelectionList::capYPosition() -{ - float max = getMaxPosition() - (y1 - y0 - 4); - if (max < 0) max /= 2; - if (yo < 0) yo = 0; - if (yo > max) yo = max; -} - -void ScrolledSelectionList::render( int xm, int ym, float a ) -{ - renderBackground(); - - int itemCount = getNumberOfItems(); - - //float xx0 = width / 2.0f + 124; - //float xx1 = xx0 + 6; - - - if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { - //LOGI("DOWN ym: %d\n", ym); - if (ym >= y0 && ym <= y1 && ym != ignoreY) { - if (dragState == NO_DRAG) { - dragState = DRAG_SKIP; - } - else if (dragState >= 0) - { - if (dragState == DRAG_SKIP) - { - lastSelectionTime = getTimeMs(); - selectionY = ym; - } - else if (dragState == DRAG_NORMAL) - { - yo -= (ym - yDrag); - yInertia += (float)(ym - yDrag); - } - dragState = DRAG_NORMAL; - } - ignoreY = -1; - } - - } else { - if (dragState != NO_DRAG) - { - //LOGI("UP ym: %d\n", ym); - } - //ignoreY = ym; - - // kill small inertia values when releasing scrollist - if (dragState >= 0 && std::abs(yInertia) < 2) - { - yInertia = 0.0f; - } - - if (dragState >= 0 && getTimeMs() - lastSelectionTime < 300) - { - float clickSlotPos = (ym - y0 - headerHeight + (int) yo - 4); - int slot = (int)clickSlotPos / itemHeight; - - if (slot >= 0 && Abs(selectionY - ym) < itemHeight) - { - bool doubleClick = false; - selectItem(slot, doubleClick); - yInertia = 0.0f; - } - } - dragState = NO_DRAG; - - yo -= yInertia; - } - yInertia = yInertia * .75f; - yDrag = (float)ym; - - capYPosition(); - - Tesselator& t = Tesselator::instance; - - renderDirtBackground(); - - int rowX = (int)(width / 2 - 92 - 16); - int rowBaseY = (int)(y0 + 4 - (int) yo); - - if (doRenderHeader) { - renderHeader(rowX, rowBaseY, t); - } - - for (int i = 0; i < itemCount; i++) { - - float y = (float)(rowBaseY + (i) * itemHeight + headerHeight); - float h = itemHeight - 4.0f; - - if (y > y1 || (y + h) < y0) { - continue; - } - - if (renderSelection && isSelectedItem(i)) { - float x0 = width / 2.0f - (92 + 16 + 2); - float x1 = width / 2.0f + (92 + 16 + 2); - glColor4f2(1, 1, 1, 1); - glDisable2(GL_TEXTURE_2D); - t.begin(); - t.color(0x808080); - t.vertexUV(x0, y + h + 2, 0, 0, 1); - t.vertexUV(x1, y + h + 2, 0, 1, 1); - t.vertexUV(x1, y - 2, 0, 1, 0); - t.vertexUV(x0, y - 2, 0, 0, 0); - - t.color(0x000000); - t.vertexUV(x0 + 1, y + h + 1, 0, 0, 1); - t.vertexUV(x1 - 1, y + h + 1, 0, 1, 1); - t.vertexUV(x1 - 1, y - 1, 0, 1, 0); - t.vertexUV(x0 + 1, y - 1, 0, 0, 0); - - t.draw(); - glEnable2(GL_TEXTURE_2D); - } - - renderItem(i, rowX, (int)y, (int)h, t); - - } - - glDisable2(GL_DEPTH_TEST); - - - int d = 4; - - renderHoleBackground(0, y0, 255, 255); - renderHoleBackground(y1, (float)height, 255, 255); - - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable2(GL_ALPHA_TEST); - glShadeModel2(GL_SMOOTH); - - glDisable2(GL_TEXTURE_2D); - - t.begin(); - t.color(0x000000, 0); - t.vertexUV(x0, y0 + d, 0, 0, 1); - t.vertexUV(x1, y0 + d, 0, 1, 1); - t.color(0x000000, 255); - t.vertexUV(x1, y0, 0, 1, 0); - t.vertexUV(x0, y0, 0, 0, 0); - t.draw(); - - t.begin(); - t.color(0x000000, 255); - t.vertexUV(x0, y1, 0, 0, 1); - t.vertexUV(x1, y1, 0, 1, 1); - t.color(0x000000, 0); - t.vertexUV(x1, y1 - d, 0, 1, 0); - t.vertexUV(x0, y1 - d, 0, 0, 0); - t.draw(); - - // { - // float max = getMaxPosition() - (y1 - y0 - 4); - // if (max > 0) { - // float barHeight = (y1 - y0) * (y1 - y0) / (getMaxPosition()); - // if (barHeight < 32) barHeight = 32; - // if (barHeight > (y1 - y0 - 8)) barHeight = (y1 - y0 - 8); - // - // float yp = (int) yo * (y1 - y0 - barHeight) / max + y0; - // if (yp < y0) yp = y0; - // - // t.begin(); - // t.color(0x000000, 255); - // t.vertexUV(xx0, y1, 0.0f, 0.0f, 1.0f); - // t.vertexUV(xx1, y1, 0.0f, 1.0f, 1.0f); - // t.vertexUV(xx1, y0, 0.0f, 1.0f, 0.0f); - // t.vertexUV(xx0, y0, 0.0f, 0.0f, 0.0f); - // t.draw(); - // - // t.begin(); - // t.color(0x808080, 255); - // t.vertexUV(xx0, yp + barHeight, 0, 0, 1); - // t.vertexUV(xx1, yp + barHeight, 0, 1, 1); - // t.vertexUV(xx1, yp, 0, 1, 0); - // t.vertexUV(xx0, yp, 0, 0, 0); - // t.draw(); - // - // t.begin(); - // t.color(0xc0c0c0, 255); - // t.vertexUV(xx0, yp + barHeight - 1, 0, 0, 1); - // t.vertexUV(xx1 - 1, yp + barHeight - 1, 0, 1, 1); - // t.vertexUV(xx1 - 1, yp, 0, 1, 0); - // t.vertexUV(xx0, yp, 0, 0, 0); - // t.draw(); - // } - // } - - renderDecorations(xm, ym); - - - glEnable2(GL_TEXTURE_2D); - glEnable2(GL_DEPTH_TEST); - - glShadeModel2(GL_FLAT); - glEnable2(GL_ALPHA_TEST); - glDisable2(GL_BLEND); -} - -void ScrolledSelectionList::renderHoleBackground( float y0, float y1, int a0, int a1 ) -{ - Tesselator& t = Tesselator::instance; - minecraft->textures->loadAndBindTexture("gui/background.png"); - glColor4f2(1.0f, 1, 1, 1); - float s = 32; - t.begin(); - t.color(0x505050, a1); - t.vertexUV(0, y1, 0, 0, y1 / s); - t.vertexUV((float)width, y1, 0, width / s, y1 / s); - t.color(0x505050, a0); - t.vertexUV((float)width, y0, 0, width / s, y0 / s); - t.vertexUV(0, y0, 0, 0, y0 / s); - t.draw(); -} - -void ScrolledSelectionList::renderDirtBackground() -{ - Tesselator& t = Tesselator::instance; - minecraft->textures->loadAndBindTexture("gui/background.png"); - glColor4f2(1.0f, 1, 1, 1); - float s = 32; - t.begin(); - t.color(0x202020); - t.vertexUV(x0, y1, 0, x0 / s, (y1 + (int) yo) / s); - t.vertexUV(x1, y1, 0, x1 / s, (y1 + (int) yo) / s); - t.vertexUV(x1, y0, 0, x1 / s, (y0 + (int) yo) / s); - t.vertexUV(x0, y0, 0, x0 / s, (y0 + (int) yo) / s); - t.draw(); -} +#include "ScrolledSelectionList.hpp" +#include "client/Minecraft.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/gles.hpp" +#include "platform/input/Mouse.hpp" +#include "client/renderer/Textures.hpp" + +static int Abs(int d) { + return d >= 0? d : -d; +} + +ScrolledSelectionList::ScrolledSelectionList( Minecraft* _minecraft, int _width, int _height, int _y0, int _y1, int _itemHeight ) +: minecraft(_minecraft), + width(_width), + height(_height), + y0((float)_y0), + y1((float)_y1), + itemHeight(_itemHeight), + x0(0.0f), + x1((float)_width), + selectionY(-1), + lastSelectionTime(0), + renderSelection(true), + doRenderHeader(false), + headerHeight(0), + dragState(DRAG_OUTSIDE), + yDrag(0.0f), + yo(0.0f), + yInertia(0.0f) +{ +} + +void ScrolledSelectionList::setRenderSelection( bool _renderSelection ) +{ + renderSelection = _renderSelection; +} + +void ScrolledSelectionList::setRenderHeader( bool _renderHeader, int _headerHeight ) +{ + doRenderHeader = _renderHeader; + headerHeight = _headerHeight; + + if (!doRenderHeader) { + headerHeight = 0; + } +} + +int ScrolledSelectionList::getMaxPosition() +{ + return getNumberOfItems() * itemHeight + headerHeight; +} + +int ScrolledSelectionList::getItemAtPosition( int x, int y ) +{ + int x0 = width / 2 - (92 + 16 + 2); + int x1 = width / 2 + (92 + 16 + 2); + + int clickSlotPos = (int)(y - y0 - headerHeight + (int) yo - 4); + int slot = clickSlotPos / itemHeight; + if (x >= x0 && x <= x1 && slot >= 0 && clickSlotPos >= 0 && slot < getNumberOfItems()) { + return slot; + } + return -1; +} + +void ScrolledSelectionList::capYPosition() +{ + float max = getMaxPosition() - (y1 - y0 - 4); + if (max < 0) max /= 2; + if (yo < 0) yo = 0; + if (yo > max) yo = max; +} + +void ScrolledSelectionList::render( int xm, int ym, float a ) +{ + renderBackground(); + + int itemCount = getNumberOfItems(); + + //float xx0 = width / 2.0f + 124; + //float xx1 = xx0 + 6; + + + if (Mouse::isButtonDown(MouseAction::ACTION_LEFT)) { + //LOGI("DOWN ym: %d\n", ym); + if (ym >= y0 && ym <= y1 && ym != ignoreY) { + if (dragState == NO_DRAG) { + dragState = DRAG_SKIP; + } + else if (dragState >= 0) + { + if (dragState == DRAG_SKIP) + { + lastSelectionTime = getTimeMs(); + selectionY = ym; + } + else if (dragState == DRAG_NORMAL) + { + yo -= (ym - yDrag); + yInertia += (float)(ym - yDrag); + } + dragState = DRAG_NORMAL; + } + ignoreY = -1; + } + + } else { + if (dragState != NO_DRAG) + { + //LOGI("UP ym: %d\n", ym); + } + //ignoreY = ym; + + // kill small inertia values when releasing scrollist + if (dragState >= 0 && std::abs(yInertia) < 2) + { + yInertia = 0.0f; + } + + if (dragState >= 0 && getTimeMs() - lastSelectionTime < 300) + { + float clickSlotPos = (ym - y0 - headerHeight + (int) yo - 4); + int slot = (int)clickSlotPos / itemHeight; + + if (slot >= 0 && Abs(selectionY - ym) < itemHeight) + { + bool doubleClick = false; + selectItem(slot, doubleClick); + yInertia = 0.0f; + } + } + dragState = NO_DRAG; + + yo -= yInertia; + } + yInertia = yInertia * .75f; + yDrag = (float)ym; + + capYPosition(); + + Tesselator& t = Tesselator::instance; + + renderDirtBackground(); + + int rowX = (int)(width / 2 - 92 - 16); + int rowBaseY = (int)(y0 + 4 - (int) yo); + + if (doRenderHeader) { + renderHeader(rowX, rowBaseY, t); + } + + for (int i = 0; i < itemCount; i++) { + + float y = (float)(rowBaseY + (i) * itemHeight + headerHeight); + float h = itemHeight - 4.0f; + + if (y > y1 || (y + h) < y0) { + continue; + } + + if (renderSelection && isSelectedItem(i)) { + float x0 = width / 2.0f - (92 + 16 + 2); + float x1 = width / 2.0f + (92 + 16 + 2); + glColor4f2(1, 1, 1, 1); + glDisable2(GL_TEXTURE_2D); + t.begin(); + t.color(0x808080); + t.vertexUV(x0, y + h + 2, 0, 0, 1); + t.vertexUV(x1, y + h + 2, 0, 1, 1); + t.vertexUV(x1, y - 2, 0, 1, 0); + t.vertexUV(x0, y - 2, 0, 0, 0); + + t.color(0x000000); + t.vertexUV(x0 + 1, y + h + 1, 0, 0, 1); + t.vertexUV(x1 - 1, y + h + 1, 0, 1, 1); + t.vertexUV(x1 - 1, y - 1, 0, 1, 0); + t.vertexUV(x0 + 1, y - 1, 0, 0, 0); + + t.draw(); + glEnable2(GL_TEXTURE_2D); + } + + renderItem(i, rowX, (int)y, (int)h, t); + + } + + glDisable2(GL_DEPTH_TEST); + + + int d = 4; + + renderHoleBackground(0, y0, 255, 255); + renderHoleBackground(y1, (float)height, 255, 255); + + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable2(GL_ALPHA_TEST); + glShadeModel2(GL_SMOOTH); + + glDisable2(GL_TEXTURE_2D); + + t.begin(); + t.color(0x000000, 0); + t.vertexUV(x0, y0 + d, 0, 0, 1); + t.vertexUV(x1, y0 + d, 0, 1, 1); + t.color(0x000000, 255); + t.vertexUV(x1, y0, 0, 1, 0); + t.vertexUV(x0, y0, 0, 0, 0); + t.draw(); + + t.begin(); + t.color(0x000000, 255); + t.vertexUV(x0, y1, 0, 0, 1); + t.vertexUV(x1, y1, 0, 1, 1); + t.color(0x000000, 0); + t.vertexUV(x1, y1 - d, 0, 1, 0); + t.vertexUV(x0, y1 - d, 0, 0, 0); + t.draw(); + + // { + // float max = getMaxPosition() - (y1 - y0 - 4); + // if (max > 0) { + // float barHeight = (y1 - y0) * (y1 - y0) / (getMaxPosition()); + // if (barHeight < 32) barHeight = 32; + // if (barHeight > (y1 - y0 - 8)) barHeight = (y1 - y0 - 8); + // + // float yp = (int) yo * (y1 - y0 - barHeight) / max + y0; + // if (yp < y0) yp = y0; + // + // t.begin(); + // t.color(0x000000, 255); + // t.vertexUV(xx0, y1, 0.0f, 0.0f, 1.0f); + // t.vertexUV(xx1, y1, 0.0f, 1.0f, 1.0f); + // t.vertexUV(xx1, y0, 0.0f, 1.0f, 0.0f); + // t.vertexUV(xx0, y0, 0.0f, 0.0f, 0.0f); + // t.draw(); + // + // t.begin(); + // t.color(0x808080, 255); + // t.vertexUV(xx0, yp + barHeight, 0, 0, 1); + // t.vertexUV(xx1, yp + barHeight, 0, 1, 1); + // t.vertexUV(xx1, yp, 0, 1, 0); + // t.vertexUV(xx0, yp, 0, 0, 0); + // t.draw(); + // + // t.begin(); + // t.color(0xc0c0c0, 255); + // t.vertexUV(xx0, yp + barHeight - 1, 0, 0, 1); + // t.vertexUV(xx1 - 1, yp + barHeight - 1, 0, 1, 1); + // t.vertexUV(xx1 - 1, yp, 0, 1, 0); + // t.vertexUV(xx0, yp, 0, 0, 0); + // t.draw(); + // } + // } + + renderDecorations(xm, ym); + + + glEnable2(GL_TEXTURE_2D); + glEnable2(GL_DEPTH_TEST); + + glShadeModel2(GL_FLAT); + glEnable2(GL_ALPHA_TEST); + glDisable2(GL_BLEND); +} + +void ScrolledSelectionList::renderHoleBackground( float y0, float y1, int a0, int a1 ) +{ + Tesselator& t = Tesselator::instance; + minecraft->textures->loadAndBindTexture("gui/background.png"); + glColor4f2(1.0f, 1, 1, 1); + float s = 32; + t.begin(); + t.color(0x505050, a1); + t.vertexUV(0, y1, 0, 0, y1 / s); + t.vertexUV((float)width, y1, 0, width / s, y1 / s); + t.color(0x505050, a0); + t.vertexUV((float)width, y0, 0, width / s, y0 / s); + t.vertexUV(0, y0, 0, 0, y0 / s); + t.draw(); +} + +void ScrolledSelectionList::renderDirtBackground() +{ + Tesselator& t = Tesselator::instance; + minecraft->textures->loadAndBindTexture("gui/background.png"); + glColor4f2(1.0f, 1, 1, 1); + float s = 32; + t.begin(); + t.color(0x202020); + t.vertexUV(x0, y1, 0, x0 / s, (y1 + (int) yo) / s); + t.vertexUV(x1, y1, 0, x1 / s, (y1 + (int) yo) / s); + t.vertexUV(x1, y0, 0, x1 / s, (y0 + (int) yo) / s); + t.vertexUV(x0, y0, 0, x0 / s, (y0 + (int) yo) / s); + t.draw(); +} diff --git a/src/client/gui/components/ScrolledSelectionList.h b/src/client/gui/components/ScrolledSelectionList.hpp similarity index 97% rename from src/client/gui/components/ScrolledSelectionList.h rename to src/client/gui/components/ScrolledSelectionList.hpp index 199edd0..f85c0a7 100755 --- a/src/client/gui/components/ScrolledSelectionList.h +++ b/src/client/gui/components/ScrolledSelectionList.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../GuiComponent.h" +#include "client/gui/GuiComponent.hpp" class Minecraft; class Tesselator; diff --git a/src/client/gui/components/ScrollingPane.cpp b/src/client/gui/components/ScrollingPane.cpp index 090bc3a..c087401 100755 --- a/src/client/gui/components/ScrollingPane.cpp +++ b/src/client/gui/components/ScrollingPane.cpp @@ -1,805 +1,805 @@ -#include "ScrollingPane.h" -#include "../../renderer/gles.h" -#include "../Gui.h" -#include "../../../util/Mth.h" -#include "../../../SharedConstants.h" - -#define STR(x) (x.toString().c_str()) - -static const float kPenetrationDeceleration = 0.03f; -static const float kPenetrationAcceleration = 0.08f; -static const float kMaxTrackingTime = 100.0f; -static const float kAcceleration = 15; -static const float kMinVelocityForDecelerationWithPaging = 4 / 3.0f; -static const float kMinVelocityForDeceleration = 1 / 3.0f; -static const float kDesiredAnimationFrameRate = 1000.0f / 60; -static const float kDecelerationFrictionFactor = 0.95f; -static const float kMinimumVelocityToHideScrollIndicators = 0.05f; -static const float kMinimumVelocity = 0.01f; -static const float kMinimumTrackingForDrag = 5; -static const float kMinIndicatorLength = 34.0f / 3; -static const float PKScrollIndicatorEndSize = 3; -static const float PKScrollIndicatorThickness = 7.0f /3; -static const float kWheelOverscrollMax = 80.0f; -static const float kWheelOverscrollDamping = 0.6f; -static const float kWheelOverscrollRestoreAlpha = 0.18f; - -ScrollingPane::ScrollingPane( - int optionFlags, - const IntRectangle& boundingBox, - const IntRectangle& itemRect, - int columns, - int numItems, - float screenScale /* = 1.0f */, - const IntRectangle& itemBoundingRect /*= IntRectangle(0,0,0,0)*/ ) -: flags(optionFlags), - bbox(boundingBox), - size(boundingBox), - area((float)bbox.x, (float)bbox.y, (float)(bbox.x + bbox.w), (float)(bbox.y + bbox.h)), - bboxArea(area), - itemRect(itemRect), - numItems(numItems), - screenScale(screenScale), - invScreenScale(1.0f / screenScale), - //hasItemBounding(), - px(0), py(0), fpx(0), fpy(0), - dx(0), dy(0), - dragState(-1), - dragLastDeltaTimeStamp(-1.0f), - friction(0.95f), - highlightTimer(-1), - highlightStarted(-1), - selectedId(-1), - decelerating(false), - tracking(false), - dragging(false), - pagingEnabled(false), - _scrollEnabled(true), - _timer(60), - _doStepTimer(false), - _wasDown(false),//Mouse::isButtonDown(MouseAction::ACTION_LEFT)), - _lx(-9999), _ly(-9999) -{ - if (itemBoundingRect.w > 0) - itemBbox = itemBoundingRect; - else - itemBbox = itemRect; - - this->columns = (columns>0)? columns : bbox.w / itemBbox.w; - - if (this->columns <= 0) { - LOGW("Columns are 0! Area width is smaller than item width. Setting columns to 1.\n"); - this->columns = 1; - } - //LOGI("%d, %d :: %d\n", bbox.w, itemBbox.w, this->columns); - - rows = 1 + (numItems-1) / this->columns; - - /* - if (columns * itemBbox.w <= bbox.w) flags |= SF_LockX; - if (rows * itemBbox.h <= bbox.h) flags |= SF_LockY; - */ - - // initialize content bounds immediately - adjustContentSize(); - minPoint.set((float)(this->size.w - this->adjustedContentSize.w), (float)(this->size.h - this->adjustedContentSize.h), 0); - this->snapContentOffsetToBounds(false); - - - dragDeltas.reserve(128); - - te_moved = 0; - te_ended = 1; - - selected = new bool[numItems]; - for (int i = 0; i < numItems; ++i) - selected[i] = false; - - // Setup the scroll bars - vScroll.w = vScroll.h = PKScrollIndicatorThickness; - hScroll.w = hScroll.h = PKScrollIndicatorThickness; - vScroll.x = bbox.x + bbox.w - vScroll.w; - vScroll.y = 0; - hScroll.x = 0; - hScroll.y = bbox.y + bbox.h - hScroll.h; - -// vScroll.alpha -// vScroll.fading = hScroll.fading = -1; -} - -ScrollingPane::~ScrollingPane() { - delete[] selected; -} - -//void ScrollingPane::init(Minecraft* mc, int width, int height) { -// this->mc = mc; -// this->width = width; -// this->height = height; -//} - -void ScrollingPane::tick() { - - if (isSet(SF_ShowScrollbar)) { - updateScrollFade(vScroll); - updateScrollFade(hScroll); - } - - if (isNotSet(SF_HardLimits) && !Mouse::isButtonDown(MouseAction::ACTION_LEFT) && !dragging && !tracking && !decelerating) { - float targetX = _contentOffset.x; - float targetY = _contentOffset.y; - bool corrected = false; - - if (targetX > 0.0f) { - targetX = Mth::lerp(targetX, 0.0f, kWheelOverscrollRestoreAlpha); - corrected = true; - } else if (targetX < minPoint.x) { - targetX = Mth::lerp(targetX, minPoint.x, kWheelOverscrollRestoreAlpha); - corrected = true; - } - - if (targetY > 0.0f) { - targetY = Mth::lerp(targetY, 0.0f, kWheelOverscrollRestoreAlpha); - corrected = true; - } else if (targetY < minPoint.y) { - targetY = Mth::lerp(targetY, minPoint.y, kWheelOverscrollRestoreAlpha); - corrected = true; - } - - if (corrected) { - if (Mth::abs(targetX - _contentOffset.x) < 0.25f) targetX = (targetX > 0.0f ? 0.0f : (targetX < minPoint.x ? minPoint.x : targetX)); - if (Mth::abs(targetY - _contentOffset.y) < 0.25f) targetY = (targetY > 0.0f ? 0.0f : (targetY < minPoint.y ? minPoint.y : targetY)); - setContentOffset(Vec3(targetX, targetY, 0)); - } - } -} - -bool ScrollingPane::getGridItemFor_slow(int itemIndex, GridItem& out) { - GridItem nw = getItemForPos(0, 0, false); - GridItem se = getItemForPos((float)bbox.w - 1, (float)bbox.h - 1, false); - const float bxx = bbox.x - (fpx /*+ dx*alpha*/) + (nw.xf - nw.x); - const float byy = bbox.y - (fpy /*+ dy*alpha*/) + (nw.yf - nw.y); - - int y = itemIndex / columns; - int x = itemIndex - (y * columns); - - out.id = itemIndex; - out.xf = bxx + x * itemBbox.w; - out.yf = byy + y * itemBbox.h; - out.x = x; - out.y = y; - - return x >= nw.x && x <= se.x - && y >= nw.y && y <= se.y; -} - - -void ScrollingPane::render( int xm, int ym, float alpha ) { - // Handle user interaction first - handleUserInput(); - - _timer.advanceTime(); - - if (_doStepTimer && !te_moved) { - for (int i = 0; i < _timer.ticks; ++i) - stepThroughDecelerationAnimation(false); - this->lastFrame = getTimeMs(); - } - - // Render - //if (isSet(SF_Scissor)) { - // glEnable2(GL_SCISSOR_TEST); - // GLuint x = (GLuint)(screenScale * bbox.x); - // GLuint y = 480 - (GLuint)(screenScale * (bbox.y + bbox.h)); - // GLuint w = (GLuint)(screenScale * bbox.w); - // GLuint h = (GLuint)(screenScale * bbox.h); - // glScissor(x, y, w, h); - // LOGI("x, y, w, h: %d, %d, %d, %d\n", x, y, w, h); - //} - - std::vector itemsToRender; - GridItem nw = getItemForPos(0, 0, false); - GridItem se = getItemForPos((float)bbox.w - 1, (float)bbox.h - 1, false); - - //LOGI("getItem: %d, %d - %d, %d\n", nw.x, nw.y, se.x, se.y); - - const float bxx = bbox.x - (fpx /*+ dx*alpha*/) + (nw.xf - nw.x); - const float byy = bbox.y - (fpy /*+ dy*alpha*/) + (nw.yf - nw.y); - for (int y = nw.y; y <= se.y; ++y) - for (int x = nw.x; x <= se.x; ++x) { - int id = y * columns + x; - if (y <0 || id < 0 || id >= numItems) continue; // @todo: break rather - if (isNotSet(SF_WrapX) && (x < 0 || x >= columns)) continue; // @todo: break rather - GridItem item; //@todo: v- Does not support SF_Wrapping - item.id = id; - item.xf = bxx + x * itemBbox.w; - item.yf = byy + y * itemBbox.h; - item.x = (int)item.xf; - item.y = (int)item.yf; - //LOGI("i: %d (%.1f, %.1f)\t", id, item.xf, item.yf); - if (isSet(SF_MultiSelect)) item.selected = selected[id]; - else item.selected = (id == selectedId); - - itemsToRender.push_back(item); - } - renderBatch(itemsToRender, alpha); - - //if (isSet(SF_Scissor)) - // glDisable2(GL_SCISSOR_TEST); -} - -void ScrollingPane::renderBatch(std::vector& items, float alpha) { - for (unsigned int i = 0; i < items.size(); ++i) - renderItem(items[i], alpha); -} - -void ScrollingPane::renderItem(GridItem& item, float alpha) { -} - -ScrollingPane::GridItem ScrollingPane::getItemForPos( float x, float y, bool isScreenPos ) { - // Screen relative pos (rather than ScrollingPane relative pos) - if (isScreenPos) { - x -= bbox.x; - y -= bbox.y; - } - - // Add the scrolled offset - x += fpx; - y += fpy; - - // Does the grid SF_Wrap around? - if (isSet(SF_WrapX)) x = fmod(x, (float)(itemBbox.w * columns)); - if (isSet(SF_WrapY)) y = fmod(y, (float)(itemBbox.h * rows)); - - GridItem out; - out.xf = x / itemBbox.w; - out.yf = y / itemBbox.h; - out.x = (int) out.xf; - out.y = (int) out.yf; - out.id = out.y * columns + out.x; - return out; -} - -void ScrollingPane::addDeltaPos(float x, float y, float dt, int a) { - if (dt <= 0) - return; - - Vec3 delta = (dragLastPos - Vec3(x, y, 0)) * (1.0f / dt); - dragDeltas.push_back(delta.x); - dragDeltas.push_back(delta.y); - dragLastPos.set(x, y, 0); - dragLastDeltaTimeStamp += dt; // @attn @fix: This relies on user to be correct - //LOGI(">> delta %d: %s\n", a, STR(delta)); -} - -static const int PKTableViewMinTouchDurationForCellSelection = 150; - -void ScrollingPane::handleUserInput() { - - bool isDown = Mouse::isButtonDown(MouseAction::ACTION_LEFT); - float x = Mouse::getX() * invScreenScale; - float y = Mouse::getY() * invScreenScale; - int t = getTimeMs(); - bool isInside = area.isInside(x, y); - //LOGI("inside? %d\n", isInside); - - bool moved = (x != _lx || y != _ly); - - _lx = x; - _ly = y; - - if (te_ended > 0 && _wasDown && !isDown) - touchesEnded(x, y, t); - else if (isDown && !_wasDown && isInside) - touchesBegan(x, y, t); - else if (te_moved > 0 && moved && isDown) - touchesMoved(x, y, t); - - if (highlightTimer >= 0 && isNotSet(SF_NoHoldSelect)) { - if (getTimeMs() - highlightTimer >= PKTableViewMinTouchDurationForCellSelection) - onHoldItem(); - } - - _wasDown = isDown; -} - -Vec3& ScrollingPane::contentOffset() { - return _contentOffset; -} - -void ScrollingPane::beginTracking(float x, float y, int t) { //@param 1: MouseEvent a - if (this->tracking) { - return; - } - //a.preventDefault(); - this->stopDecelerationAnimation(); - //this->hostingLayer.style.webkitTransitionDuration = 0; - this->adjustContentSize(); //@todo @? - this->minPoint.set((float)(this->size.w - this->adjustedContentSize.w), (float)(this->size.h - this->adjustedContentSize.h), 0); //@todo - this->snapContentOffsetToBounds(false); - this->startPosition = this->_contentOffset; - this->startTouchPosition.set(x, y, 0); - this->startTime = (float)t; - this->startTimePosition = this->contentOffset(); - this->tracking = true; - this->dragging = false; - this->touchesHaveMoved = false; - //window.addEventListener(PKMoveEvent, this, true); //@todo - //window.addEventListener(PKEndEvent, this, true); - //window.addEventListener("touchcancel", this, true); - //window.addEventListener(PKEndEvent, this, false) -}; - -void ScrollingPane::touchesBegan(float x, float y, int t) { //@param 1: MouseEvent a - if (!this->_scrollEnabled) { - return; - } - - te_ended = 1; - //if (a.eventPhase == Event.CAPTURING_PHASE) { - // if (a._manufactured) { - // return - // } - //this->highlightItem = getItemForPos(x, y, true); - // if (this.delaysContentTouches) { - // a.stopPropagation(); - // this.callMethodNameAfterDelay("beginTouchesInContent", kContentTouchesDelay, a); - this->beginTracking(x, y, t); - // } - //} else { - // this.beginTracking(a) - //} - te_moved = 2; - - GridItem gi = getItemForPos(x, y, true); - if (gi.id >= 0 && gi.id < numItems) { - //LOGI("Pressed down at %d (%d, %d)\n", gi.id, gi.x, gi.y); - highlightItem.id = bboxArea.isInside(x, y)? gi.id : -1; - highlightStarted = highlightTimer = bboxArea.isInside(x, y)? getTimeMs() : -1; - } else { - highlightItem.id = -1; - highlightStarted = highlightTimer = -1; - } -} - -void ScrollingPane::touchesMoved(float x, float y, int t) -{ - this->touchesHaveMoved = true; - //this->callSuper(d); - Vec3 e(x, y, 0); - float b = e.x - this->startTouchPosition.x; - float c = e.y - this->startTouchPosition.y; - if (!this->dragging) { - if ((Mth::abs(b) >= kMinimumTrackingForDrag && isNotSet(SF_LockX)) || (Mth::abs(c) >= kMinimumTrackingForDrag && isNotSet(SF_LockY))) { - willBeginDragging(); - this->dragging = true; - this->firstDrag = true; - - if (isSet(SF_ShowScrollbar)) { - if (isNotSet(SF_LockX) && (this->adjustedContentSize.w > this->size.w)) - //this->hScroll.visible = true; - this->hScroll.fading = 1; - if (isNotSet(SF_LockY) && (this->adjustedContentSize.h > this->size.h)) - //this->vScroll.visible = true; - this->vScroll.fading = 1; - } - } - } - if (this->dragging) { - //d.stopPropagation(); - float f = isNotSet(SF_LockX) ? (this->startPosition.x + b) : this->_contentOffset.x; - float a = isNotSet(SF_LockY) ? (this->startPosition.y + c) : this->_contentOffset.y; - if (isNotSet(SF_HardLimits)) { - f -= ((f < this->minPoint.x) ? (f - this->minPoint.x) : ((f > 0) ? f : 0)) / 2; - a -= ((a < this->minPoint.y) ? (a - this->minPoint.y) : ((a > 0) ? a : 0)) / 2; - } else { - f = Mth::Min(Mth::Max(this->minPoint.x, f), 0.0f); - a = Mth::Min(Mth::Max(this->minPoint.y, a), 0.0f); - } - if (this->firstDrag) { - this->firstDrag = false; - this->startTouchPosition = e; - return; - } - this->setContentOffset(f, a); - this->lastEventTime = t;//d.timeStamp; - } -} - -void ScrollingPane::touchesEnded(float x, float y, int t) { - te_ended = 0; - highlightStarted = -1; - //te_moved = 0; - - //this.callSuper(a); - this->tracking = false; - if (this->dragging) { - this->dragging = false; - //a.stopPropagation(); - if (t - this->lastEventTime <= kMaxTrackingTime) { - this->_contentOffsetBeforeDeceleration = this->_contentOffset; - this->startDecelerationAnimation(false); - } - if (!this->decelerating) {} - //window.removeEventListener(PKEndEvent, this, false); - didEndDragging(); - } - if (!this->decelerating) { - if (fpy < 0 || fpy > bbox.h) { //@todo: for x as well (or rather, x^y) - this->_contentOffsetBeforeDeceleration = this->_contentOffset; - this->startDecelerationAnimation(true); - } else { - this->snapContentOffsetToBounds(true); //@fix - this->hideScrollIndicators(); - } - } - //if (a.eventPhase == Event.BUBBLING_PHASE) { //@? @todo - // window.removeEventListener(PKEndEvent, this, false); - - //// old and shaky, doesn't work good with Xperia Play (and presumably lots of others) - //if (!this->touchesHaveMoved && this->highlightItem.id >= 0) { - // _onSelect(this->highlightItem.id); - //} - if (Vec3(x, y, 0).distanceToSqr(startTouchPosition) <= 6.0f * 6.0f && this->highlightItem.id >= 0) { - _onSelect(this->highlightItem.id); - } - //} - te_moved = 0; -}; - - -void ScrollingPane::touchesCancelled(float x, float y, int a) { - touchesEnded(x, y, a); -} - -void ScrollingPane::startDecelerationAnimation( bool force ) -{ - Vec3 a(this->_contentOffset.x - this->startTimePosition.x, this->_contentOffset.y - this->startTimePosition.y, 0); - float b = (getTimeMs()/*event.timeStamp*/ - this->startTime) / kAcceleration; - //LOGI("starting deceleration! %s, %f\n", STR(a), b); - - this->decelerationVelocity = Vec3(a.x / b, a.y / b, 0); - this->minDecelerationPoint = this->minPoint; - this->maxDecelerationPoint = Vec3(0, 0, 0); - if (this->pagingEnabled) { - this->minDecelerationPoint.x = Mth::Max(this->minPoint.x, std::floor(this->_contentOffsetBeforeDeceleration.x / this->size.w) * this->size.w); - this->minDecelerationPoint.y = Mth::Max(this->minPoint.y, std::floor(this->_contentOffsetBeforeDeceleration.y / this->size.h) * this->size.h); - this->maxDecelerationPoint.x = Mth::Min(0.0f, std::ceil(this->_contentOffsetBeforeDeceleration.x / this->size.w) * this->size.w); - this->maxDecelerationPoint.y = Mth::Min(0.0f, std::ceil(this->_contentOffsetBeforeDeceleration.y / this->size.h) * this->size.h); - } - this->penetrationDeceleration = kPenetrationDeceleration; - this->penetrationAcceleration = kPenetrationAcceleration; - if (this->pagingEnabled) { - this->penetrationDeceleration *= 5; - } - float c = this->pagingEnabled ? kMinVelocityForDecelerationWithPaging : kMinVelocityForDeceleration; - if (force || (Mth::abs(this->decelerationVelocity.x) > c || Mth::abs(this->decelerationVelocity.y) > c)) { - this->decelerating = true; - //LOGI("accelerating True - A\n"); - _doStepTimer = true; - //this->decelerationTimer = this->callMethodNameAfterDelay("stepThroughDecelerationAnimation", kDesiredAnimationFrameRate); //@? - this->lastFrame = getTimeMs(); - willBeginDecelerating(); - } -} - -void ScrollingPane::hideScrollIndicators() { - //hScroll.visible = vScroll.visible = false; - hScroll.fading = vScroll.fading = 0; -} - - -void ScrollingPane::stopDecelerationAnimation() -{ - //LOGI("decelerating False - A\n"); - this->decelerating = false; - _doStepTimer = false; - //clearTimeout(this.decelerationTimer) //@? -} - -void ScrollingPane::stepThroughDecelerationAnimation(bool noAnimation) { - if (!this->decelerating) { - return; - } - int d = getTimeMs(); - int k = d - this->lastFrame; - - int l = noAnimation ? 0 : (int)(std::floor(0.5f + ((float)k / kDesiredAnimationFrameRate) - 1)); - //LOGI("k: %d, %d %d : %d\n", d, this->lastFrame, k, l); - for (int j = 0; j < l; j++) - this->stepThroughDecelerationAnimation(true); - - float g = this->contentOffset().x + this->decelerationVelocity.x; - float h = this->contentOffset().y + this->decelerationVelocity.y; - if (isSet(SF_HardLimits)) { - float a = Mth::Min(Mth::Max(this->minPoint.x, g), 0.0f); - if (a != g) { - g = a; - this->decelerationVelocity.x = 0; - } - float c = Mth::Min(Mth::Max(this->minPoint.y, h), 0.0f); - if (c != h) { - h = c; - this->decelerationVelocity.y = 0; - } - } - if (noAnimation) { - this->contentOffset().x = g; - this->contentOffset().y = h; - } else { - this->setContentOffset(g, h); - } - if (!this->pagingEnabled) { - this->decelerationVelocity.x *= kDecelerationFrictionFactor; - this->decelerationVelocity.y *= kDecelerationFrictionFactor; - } - float b = Mth::abs(this->decelerationVelocity.x); - float i = Mth::abs(this->decelerationVelocity.y); - if (!noAnimation && b <= kMinimumVelocityToHideScrollIndicators && i <= kMinimumVelocityToHideScrollIndicators) { - this->hideScrollIndicators(); - if (b <= kMinimumVelocity && i <= kMinimumVelocity) { - //LOGI("decelerating False - B\n"); - this->decelerating = false; - didEndDecelerating(); - return; - } - } - if (!noAnimation) { - //this->decelerationTimer = this->callMethodNameAfterDelay("stepThroughDecelerationAnimation", kDesiredAnimationFrameRate) - } - //if (noAnimation) doStepTimer = false; - - - if (isNotSet(SF_HardLimits)) { - Vec3 e; - if (g < this->minDecelerationPoint.x) { - e.x = this->minDecelerationPoint.x - g; - } else { - if (g > this->maxDecelerationPoint.x) { - e.x = this->maxDecelerationPoint.x - g; - } - } - if (h < this->minDecelerationPoint.y) { - e.y = this->minDecelerationPoint.y - h; - } else { - if (h > this->maxDecelerationPoint.y) { - e.y = this->maxDecelerationPoint.y - h; - } - } - if (e.x != 0) { - if (e.x * this->decelerationVelocity.x <= 0) { - this->decelerationVelocity.x += e.x * this->penetrationDeceleration; - } else { - this->decelerationVelocity.x = e.x * this->penetrationAcceleration; - } - } - if (e.y != 0) { - if (e.y * this->decelerationVelocity.y <= 0) { - this->decelerationVelocity.y += e.y * this->penetrationDeceleration; - } else { - this->decelerationVelocity.y = e.y * this->penetrationAcceleration; - } - } - } - if (!noAnimation) { - this->lastFrame = d; - } -} - -void ScrollingPane::scrollBy(float dx, float dy) { - // compute target content offset from wheel delta (in screen-space w/ opposite sign) - float targetX = _contentOffset.x - dx; - float targetY = _contentOffset.y - dy; - - if (isSet(SF_LockX)) targetX = _contentOffset.x; - if (isSet(SF_LockY)) targetY = _contentOffset.y; - - if (isSet(SF_HardLimits)) { - targetX = Mth::clamp(targetX, minPoint.x, 0.0f); - targetY = Mth::clamp(targetY, minPoint.y, 0.0f); - } else { - if (targetX > 0.0f) { - float overshoot = targetX; - overshoot = Mth::Min(overshoot, kWheelOverscrollMax); - targetX = overshoot * kWheelOverscrollDamping; - } else if (targetX < minPoint.x) { - float overshoot = targetX - minPoint.x; - overshoot = Mth::Max(overshoot, -kWheelOverscrollMax); - targetX = minPoint.x + overshoot * kWheelOverscrollDamping; - } - - if (targetY > 0.0f) { - float overshoot = targetY; - overshoot = Mth::Min(overshoot, kWheelOverscrollMax); - targetY = overshoot * kWheelOverscrollDamping; - } else if (targetY < minPoint.y) { - float overshoot = targetY - minPoint.y; - overshoot = Mth::Max(overshoot, -kWheelOverscrollMax); - targetY = minPoint.y + overshoot * kWheelOverscrollDamping; - } - } - - setContentOffset(Vec3(targetX, targetY, 0)); -} - -void ScrollingPane::setContentOffset(float x, float y) { - this->setContentOffsetWithAnimation(Vec3(x, y, 0), false); -} -void ScrollingPane::setContentOffset(Vec3 a) { - this->setContentOffsetWithAnimation(a, false); -}; - -void ScrollingPane::setContentOffsetWithAnimation(Vec3 b, bool doScroll) { - this->_contentOffset = b; - fpx = -this->_contentOffset.x; - fpy = -this->_contentOffset.y; - /* //@todo //@? - this->hostingLayer.style.webkitTransform = PKUtils.t(this->_contentOffset.x, this->_contentOffset.y); - if (a) { - this->scrollTransitionsNeedRemoval = true; - this->hostingLayer.style.webkitTransitionDuration = kPagingTransitionDuration - } else { - this->didScroll(false) - } - */ - if (!doScroll) { - // @todo: for scroll indicator //@? - if (isSet(SF_ShowScrollbar)) { - if (isNotSet(SF_LockX)) this->updateHorizontalScrollIndicator(); - if (isNotSet(SF_LockY)) this->updateVerticalScrollIndicator(); - } - } - //this->notifyPropertyChange("contentOffset") -} - -void ScrollingPane::snapContentOffsetToBounds(bool a) { - bool b = false; - Vec3 c; - if (this->pagingEnabled) { - c.x = std::floor(0.5f + this->_contentOffset.x / this->size.w) * this->size.w; - c.y = std::floor(0.5f + this->_contentOffset.y / this->size.h) * this->size.h; - b = true; - } else { - if (isNotSet(SF_HardLimits)) { - c.x = Mth::Min(Mth::Max(this->minPoint.x, this->_contentOffset.x), 0.0f); - c.y = Mth::Min(Mth::Max(this->minPoint.y, this->_contentOffset.y), 0.0f); - b = (c.x != this->_contentOffset.x || c.y != this->_contentOffset.y); - } - } - if (b) { - this->setContentOffsetWithAnimation(c, a); - } -} - -void ScrollingPane::adjustContentSize() -{ - this->adjustedContentSize.w = Mth::Max(itemBbox.w * columns, bbox.w); - this->adjustedContentSize.h = Mth::Max(itemBbox.h * rows, bbox.h); -} - -void ScrollingPane::onHoldItem() { - //LOGI("dragging, tracking %d, %d\n", !this->dragging, this->tracking); - int id = highlightItem.id; - if (id != -1 && !this->dragging && this->tracking) - _onSelect(id); - highlightTimer = -1; - //highlightItem.id = -1; -} - -bool ScrollingPane::onSelect( int gridId, bool selected ) -{ - return selected; -} - -void ScrollingPane::updateHorizontalScrollIndicator() -{ - float c = (isNotSet(SF_LockX) && isSet(SF_ShowScrollbar)) ? PKScrollIndicatorEndSize * 2 : 1; - float d = Mth::Max(kMinIndicatorLength, std::floor(0.5f + (this->size.w / this->adjustedContentSize.w) * (this->size.w - c))); - float a = (-this->_contentOffset.x / (this->adjustedContentSize.w - this->size.w)) * (this->size.w - c - d); - //float b = this->size.h - PKScrollIndicatorThickness - 1; - if (this->_contentOffset.x > 0) { - d = std::floor(0.5f + Mth::Max(d - this->_contentOffset.x, PKScrollIndicatorThickness)); - a = 1; - } else { - if (this->_contentOffset.x < -(this->adjustedContentSize.w - this->size.w)) { - d = std::floor(0.5f + Mth::Max(d + this->adjustedContentSize.w - this->size.w + this->contentOffset().x, PKScrollIndicatorThickness)); - a = this->size.w - d - c; - } - } - this->hScroll.x = a + bbox.x; - //this->hScroll.y = b; - this->hScroll.w = d; //@property -}; - - -void ScrollingPane::updateVerticalScrollIndicator() -{ - float c = (isNotSet(SF_LockY) && isSet(SF_ShowScrollbar)) ? PKScrollIndicatorEndSize * 2 : 1; - float d = Mth::Max(kMinIndicatorLength, std::floor(0.5f + (this->size.h / this->adjustedContentSize.h) * (this->size.h - c))); - //float a = this->size.w - PKScrollIndicatorThickness - 1; - float b = (-this->_contentOffset.y / (this->adjustedContentSize.h - this->size.h)) * (this->size.h - c - d); - if (this->_contentOffset.y > 0) { - d = std::floor(0.5f + Mth::Max(d - this->_contentOffset.y, PKScrollIndicatorThickness)); - b = 1; - } else { - if (this->_contentOffset.y < -(this->adjustedContentSize.h - this->size.h)) { - d = std::floor(0.5f + Mth::Max(d + this->adjustedContentSize.h - this->size.h + this->contentOffset().y, PKScrollIndicatorThickness)); - b = this->size.h - d - c; - } - } - //this->vScroll.x = a; - this->vScroll.y = b + bbox.y; - this->vScroll.h = d; //@property -}; - -void ScrollingPane::_onSelect( int id ) -{ - if (isSet(SF_MultiSelect)) { - selected[id] = onSelect(id, !selected[id]); - } else { - // Change the selection, if the user wants it - // @note: There's currently no way to clear a selection - bool doSelect = onSelect(id, true); - if (id != selectedId && doSelect) { - onSelect(selectedId, false); - selectedId = id; - } - } -} - -void ScrollingPane::updateScrollFade( ScrollBar& sb ) { - if (sb.fading == 1 && ((sb.alpha += 0.33f) >= 1)) { - sb.alpha = 1; - sb.fading = -1; - } - if (sb.fading == 0 && ((sb.alpha -= 0.10f) <= 0)) { - sb.alpha = 0; - sb.fading = -1; - } -} - -void ScrollingPane::setSelected( int id, bool selected ) -{ - if (isSet(SF_MultiSelect)) - this->selected[id] = selected; - else { - if (selected) selectedId = selected? id : -1; - else if (id == selectedId) - selectedId = -1; - } -} - -void ScrollingPane::translate( float xo, float yo ) -{ - bbox.x += (int)xo; - bbox.y += (int)yo; - area._x0 += xo; - area._x1 += xo; - area._y0 += yo; - area._y1 += yo; - bboxArea._x0 += xo; - bboxArea._x1 += xo; - bboxArea._y0 += yo; - bboxArea._y1 += yo; - hScroll.x += xo; - hScroll.y += yo; - vScroll.x += xo; - vScroll.y += yo; -} - -bool ScrollingPane::queryHoldTime(int* gridItem, int* heldMs) { - *gridItem = -1; - *heldMs = -1; - - if (!dragging && highlightStarted >= 0) { - GridItem item = getItemForPos(_lx, _ly, true); - if (item.id == highlightItem.id) { - *gridItem = highlightItem.id; - *heldMs = getTimeMs() - highlightStarted; - return true; - } else { - highlightStarted = -1; - } - } - - return false; -} +#include "ScrollingPane.hpp" +#include "client/renderer/gles.hpp" +#include "client/gui/Gui.hpp" +#include "util/Mth.hpp" +#include "SharedConstants.hpp" + +#define STR(x) (x.toString().c_str()) + +static const float kPenetrationDeceleration = 0.03f; +static const float kPenetrationAcceleration = 0.08f; +static const float kMaxTrackingTime = 100.0f; +static const float kAcceleration = 15; +static const float kMinVelocityForDecelerationWithPaging = 4 / 3.0f; +static const float kMinVelocityForDeceleration = 1 / 3.0f; +static const float kDesiredAnimationFrameRate = 1000.0f / 60; +static const float kDecelerationFrictionFactor = 0.95f; +static const float kMinimumVelocityToHideScrollIndicators = 0.05f; +static const float kMinimumVelocity = 0.01f; +static const float kMinimumTrackingForDrag = 5; +static const float kMinIndicatorLength = 34.0f / 3; +static const float PKScrollIndicatorEndSize = 3; +static const float PKScrollIndicatorThickness = 7.0f /3; +static const float kWheelOverscrollMax = 80.0f; +static const float kWheelOverscrollDamping = 0.6f; +static const float kWheelOverscrollRestoreAlpha = 0.18f; + +ScrollingPane::ScrollingPane( + int optionFlags, + const IntRectangle& boundingBox, + const IntRectangle& itemRect, + int columns, + int numItems, + float screenScale /* = 1.0f */, + const IntRectangle& itemBoundingRect /*= IntRectangle(0,0,0,0)*/ ) +: flags(optionFlags), + bbox(boundingBox), + size(boundingBox), + area((float)bbox.x, (float)bbox.y, (float)(bbox.x + bbox.w), (float)(bbox.y + bbox.h)), + bboxArea(area), + itemRect(itemRect), + numItems(numItems), + screenScale(screenScale), + invScreenScale(1.0f / screenScale), + //hasItemBounding(), + px(0), py(0), fpx(0), fpy(0), + dx(0), dy(0), + dragState(-1), + dragLastDeltaTimeStamp(-1.0f), + friction(0.95f), + highlightTimer(-1), + highlightStarted(-1), + selectedId(-1), + decelerating(false), + tracking(false), + dragging(false), + pagingEnabled(false), + _scrollEnabled(true), + _timer(60), + _doStepTimer(false), + _wasDown(false),//Mouse::isButtonDown(MouseAction::ACTION_LEFT)), + _lx(-9999), _ly(-9999) +{ + if (itemBoundingRect.w > 0) + itemBbox = itemBoundingRect; + else + itemBbox = itemRect; + + this->columns = (columns>0)? columns : bbox.w / itemBbox.w; + + if (this->columns <= 0) { + LOGW("Columns are 0! Area width is smaller than item width. Setting columns to 1.\n"); + this->columns = 1; + } + //LOGI("%d, %d :: %d\n", bbox.w, itemBbox.w, this->columns); + + rows = 1 + (numItems-1) / this->columns; + + /* + if (columns * itemBbox.w <= bbox.w) flags |= SF_LockX; + if (rows * itemBbox.h <= bbox.h) flags |= SF_LockY; + */ + + // initialize content bounds immediately + adjustContentSize(); + minPoint.set((float)(this->size.w - this->adjustedContentSize.w), (float)(this->size.h - this->adjustedContentSize.h), 0); + this->snapContentOffsetToBounds(false); + + + dragDeltas.reserve(128); + + te_moved = 0; + te_ended = 1; + + selected = new bool[numItems]; + for (int i = 0; i < numItems; ++i) + selected[i] = false; + + // Setup the scroll bars + vScroll.w = vScroll.h = PKScrollIndicatorThickness; + hScroll.w = hScroll.h = PKScrollIndicatorThickness; + vScroll.x = bbox.x + bbox.w - vScroll.w; + vScroll.y = 0; + hScroll.x = 0; + hScroll.y = bbox.y + bbox.h - hScroll.h; + +// vScroll.alpha +// vScroll.fading = hScroll.fading = -1; +} + +ScrollingPane::~ScrollingPane() { + delete[] selected; +} + +//void ScrollingPane::init(Minecraft* mc, int width, int height) { +// this->mc = mc; +// this->width = width; +// this->height = height; +//} + +void ScrollingPane::tick() { + + if (isSet(SF_ShowScrollbar)) { + updateScrollFade(vScroll); + updateScrollFade(hScroll); + } + + if (isNotSet(SF_HardLimits) && !Mouse::isButtonDown(MouseAction::ACTION_LEFT) && !dragging && !tracking && !decelerating) { + float targetX = _contentOffset.x; + float targetY = _contentOffset.y; + bool corrected = false; + + if (targetX > 0.0f) { + targetX = Mth::lerp(targetX, 0.0f, kWheelOverscrollRestoreAlpha); + corrected = true; + } else if (targetX < minPoint.x) { + targetX = Mth::lerp(targetX, minPoint.x, kWheelOverscrollRestoreAlpha); + corrected = true; + } + + if (targetY > 0.0f) { + targetY = Mth::lerp(targetY, 0.0f, kWheelOverscrollRestoreAlpha); + corrected = true; + } else if (targetY < minPoint.y) { + targetY = Mth::lerp(targetY, minPoint.y, kWheelOverscrollRestoreAlpha); + corrected = true; + } + + if (corrected) { + if (Mth::abs(targetX - _contentOffset.x) < 0.25f) targetX = (targetX > 0.0f ? 0.0f : (targetX < minPoint.x ? minPoint.x : targetX)); + if (Mth::abs(targetY - _contentOffset.y) < 0.25f) targetY = (targetY > 0.0f ? 0.0f : (targetY < minPoint.y ? minPoint.y : targetY)); + setContentOffset(Vec3(targetX, targetY, 0)); + } + } +} + +bool ScrollingPane::getGridItemFor_slow(int itemIndex, GridItem& out) { + GridItem nw = getItemForPos(0, 0, false); + GridItem se = getItemForPos((float)bbox.w - 1, (float)bbox.h - 1, false); + const float bxx = bbox.x - (fpx /*+ dx*alpha*/) + (nw.xf - nw.x); + const float byy = bbox.y - (fpy /*+ dy*alpha*/) + (nw.yf - nw.y); + + int y = itemIndex / columns; + int x = itemIndex - (y * columns); + + out.id = itemIndex; + out.xf = bxx + x * itemBbox.w; + out.yf = byy + y * itemBbox.h; + out.x = x; + out.y = y; + + return x >= nw.x && x <= se.x + && y >= nw.y && y <= se.y; +} + + +void ScrollingPane::render( int xm, int ym, float alpha ) { + // Handle user interaction first + handleUserInput(); + + _timer.advanceTime(); + + if (_doStepTimer && !te_moved) { + for (int i = 0; i < _timer.ticks; ++i) + stepThroughDecelerationAnimation(false); + this->lastFrame = getTimeMs(); + } + + // Render + //if (isSet(SF_Scissor)) { + // glEnable2(GL_SCISSOR_TEST); + // GLuint x = (GLuint)(screenScale * bbox.x); + // GLuint y = 480 - (GLuint)(screenScale * (bbox.y + bbox.h)); + // GLuint w = (GLuint)(screenScale * bbox.w); + // GLuint h = (GLuint)(screenScale * bbox.h); + // glScissor(x, y, w, h); + // LOGI("x, y, w, h: %d, %d, %d, %d\n", x, y, w, h); + //} + + std::vector itemsToRender; + GridItem nw = getItemForPos(0, 0, false); + GridItem se = getItemForPos((float)bbox.w - 1, (float)bbox.h - 1, false); + + //LOGI("getItem: %d, %d - %d, %d\n", nw.x, nw.y, se.x, se.y); + + const float bxx = bbox.x - (fpx /*+ dx*alpha*/) + (nw.xf - nw.x); + const float byy = bbox.y - (fpy /*+ dy*alpha*/) + (nw.yf - nw.y); + for (int y = nw.y; y <= se.y; ++y) + for (int x = nw.x; x <= se.x; ++x) { + int id = y * columns + x; + if (y <0 || id < 0 || id >= numItems) continue; // @todo: break rather + if (isNotSet(SF_WrapX) && (x < 0 || x >= columns)) continue; // @todo: break rather + GridItem item; //@todo: v- Does not support SF_Wrapping + item.id = id; + item.xf = bxx + x * itemBbox.w; + item.yf = byy + y * itemBbox.h; + item.x = (int)item.xf; + item.y = (int)item.yf; + //LOGI("i: %d (%.1f, %.1f)\t", id, item.xf, item.yf); + if (isSet(SF_MultiSelect)) item.selected = selected[id]; + else item.selected = (id == selectedId); + + itemsToRender.push_back(item); + } + renderBatch(itemsToRender, alpha); + + //if (isSet(SF_Scissor)) + // glDisable2(GL_SCISSOR_TEST); +} + +void ScrollingPane::renderBatch(std::vector& items, float alpha) { + for (unsigned int i = 0; i < items.size(); ++i) + renderItem(items[i], alpha); +} + +void ScrollingPane::renderItem(GridItem& item, float alpha) { +} + +ScrollingPane::GridItem ScrollingPane::getItemForPos( float x, float y, bool isScreenPos ) { + // Screen relative pos (rather than ScrollingPane relative pos) + if (isScreenPos) { + x -= bbox.x; + y -= bbox.y; + } + + // Add the scrolled offset + x += fpx; + y += fpy; + + // Does the grid SF_Wrap around? + if (isSet(SF_WrapX)) x = fmod(x, (float)(itemBbox.w * columns)); + if (isSet(SF_WrapY)) y = fmod(y, (float)(itemBbox.h * rows)); + + GridItem out; + out.xf = x / itemBbox.w; + out.yf = y / itemBbox.h; + out.x = (int) out.xf; + out.y = (int) out.yf; + out.id = out.y * columns + out.x; + return out; +} + +void ScrollingPane::addDeltaPos(float x, float y, float dt, int a) { + if (dt <= 0) + return; + + Vec3 delta = (dragLastPos - Vec3(x, y, 0)) * (1.0f / dt); + dragDeltas.push_back(delta.x); + dragDeltas.push_back(delta.y); + dragLastPos.set(x, y, 0); + dragLastDeltaTimeStamp += dt; // @attn @fix: This relies on user to be correct + //LOGI(">> delta %d: %s\n", a, STR(delta)); +} + +static const int PKTableViewMinTouchDurationForCellSelection = 150; + +void ScrollingPane::handleUserInput() { + + bool isDown = Mouse::isButtonDown(MouseAction::ACTION_LEFT); + float x = Mouse::getX() * invScreenScale; + float y = Mouse::getY() * invScreenScale; + int t = getTimeMs(); + bool isInside = area.isInside(x, y); + //LOGI("inside? %d\n", isInside); + + bool moved = (x != _lx || y != _ly); + + _lx = x; + _ly = y; + + if (te_ended > 0 && _wasDown && !isDown) + touchesEnded(x, y, t); + else if (isDown && !_wasDown && isInside) + touchesBegan(x, y, t); + else if (te_moved > 0 && moved && isDown) + touchesMoved(x, y, t); + + if (highlightTimer >= 0 && isNotSet(SF_NoHoldSelect)) { + if (getTimeMs() - highlightTimer >= PKTableViewMinTouchDurationForCellSelection) + onHoldItem(); + } + + _wasDown = isDown; +} + +Vec3& ScrollingPane::contentOffset() { + return _contentOffset; +} + +void ScrollingPane::beginTracking(float x, float y, int t) { //@param 1: MouseEvent a + if (this->tracking) { + return; + } + //a.preventDefault(); + this->stopDecelerationAnimation(); + //this->hostingLayer.style.webkitTransitionDuration = 0; + this->adjustContentSize(); //@todo @? + this->minPoint.set((float)(this->size.w - this->adjustedContentSize.w), (float)(this->size.h - this->adjustedContentSize.h), 0); //@todo + this->snapContentOffsetToBounds(false); + this->startPosition = this->_contentOffset; + this->startTouchPosition.set(x, y, 0); + this->startTime = (float)t; + this->startTimePosition = this->contentOffset(); + this->tracking = true; + this->dragging = false; + this->touchesHaveMoved = false; + //window.addEventListener(PKMoveEvent, this, true); //@todo + //window.addEventListener(PKEndEvent, this, true); + //window.addEventListener("touchcancel", this, true); + //window.addEventListener(PKEndEvent, this, false) +}; + +void ScrollingPane::touchesBegan(float x, float y, int t) { //@param 1: MouseEvent a + if (!this->_scrollEnabled) { + return; + } + + te_ended = 1; + //if (a.eventPhase == Event.CAPTURING_PHASE) { + // if (a._manufactured) { + // return + // } + //this->highlightItem = getItemForPos(x, y, true); + // if (this.delaysContentTouches) { + // a.stopPropagation(); + // this.callMethodNameAfterDelay("beginTouchesInContent", kContentTouchesDelay, a); + this->beginTracking(x, y, t); + // } + //} else { + // this.beginTracking(a) + //} + te_moved = 2; + + GridItem gi = getItemForPos(x, y, true); + if (gi.id >= 0 && gi.id < numItems) { + //LOGI("Pressed down at %d (%d, %d)\n", gi.id, gi.x, gi.y); + highlightItem.id = bboxArea.isInside(x, y)? gi.id : -1; + highlightStarted = highlightTimer = bboxArea.isInside(x, y)? getTimeMs() : -1; + } else { + highlightItem.id = -1; + highlightStarted = highlightTimer = -1; + } +} + +void ScrollingPane::touchesMoved(float x, float y, int t) +{ + this->touchesHaveMoved = true; + //this->callSuper(d); + Vec3 e(x, y, 0); + float b = e.x - this->startTouchPosition.x; + float c = e.y - this->startTouchPosition.y; + if (!this->dragging) { + if ((Mth::abs(b) >= kMinimumTrackingForDrag && isNotSet(SF_LockX)) || (Mth::abs(c) >= kMinimumTrackingForDrag && isNotSet(SF_LockY))) { + willBeginDragging(); + this->dragging = true; + this->firstDrag = true; + + if (isSet(SF_ShowScrollbar)) { + if (isNotSet(SF_LockX) && (this->adjustedContentSize.w > this->size.w)) + //this->hScroll.visible = true; + this->hScroll.fading = 1; + if (isNotSet(SF_LockY) && (this->adjustedContentSize.h > this->size.h)) + //this->vScroll.visible = true; + this->vScroll.fading = 1; + } + } + } + if (this->dragging) { + //d.stopPropagation(); + float f = isNotSet(SF_LockX) ? (this->startPosition.x + b) : this->_contentOffset.x; + float a = isNotSet(SF_LockY) ? (this->startPosition.y + c) : this->_contentOffset.y; + if (isNotSet(SF_HardLimits)) { + f -= ((f < this->minPoint.x) ? (f - this->minPoint.x) : ((f > 0) ? f : 0)) / 2; + a -= ((a < this->minPoint.y) ? (a - this->minPoint.y) : ((a > 0) ? a : 0)) / 2; + } else { + f = Mth::Min(Mth::Max(this->minPoint.x, f), 0.0f); + a = Mth::Min(Mth::Max(this->minPoint.y, a), 0.0f); + } + if (this->firstDrag) { + this->firstDrag = false; + this->startTouchPosition = e; + return; + } + this->setContentOffset(f, a); + this->lastEventTime = t;//d.timeStamp; + } +} + +void ScrollingPane::touchesEnded(float x, float y, int t) { + te_ended = 0; + highlightStarted = -1; + //te_moved = 0; + + //this.callSuper(a); + this->tracking = false; + if (this->dragging) { + this->dragging = false; + //a.stopPropagation(); + if (t - this->lastEventTime <= kMaxTrackingTime) { + this->_contentOffsetBeforeDeceleration = this->_contentOffset; + this->startDecelerationAnimation(false); + } + if (!this->decelerating) {} + //window.removeEventListener(PKEndEvent, this, false); + didEndDragging(); + } + if (!this->decelerating) { + if (fpy < 0 || fpy > bbox.h) { //@todo: for x as well (or rather, x^y) + this->_contentOffsetBeforeDeceleration = this->_contentOffset; + this->startDecelerationAnimation(true); + } else { + this->snapContentOffsetToBounds(true); //@fix + this->hideScrollIndicators(); + } + } + //if (a.eventPhase == Event.BUBBLING_PHASE) { //@? @todo + // window.removeEventListener(PKEndEvent, this, false); + + //// old and shaky, doesn't work good with Xperia Play (and presumably lots of others) + //if (!this->touchesHaveMoved && this->highlightItem.id >= 0) { + // _onSelect(this->highlightItem.id); + //} + if (Vec3(x, y, 0).distanceToSqr(startTouchPosition) <= 6.0f * 6.0f && this->highlightItem.id >= 0) { + _onSelect(this->highlightItem.id); + } + //} + te_moved = 0; +}; + + +void ScrollingPane::touchesCancelled(float x, float y, int a) { + touchesEnded(x, y, a); +} + +void ScrollingPane::startDecelerationAnimation( bool force ) +{ + Vec3 a(this->_contentOffset.x - this->startTimePosition.x, this->_contentOffset.y - this->startTimePosition.y, 0); + float b = (getTimeMs()/*event.timeStamp*/ - this->startTime) / kAcceleration; + //LOGI("starting deceleration! %s, %f\n", STR(a), b); + + this->decelerationVelocity = Vec3(a.x / b, a.y / b, 0); + this->minDecelerationPoint = this->minPoint; + this->maxDecelerationPoint = Vec3(0, 0, 0); + if (this->pagingEnabled) { + this->minDecelerationPoint.x = Mth::Max(this->minPoint.x, std::floor(this->_contentOffsetBeforeDeceleration.x / this->size.w) * this->size.w); + this->minDecelerationPoint.y = Mth::Max(this->minPoint.y, std::floor(this->_contentOffsetBeforeDeceleration.y / this->size.h) * this->size.h); + this->maxDecelerationPoint.x = Mth::Min(0.0f, std::ceil(this->_contentOffsetBeforeDeceleration.x / this->size.w) * this->size.w); + this->maxDecelerationPoint.y = Mth::Min(0.0f, std::ceil(this->_contentOffsetBeforeDeceleration.y / this->size.h) * this->size.h); + } + this->penetrationDeceleration = kPenetrationDeceleration; + this->penetrationAcceleration = kPenetrationAcceleration; + if (this->pagingEnabled) { + this->penetrationDeceleration *= 5; + } + float c = this->pagingEnabled ? kMinVelocityForDecelerationWithPaging : kMinVelocityForDeceleration; + if (force || (Mth::abs(this->decelerationVelocity.x) > c || Mth::abs(this->decelerationVelocity.y) > c)) { + this->decelerating = true; + //LOGI("accelerating True - A\n"); + _doStepTimer = true; + //this->decelerationTimer = this->callMethodNameAfterDelay("stepThroughDecelerationAnimation", kDesiredAnimationFrameRate); //@? + this->lastFrame = getTimeMs(); + willBeginDecelerating(); + } +} + +void ScrollingPane::hideScrollIndicators() { + //hScroll.visible = vScroll.visible = false; + hScroll.fading = vScroll.fading = 0; +} + + +void ScrollingPane::stopDecelerationAnimation() +{ + //LOGI("decelerating False - A\n"); + this->decelerating = false; + _doStepTimer = false; + //clearTimeout(this.decelerationTimer) //@? +} + +void ScrollingPane::stepThroughDecelerationAnimation(bool noAnimation) { + if (!this->decelerating) { + return; + } + int d = getTimeMs(); + int k = d - this->lastFrame; + + int l = noAnimation ? 0 : (int)(std::floor(0.5f + ((float)k / kDesiredAnimationFrameRate) - 1)); + //LOGI("k: %d, %d %d : %d\n", d, this->lastFrame, k, l); + for (int j = 0; j < l; j++) + this->stepThroughDecelerationAnimation(true); + + float g = this->contentOffset().x + this->decelerationVelocity.x; + float h = this->contentOffset().y + this->decelerationVelocity.y; + if (isSet(SF_HardLimits)) { + float a = Mth::Min(Mth::Max(this->minPoint.x, g), 0.0f); + if (a != g) { + g = a; + this->decelerationVelocity.x = 0; + } + float c = Mth::Min(Mth::Max(this->minPoint.y, h), 0.0f); + if (c != h) { + h = c; + this->decelerationVelocity.y = 0; + } + } + if (noAnimation) { + this->contentOffset().x = g; + this->contentOffset().y = h; + } else { + this->setContentOffset(g, h); + } + if (!this->pagingEnabled) { + this->decelerationVelocity.x *= kDecelerationFrictionFactor; + this->decelerationVelocity.y *= kDecelerationFrictionFactor; + } + float b = Mth::abs(this->decelerationVelocity.x); + float i = Mth::abs(this->decelerationVelocity.y); + if (!noAnimation && b <= kMinimumVelocityToHideScrollIndicators && i <= kMinimumVelocityToHideScrollIndicators) { + this->hideScrollIndicators(); + if (b <= kMinimumVelocity && i <= kMinimumVelocity) { + //LOGI("decelerating False - B\n"); + this->decelerating = false; + didEndDecelerating(); + return; + } + } + if (!noAnimation) { + //this->decelerationTimer = this->callMethodNameAfterDelay("stepThroughDecelerationAnimation", kDesiredAnimationFrameRate) + } + //if (noAnimation) doStepTimer = false; + + + if (isNotSet(SF_HardLimits)) { + Vec3 e; + if (g < this->minDecelerationPoint.x) { + e.x = this->minDecelerationPoint.x - g; + } else { + if (g > this->maxDecelerationPoint.x) { + e.x = this->maxDecelerationPoint.x - g; + } + } + if (h < this->minDecelerationPoint.y) { + e.y = this->minDecelerationPoint.y - h; + } else { + if (h > this->maxDecelerationPoint.y) { + e.y = this->maxDecelerationPoint.y - h; + } + } + if (e.x != 0) { + if (e.x * this->decelerationVelocity.x <= 0) { + this->decelerationVelocity.x += e.x * this->penetrationDeceleration; + } else { + this->decelerationVelocity.x = e.x * this->penetrationAcceleration; + } + } + if (e.y != 0) { + if (e.y * this->decelerationVelocity.y <= 0) { + this->decelerationVelocity.y += e.y * this->penetrationDeceleration; + } else { + this->decelerationVelocity.y = e.y * this->penetrationAcceleration; + } + } + } + if (!noAnimation) { + this->lastFrame = d; + } +} + +void ScrollingPane::scrollBy(float dx, float dy) { + // compute target content offset from wheel delta (in screen-space w/ opposite sign) + float targetX = _contentOffset.x - dx; + float targetY = _contentOffset.y - dy; + + if (isSet(SF_LockX)) targetX = _contentOffset.x; + if (isSet(SF_LockY)) targetY = _contentOffset.y; + + if (isSet(SF_HardLimits)) { + targetX = Mth::clamp(targetX, minPoint.x, 0.0f); + targetY = Mth::clamp(targetY, minPoint.y, 0.0f); + } else { + if (targetX > 0.0f) { + float overshoot = targetX; + overshoot = Mth::Min(overshoot, kWheelOverscrollMax); + targetX = overshoot * kWheelOverscrollDamping; + } else if (targetX < minPoint.x) { + float overshoot = targetX - minPoint.x; + overshoot = Mth::Max(overshoot, -kWheelOverscrollMax); + targetX = minPoint.x + overshoot * kWheelOverscrollDamping; + } + + if (targetY > 0.0f) { + float overshoot = targetY; + overshoot = Mth::Min(overshoot, kWheelOverscrollMax); + targetY = overshoot * kWheelOverscrollDamping; + } else if (targetY < minPoint.y) { + float overshoot = targetY - minPoint.y; + overshoot = Mth::Max(overshoot, -kWheelOverscrollMax); + targetY = minPoint.y + overshoot * kWheelOverscrollDamping; + } + } + + setContentOffset(Vec3(targetX, targetY, 0)); +} + +void ScrollingPane::setContentOffset(float x, float y) { + this->setContentOffsetWithAnimation(Vec3(x, y, 0), false); +} +void ScrollingPane::setContentOffset(Vec3 a) { + this->setContentOffsetWithAnimation(a, false); +}; + +void ScrollingPane::setContentOffsetWithAnimation(Vec3 b, bool doScroll) { + this->_contentOffset = b; + fpx = -this->_contentOffset.x; + fpy = -this->_contentOffset.y; + /* //@todo //@? + this->hostingLayer.style.webkitTransform = PKUtils.t(this->_contentOffset.x, this->_contentOffset.y); + if (a) { + this->scrollTransitionsNeedRemoval = true; + this->hostingLayer.style.webkitTransitionDuration = kPagingTransitionDuration + } else { + this->didScroll(false) + } + */ + if (!doScroll) { + // @todo: for scroll indicator //@? + if (isSet(SF_ShowScrollbar)) { + if (isNotSet(SF_LockX)) this->updateHorizontalScrollIndicator(); + if (isNotSet(SF_LockY)) this->updateVerticalScrollIndicator(); + } + } + //this->notifyPropertyChange("contentOffset") +} + +void ScrollingPane::snapContentOffsetToBounds(bool a) { + bool b = false; + Vec3 c; + if (this->pagingEnabled) { + c.x = std::floor(0.5f + this->_contentOffset.x / this->size.w) * this->size.w; + c.y = std::floor(0.5f + this->_contentOffset.y / this->size.h) * this->size.h; + b = true; + } else { + if (isNotSet(SF_HardLimits)) { + c.x = Mth::Min(Mth::Max(this->minPoint.x, this->_contentOffset.x), 0.0f); + c.y = Mth::Min(Mth::Max(this->minPoint.y, this->_contentOffset.y), 0.0f); + b = (c.x != this->_contentOffset.x || c.y != this->_contentOffset.y); + } + } + if (b) { + this->setContentOffsetWithAnimation(c, a); + } +} + +void ScrollingPane::adjustContentSize() +{ + this->adjustedContentSize.w = Mth::Max(itemBbox.w * columns, bbox.w); + this->adjustedContentSize.h = Mth::Max(itemBbox.h * rows, bbox.h); +} + +void ScrollingPane::onHoldItem() { + //LOGI("dragging, tracking %d, %d\n", !this->dragging, this->tracking); + int id = highlightItem.id; + if (id != -1 && !this->dragging && this->tracking) + _onSelect(id); + highlightTimer = -1; + //highlightItem.id = -1; +} + +bool ScrollingPane::onSelect( int gridId, bool selected ) +{ + return selected; +} + +void ScrollingPane::updateHorizontalScrollIndicator() +{ + float c = (isNotSet(SF_LockX) && isSet(SF_ShowScrollbar)) ? PKScrollIndicatorEndSize * 2 : 1; + float d = Mth::Max(kMinIndicatorLength, std::floor(0.5f + (this->size.w / this->adjustedContentSize.w) * (this->size.w - c))); + float a = (-this->_contentOffset.x / (this->adjustedContentSize.w - this->size.w)) * (this->size.w - c - d); + //float b = this->size.h - PKScrollIndicatorThickness - 1; + if (this->_contentOffset.x > 0) { + d = std::floor(0.5f + Mth::Max(d - this->_contentOffset.x, PKScrollIndicatorThickness)); + a = 1; + } else { + if (this->_contentOffset.x < -(this->adjustedContentSize.w - this->size.w)) { + d = std::floor(0.5f + Mth::Max(d + this->adjustedContentSize.w - this->size.w + this->contentOffset().x, PKScrollIndicatorThickness)); + a = this->size.w - d - c; + } + } + this->hScroll.x = a + bbox.x; + //this->hScroll.y = b; + this->hScroll.w = d; //@property +}; + + +void ScrollingPane::updateVerticalScrollIndicator() +{ + float c = (isNotSet(SF_LockY) && isSet(SF_ShowScrollbar)) ? PKScrollIndicatorEndSize * 2 : 1; + float d = Mth::Max(kMinIndicatorLength, std::floor(0.5f + (this->size.h / this->adjustedContentSize.h) * (this->size.h - c))); + //float a = this->size.w - PKScrollIndicatorThickness - 1; + float b = (-this->_contentOffset.y / (this->adjustedContentSize.h - this->size.h)) * (this->size.h - c - d); + if (this->_contentOffset.y > 0) { + d = std::floor(0.5f + Mth::Max(d - this->_contentOffset.y, PKScrollIndicatorThickness)); + b = 1; + } else { + if (this->_contentOffset.y < -(this->adjustedContentSize.h - this->size.h)) { + d = std::floor(0.5f + Mth::Max(d + this->adjustedContentSize.h - this->size.h + this->contentOffset().y, PKScrollIndicatorThickness)); + b = this->size.h - d - c; + } + } + //this->vScroll.x = a; + this->vScroll.y = b + bbox.y; + this->vScroll.h = d; //@property +}; + +void ScrollingPane::_onSelect( int id ) +{ + if (isSet(SF_MultiSelect)) { + selected[id] = onSelect(id, !selected[id]); + } else { + // Change the selection, if the user wants it + // @note: There's currently no way to clear a selection + bool doSelect = onSelect(id, true); + if (id != selectedId && doSelect) { + onSelect(selectedId, false); + selectedId = id; + } + } +} + +void ScrollingPane::updateScrollFade( ScrollBar& sb ) { + if (sb.fading == 1 && ((sb.alpha += 0.33f) >= 1)) { + sb.alpha = 1; + sb.fading = -1; + } + if (sb.fading == 0 && ((sb.alpha -= 0.10f) <= 0)) { + sb.alpha = 0; + sb.fading = -1; + } +} + +void ScrollingPane::setSelected( int id, bool selected ) +{ + if (isSet(SF_MultiSelect)) + this->selected[id] = selected; + else { + if (selected) selectedId = selected? id : -1; + else if (id == selectedId) + selectedId = -1; + } +} + +void ScrollingPane::translate( float xo, float yo ) +{ + bbox.x += (int)xo; + bbox.y += (int)yo; + area._x0 += xo; + area._x1 += xo; + area._y0 += yo; + area._y1 += yo; + bboxArea._x0 += xo; + bboxArea._x1 += xo; + bboxArea._y0 += yo; + bboxArea._y1 += yo; + hScroll.x += xo; + hScroll.y += yo; + vScroll.x += xo; + vScroll.y += yo; +} + +bool ScrollingPane::queryHoldTime(int* gridItem, int* heldMs) { + *gridItem = -1; + *heldMs = -1; + + if (!dragging && highlightStarted >= 0) { + GridItem item = getItemForPos(_lx, _ly, true); + if (item.id == highlightItem.id) { + *gridItem = highlightItem.id; + *heldMs = getTimeMs() - highlightStarted; + return true; + } else { + highlightStarted = -1; + } + } + + return false; +} diff --git a/src/client/gui/components/ScrollingPane.h b/src/client/gui/components/ScrollingPane.hpp similarity index 96% rename from src/client/gui/components/ScrollingPane.h rename to src/client/gui/components/ScrollingPane.hpp index a27af1c..9eada38 100755 --- a/src/client/gui/components/ScrollingPane.h +++ b/src/client/gui/components/ScrollingPane.hpp @@ -1,10 +1,10 @@ #pragma once -#include "../GuiComponent.h" -#include "ImageButton.h" -#include "../../player/input/touchscreen/TouchAreaModel.h" -#include "../../../world/phys/Vec3.h" -#include "../../Timer.h" +#include "client/gui/GuiComponent.hpp" +#include "ImageButton.hpp" +#include "client/player/input/touchscreen/TouchAreaModel.hpp" +#include "world/phys/Vec3.hpp" +#include "client/Timer.hpp" enum ScrollingPaneFlags { SF_LockX = 1 << 0, diff --git a/src/client/gui/components/Slider.cpp b/src/client/gui/components/Slider.cpp index 27a3b36..01fa0cc 100755 --- a/src/client/gui/components/Slider.cpp +++ b/src/client/gui/components/Slider.cpp @@ -1,94 +1,94 @@ -#include "Slider.h" -#include "../../Minecraft.h" -#include "../../renderer/Textures.h" -#include "../Screen.h" -#include "../../../locale/I18n.h" -#include "../../../util/Mth.h" -#include -#include - -Slider::Slider(OptionId optId) : m_mouseDownOnElement(false), m_optId(optId), m_numSteps(0) {} - -void Slider::render( Minecraft* minecraft, int xm, int ym ) { - int xSliderStart = x + 5; - int xSliderEnd = x + width - 5; - int ySliderStart = y + 6; - int ySliderEnd = y + 9; - int handleSizeX = 9; - int handleSizeY = 15; - int barWidth = xSliderEnd - xSliderStart; - //fill(x, y + 8, x + (int)(width * percentage), y + height, 0xffff00ff); - fill(xSliderStart, ySliderStart, xSliderEnd, ySliderEnd, 0xff606060); - - if (m_numSteps > 2) { - int stepDistance = barWidth / (m_numSteps-1); - for(int a = 0; a < m_numSteps; ++a) { - int renderSliderStepPosX = xSliderStart + a * stepDistance + 1; - fill(renderSliderStepPosX - 1, ySliderStart - 2, renderSliderStepPosX + 1, ySliderEnd + 2, 0xff606060); - } - } - - minecraft->textures->loadAndBindTexture("gui/touchgui.png"); - blit(xSliderStart + (int)(m_percentage * barWidth) - handleSizeX / 2, y, 226, 126, handleSizeX, handleSizeY, handleSizeX, handleSizeY); -} - -void Slider::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { - if(pointInside(x, y)) { - m_mouseDownOnElement = true; - } -} - -void Slider::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { - m_mouseDownOnElement = false; -} - -void Slider::tick(Minecraft* minecraft) { - if(minecraft->screen != NULL) { - int xm = Mouse::getX(); - int ym = Mouse::getY(); - - minecraft->screen->toGUICoordinate(xm, ym); - - if(m_mouseDownOnElement) { - m_percentage = float(xm - x) / float(width); - m_percentage = Mth::clamp(m_percentage, 0.0f, 1.0f); - } - } -} - -SliderFloat::SliderFloat(Minecraft* minecraft, OptionId option) -: Slider(option), m_option(dynamic_cast(minecraft->options.getOpt(option))) -{ - m_percentage = Mth::clamp((m_option->get() - m_option->getMin()) / (m_option->getMax() - m_option->getMin()), 0.f, 1.f); -} - -SliderInt::SliderInt(Minecraft* minecraft, OptionId option) -: Slider(option), m_option(dynamic_cast(minecraft->options.getOpt(option))) -{ - m_numSteps = m_option->getMax() - m_option->getMin() + 1; - m_percentage = float(m_option->get() - m_option->getMin()) / (m_numSteps-1); -} - -void SliderInt::render( Minecraft* minecraft, int xm, int ym ) { - Slider::render(minecraft, xm, ym); -} - -void SliderInt::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { - Slider::mouseReleased(minecraft, x, y, buttonNum); - - if (pointInside(x, y)) { - int curStep = int(m_percentage * (m_numSteps-1) + 0.5f); - curStep = Mth::clamp(curStep + m_option->getMin(), m_option->getMin(), m_option->getMax()); - m_percentage = float(curStep - m_option->getMin()) / (m_numSteps-1); - - minecraft->options.set(m_optId, curStep); - } -} - -void SliderFloat::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { - Slider::mouseReleased(minecraft, x, y, buttonNum); - - if (pointInside(x, y)) { - minecraft->options.set(m_optId, m_percentage * (m_option->getMax() - m_option->getMin()) + m_option->getMin()); - } +#include "Slider.hpp" +#include "client/Minecraft.hpp" +#include "client/renderer/Textures.hpp" +#include "client/gui/Screen.hpp" +#include "locale/I18n.hpp" +#include "util/Mth.hpp" +#include +#include + +Slider::Slider(OptionId optId) : m_mouseDownOnElement(false), m_optId(optId), m_numSteps(0) {} + +void Slider::render( Minecraft* minecraft, int xm, int ym ) { + int xSliderStart = x + 5; + int xSliderEnd = x + width - 5; + int ySliderStart = y + 6; + int ySliderEnd = y + 9; + int handleSizeX = 9; + int handleSizeY = 15; + int barWidth = xSliderEnd - xSliderStart; + //fill(x, y + 8, x + (int)(width * percentage), y + height, 0xffff00ff); + fill(xSliderStart, ySliderStart, xSliderEnd, ySliderEnd, 0xff606060); + + if (m_numSteps > 2) { + int stepDistance = barWidth / (m_numSteps-1); + for(int a = 0; a < m_numSteps; ++a) { + int renderSliderStepPosX = xSliderStart + a * stepDistance + 1; + fill(renderSliderStepPosX - 1, ySliderStart - 2, renderSliderStepPosX + 1, ySliderEnd + 2, 0xff606060); + } + } + + minecraft->textures->loadAndBindTexture("gui/touchgui.png"); + blit(xSliderStart + (int)(m_percentage * barWidth) - handleSizeX / 2, y, 226, 126, handleSizeX, handleSizeY, handleSizeX, handleSizeY); +} + +void Slider::mouseClicked( Minecraft* minecraft, int x, int y, int buttonNum ) { + if(pointInside(x, y)) { + m_mouseDownOnElement = true; + } +} + +void Slider::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { + m_mouseDownOnElement = false; +} + +void Slider::tick(Minecraft* minecraft) { + if(minecraft->screen != NULL) { + int xm = Mouse::getX(); + int ym = Mouse::getY(); + + minecraft->screen->toGUICoordinate(xm, ym); + + if(m_mouseDownOnElement) { + m_percentage = float(xm - x) / float(width); + m_percentage = Mth::clamp(m_percentage, 0.0f, 1.0f); + } + } +} + +SliderFloat::SliderFloat(Minecraft* minecraft, OptionId option) +: Slider(option), m_option(dynamic_cast(minecraft->options.getOpt(option))) +{ + m_percentage = Mth::clamp((m_option->get() - m_option->getMin()) / (m_option->getMax() - m_option->getMin()), 0.f, 1.f); +} + +SliderInt::SliderInt(Minecraft* minecraft, OptionId option) +: Slider(option), m_option(dynamic_cast(minecraft->options.getOpt(option))) +{ + m_numSteps = m_option->getMax() - m_option->getMin() + 1; + m_percentage = float(m_option->get() - m_option->getMin()) / (m_numSteps-1); +} + +void SliderInt::render( Minecraft* minecraft, int xm, int ym ) { + Slider::render(minecraft, xm, ym); +} + +void SliderInt::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { + Slider::mouseReleased(minecraft, x, y, buttonNum); + + if (pointInside(x, y)) { + int curStep = int(m_percentage * (m_numSteps-1) + 0.5f); + curStep = Mth::clamp(curStep + m_option->getMin(), m_option->getMin(), m_option->getMax()); + m_percentage = float(curStep - m_option->getMin()) / (m_numSteps-1); + + minecraft->options.set(m_optId, curStep); + } +} + +void SliderFloat::mouseReleased( Minecraft* minecraft, int x, int y, int buttonNum ) { + Slider::mouseReleased(minecraft, x, y, buttonNum); + + if (pointInside(x, y)) { + minecraft->options.set(m_optId, m_percentage * (m_option->getMax() - m_option->getMin()) + m_option->getMin()); + } } \ No newline at end of file diff --git a/src/client/gui/components/Slider.h b/src/client/gui/components/Slider.hpp similarity index 91% rename from src/client/gui/components/Slider.h rename to src/client/gui/components/Slider.hpp index ccccb26..def696a 100755 --- a/src/client/gui/components/Slider.h +++ b/src/client/gui/components/Slider.hpp @@ -1,8 +1,8 @@ #pragma once -#include "GuiElement.h" -#include "../../../client/Options.h" -#include +#include "GuiElement.hpp" +#include "client/Options.hpp" +#include class Slider : public GuiElement { typedef GuiElement super; diff --git a/src/client/gui/components/TextBox.cpp b/src/client/gui/components/TextBox.cpp index 16bf8a6..6a506ca 100755 --- a/src/client/gui/components/TextBox.cpp +++ b/src/client/gui/components/TextBox.cpp @@ -1,102 +1,102 @@ -#include "TextBox.h" -#include "../Gui.h" -#include "../../Minecraft.h" -#include "../../../AppPlatform.h" -#include "../../../platform/input/Mouse.h" - -// delegate constructors -TextBox::TextBox(int id, const std::string& msg) - : TextBox(id, 0, 0, msg) -{ -} - -TextBox::TextBox(int id, int x, int y, const std::string& msg) - : TextBox(id, x, y, 24, Font::DefaultLineHeight + 4, msg) -{ -} - -TextBox::TextBox(int id, int x, int y, int w, int h, const std::string& msg) - : GuiElement(true, true, x, y, w, h), - id(id), hint(msg), focused(false), blink(false), blinkTicks(0) -{ -} - -void TextBox::setFocus(Minecraft* minecraft) { - if (!focused) { - minecraft->platform()->showKeyboard(); - focused = true; - blinkTicks = 0; - blink = false; - } -} - -bool TextBox::loseFocus(Minecraft* minecraft) { - if (focused) { - minecraft->platform()->hideKeyboard(); - focused = false; - return true; - } - return false; -} - -void TextBox::mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) { - if (buttonNum == MouseAction::ACTION_LEFT) { - if (pointInside(x, y)) { - setFocus(minecraft); - } else { - loseFocus(minecraft); - } - } -} - -void TextBox::charPressed(Minecraft* minecraft, char c) { - if (focused && c >= 32 && c < 127 && (int)text.size() < 256) { - text.push_back(c); - } -} - -void TextBox::keyPressed(Minecraft* minecraft, int key) { - if (focused && key == Keyboard::KEY_BACKSPACE && !text.empty()) { - text.pop_back(); - } -} - -void TextBox::tick(Minecraft* minecraft) { - blinkTicks++; - if (blinkTicks >= 5) { - blink = !blink; - blinkTicks = 0; - } -} - -void TextBox::render(Minecraft* minecraft, int xm, int ym) { - // textbox like in beta 1.7.3 - // change appearance when focused so the user can tell it's active - // active background darker gray with a subtle border - uint32_t bgColor = focused ? 0xffa0a0a0 : 0xffa0a0a0; - uint32_t borderColor = focused ? 0xff000000 : 0xff000000; - fill(x, y, x + width, y + height, bgColor); - fill(x + 1, y + 1, x + width - 1, y + height - 1, borderColor); - - glEnable2(GL_SCISSOR_TEST); - glScissor( - Gui::GuiScale * (x + 2), - minecraft->height - Gui::GuiScale * (y + height - 2), - Gui::GuiScale * (width - 2), - Gui::GuiScale * (height - 2) - ); - - int _y = y + (height - Font::DefaultLineHeight) / 2; - - if (text.empty() && !focused) { - drawString(minecraft->font, hint, x + 2, _y, 0xff5e5e5e); - } - - if (focused && blink) text.push_back('_'); - - drawString(minecraft->font, text, x + 2, _y, 0xffffffff); - - if (focused && blink) text.pop_back(); - - glDisable2(GL_SCISSOR_TEST); -} +#include "TextBox.hpp" +#include "client/gui/Gui.hpp" +#include "client/Minecraft.hpp" +#include "AppPlatform.hpp" +#include "platform/input/Mouse.hpp" + +// delegate constructors +TextBox::TextBox(int id, const std::string& msg) + : TextBox(id, 0, 0, msg) +{ +} + +TextBox::TextBox(int id, int x, int y, const std::string& msg) + : TextBox(id, x, y, 24, Font::DefaultLineHeight + 4, msg) +{ +} + +TextBox::TextBox(int id, int x, int y, int w, int h, const std::string& msg) + : GuiElement(true, true, x, y, w, h), + id(id), hint(msg), focused(false), blink(false), blinkTicks(0) +{ +} + +void TextBox::setFocus(Minecraft* minecraft) { + if (!focused) { + minecraft->platform()->showKeyboard(); + focused = true; + blinkTicks = 0; + blink = false; + } +} + +bool TextBox::loseFocus(Minecraft* minecraft) { + if (focused) { + minecraft->platform()->hideKeyboard(); + focused = false; + return true; + } + return false; +} + +void TextBox::mouseClicked(Minecraft* minecraft, int x, int y, int buttonNum) { + if (buttonNum == MouseAction::ACTION_LEFT) { + if (pointInside(x, y)) { + setFocus(minecraft); + } else { + loseFocus(minecraft); + } + } +} + +void TextBox::charPressed(Minecraft* minecraft, char c) { + if (focused && c >= 32 && c < 127 && (int)text.size() < 256) { + text.push_back(c); + } +} + +void TextBox::keyPressed(Minecraft* minecraft, int key) { + if (focused && key == Keyboard::KEY_BACKSPACE && !text.empty()) { + text.pop_back(); + } +} + +void TextBox::tick(Minecraft* minecraft) { + blinkTicks++; + if (blinkTicks >= 5) { + blink = !blink; + blinkTicks = 0; + } +} + +void TextBox::render(Minecraft* minecraft, int xm, int ym) { + // textbox like in beta 1.7.3 + // change appearance when focused so the user can tell it's active + // active background darker gray with a subtle border + uint32_t bgColor = focused ? 0xffa0a0a0 : 0xffa0a0a0; + uint32_t borderColor = focused ? 0xff000000 : 0xff000000; + fill(x, y, x + width, y + height, bgColor); + fill(x + 1, y + 1, x + width - 1, y + height - 1, borderColor); + + glEnable2(GL_SCISSOR_TEST); + glScissor( + Gui::GuiScale * (x + 2), + minecraft->height - Gui::GuiScale * (y + height - 2), + Gui::GuiScale * (width - 2), + Gui::GuiScale * (height - 2) + ); + + int _y = y + (height - Font::DefaultLineHeight) / 2; + + if (text.empty() && !focused) { + drawString(minecraft->font, hint, x + 2, _y, 0xff5e5e5e); + } + + if (focused && blink) text.push_back('_'); + + drawString(minecraft->font, text, x + 2, _y, 0xffffffff); + + if (focused && blink) text.pop_back(); + + glDisable2(GL_SCISSOR_TEST); +} diff --git a/src/client/gui/components/TextBox.h b/src/client/gui/components/TextBox.hpp similarity index 85% rename from src/client/gui/components/TextBox.h rename to src/client/gui/components/TextBox.hpp index 6f306a6..18f9324 100755 --- a/src/client/gui/components/TextBox.h +++ b/src/client/gui/components/TextBox.hpp @@ -3,10 +3,10 @@ //package net.minecraft.client.gui; #include -#include "GuiElement.h" -#include "../../Options.h" -#include "../../../platform/input/Mouse.h" -#include "../../../platform/input/Keyboard.h" +#include "GuiElement.hpp" +#include "client/Options.hpp" +#include "platform/input/Mouse.hpp" +#include "platform/input/Keyboard.hpp" class Font; class Minecraft; diff --git a/src/client/gui/components/TextOption.cpp b/src/client/gui/components/TextOption.cpp index 83b8535..d635abb 100644 --- a/src/client/gui/components/TextOption.cpp +++ b/src/client/gui/components/TextOption.cpp @@ -1,5 +1,5 @@ -#include "TextOption.h" -#include +#include "TextOption.hpp" +#include TextOption::TextOption(Minecraft* minecraft, OptionId optId) : TextBox((int)optId, minecraft->options.getOpt(optId)->getStringId()) diff --git a/src/client/gui/components/TextOption.h b/src/client/gui/components/TextOption.hpp similarity index 75% rename from src/client/gui/components/TextOption.h rename to src/client/gui/components/TextOption.hpp index 89c545c..30c0a04 100644 --- a/src/client/gui/components/TextOption.h +++ b/src/client/gui/components/TextOption.hpp @@ -1,6 +1,6 @@ #pragma once -#include "TextBox.h" -#include +#include "TextBox.hpp" +#include class TextOption : public TextBox { public: diff --git a/src/client/gui/screens/ArmorScreen.cpp b/src/client/gui/screens/ArmorScreen.cpp index 593a892..1aed23a 100755 --- a/src/client/gui/screens/ArmorScreen.cpp +++ b/src/client/gui/screens/ArmorScreen.cpp @@ -1,370 +1,370 @@ -#include "ArmorScreen.h" -#include "../Screen.h" -#include "../components/NinePatch.h" -#include "../../Minecraft.h" -#include "../../player/LocalPlayer.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/entity/ItemRenderer.h" -#include "../../../world/item/Item.h" -#include "../../../world/item/ItemCategory.h" -#include "../../../world/entity/player/Inventory.h" -#include "../../../world/entity/item/ItemEntity.h" -#include "../../../world/level/Level.h" -#include "../../../network/RakNetInstance.h" -#include "../../renderer/entity/EntityRenderDispatcher.h" -#include "../../../world/item/ArmorItem.h" - -static void setIfNotSet(bool& ref, bool condition) { - ref = (ref || condition); -} - -const int descFrameWidth = 100; - -const int rgbActive = 0xfff0f0f0; -const int rgbInactive = 0xc0635558; -const int rgbInactiveShadow = 0xc0aaaaaa; - -#ifdef __APPLE__ - static const float BorderPixels = 4; - #ifdef DEMO_MODE - static const float BlockPixels = 22; - #else - static const float BlockPixels = 22; - #endif -#else - static const float BorderPixels = 4; - static const float BlockPixels = 24; -#endif -static const int ItemSize = (int)(BlockPixels + 2*BorderPixels); - -static const int Bx = 10; // Border Frame width -static const int By = 6; // Border Frame height - - -ArmorScreen::ArmorScreen(): - inventoryPane(NULL), - btnArmor0(0), - btnArmor1(1), - btnArmor2(2), - btnArmor3(3), - btnClose(4, ""), - bHeader (5, "Armor"), - guiBackground(NULL), - guiSlot(NULL), - guiPaneFrame(NULL), - guiPlayerBg(NULL), - doRecreatePane(false), - descWidth(90) - //guiSlotItem(NULL), - //guiSlotItemSelected(NULL) -{ - //LOGI("Creating ArmorScreen with %p, %d\n", furnace, furnace->runningId); -} - -ArmorScreen::~ArmorScreen() { - delete inventoryPane; - - delete guiBackground; - delete guiSlot; - delete guiPaneFrame; - delete guiPlayerBg; -} - -void ArmorScreen::init() { - super::init(); - - player = minecraft->player; - - ImageDef def; - def.name = "gui/spritesheet.png"; - def.x = 0; - def.y = 1; - def.width = def.height = 18; - def.setSrc(IntRectangle(60, 0, 18, 18)); - btnClose.setImageDef(def, true); - btnClose.scaleWhenPressed = false; - - buttons.push_back(&bHeader); - buttons.push_back(&btnClose); - - armorButtons[0] = &btnArmor0; - armorButtons[1] = &btnArmor1; - armorButtons[2] = &btnArmor2; - armorButtons[3] = &btnArmor3; - for (int i = 0; i < NUM_ARMORBUTTONS; ++i) - buttons.push_back(armorButtons[i]); - - // GUI - nine patches - NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); - - guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); - guiSlot = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 3, 3, 20, 20); - guiPaneFrame = builder.createSymmetrical(IntRectangle(28, 42, 4, 4), 1, 1)->setExcluded(1 << 4); - guiPlayerBg = builder.createSymmetrical(IntRectangle(0, 20, 8, 8), 3, 3); - - updateItems(); -} - -void ArmorScreen::setupPositions() { - // Left - Categories - bHeader.x = bHeader.y = 0; - bHeader.width = width;// - bDone.w; - - btnClose.width = btnClose.height = 19; - btnClose.x = width - btnClose.width; - btnClose.y = 0; - - // Inventory pane - const int maxWidth = (int)(width/1.8f) - Bx - Bx; - const int InventoryColumns = maxWidth / ItemSize; - const int realWidth = InventoryColumns * ItemSize; - const int paneWidth = realWidth + Bx + Bx; - const int realBx = (paneWidth - realWidth) / 2; - - inventoryPaneRect = IntRectangle(realBx, -#ifdef __APPLE__ - 26 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-28); -#else - 26 + By, realWidth, height-By-By-28); -#endif - - for (int i = 0; i < NUM_ARMORBUTTONS; ++i) { - Button& b = *armorButtons[i]; - b.x = paneWidth; - b.y = inventoryPaneRect.y + 24 * i; - b.width = 20; - b.height = 20; - } - - guiPlayerBgRect.y = inventoryPaneRect.y; - int xx = armorButtons[0]->x + armorButtons[0]->width; - int xw = width - xx; - guiPlayerBgRect.x = xx + xw / 10; - guiPlayerBgRect.w = xw - (xw / 10) * 2; - guiPlayerBgRect.h = inventoryPaneRect.h; - - guiPaneFrame->setSize((float)inventoryPaneRect.w + 2, (float)inventoryPaneRect.h + 2); - guiPlayerBg->setSize((float)guiPlayerBgRect.w, (float)guiPlayerBgRect.h); - guiBackground->setSize((float)width, (float)height); - - updateItems(); - setupInventoryPane(); -} - -void ArmorScreen::tick() { - if (inventoryPane) - inventoryPane->tick(); - - if (doRecreatePane) { - updateItems(); - setupInventoryPane(); - doRecreatePane = false; - } -} - -void ArmorScreen::handleRenderPane(Touch::InventoryPane* pane, Tesselator& t, int xm, int ym, float a) { - if (pane) { - pane->render(xm, ym, a); - guiPaneFrame->draw(t, (float)(pane->rect.x - 1), (float)(pane->rect.y - 1)); - } -} - -void ArmorScreen::render(int xm, int ym, float a) { - //renderBackground(); - - Tesselator& t = Tesselator::instance; - - t.addOffset(0, 0, -500); - guiBackground->draw(t, 0, 0); - t.addOffset(0, 0, 500); - glEnable2(GL_ALPHA_TEST); - - // Buttons (Left side + crafting) - super::render(xm, ym, a); - - handleRenderPane(inventoryPane, t, xm, ym, a); - - t.colorABGR(0xffffffff); - glColor4f2(1, 1, 1, 1); - - t.addOffset(0, 0, -490); - guiPlayerBg->draw(t, (float)guiPlayerBgRect.x, (float)guiPlayerBgRect.y); - t.addOffset(0, 0, 490); - renderPlayer((float)(guiPlayerBgRect.x + guiPlayerBgRect.w / 2), 0.85f * height); - - for (int i = 0; i < NUM_ARMORBUTTONS; ++i) { - drawSlotItemAt(t, i, player->getArmor(i), armorButtons[i]->x, armorButtons[i]->y); - } - glDisable2(GL_ALPHA_TEST); -} - -void ArmorScreen::buttonClicked(Button* button) { - if (button == &btnClose) { - minecraft->setScreen(NULL); - } - - if (button->id >= 0 && button->id <= 3) { - takeAndClearSlot(button->id); - } -} - -bool ArmorScreen::addItem(const Touch::InventoryPane* forPane, int itemIndex) { - const ItemInstance* instance = armorItems[itemIndex]; - if (!ItemInstance::isArmorItem(instance)) - return false; - - ArmorItem* item = (ArmorItem*) instance->getItem(); - ItemInstance* old = player->getArmor(item->slot); - ItemInstance oldArmor; - - if (ItemInstance::isArmorItem(old)) { - oldArmor = *old; - } - - player->setArmor(item->slot, instance); - - player->inventory->removeItem(instance); - //@attn: this is hugely important - armorItems[itemIndex] = NULL; - - if (!oldArmor.isNull()) { - if (!player->inventory->add(&oldArmor)) { - player->drop(new ItemInstance(oldArmor), false); - } - } - - doRecreatePane = true; - return true; -} - -bool ArmorScreen::isAllowed( int slot ) { - return true; -} - -bool ArmorScreen::renderGameBehind() { - return false; -} - -std::vector ArmorScreen::getItems( const Touch::InventoryPane* forPane ) { - return armorItems; -} - -void ArmorScreen::updateItems() { - armorItems.clear(); - - for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) { - ItemInstance* item = minecraft->player->inventory->getItem(i); - if (ItemInstance::isArmorItem(item)) - armorItems.push_back(item); - } -} - -bool ArmorScreen::canMoveToSlot(int slot, const ItemInstance* item) { - return ItemInstance::isArmorItem(item) - && ((ArmorItem*)item)->slot == slot; -} - -void ArmorScreen::setupInventoryPane() { - // IntRectangle(0, 0, 100, 100) - if (inventoryPane) delete inventoryPane; - inventoryPane = new Touch::InventoryPane(this, minecraft, inventoryPaneRect, inventoryPaneRect.w, BorderPixels, armorItems.size(), ItemSize, (int)BorderPixels); - inventoryPane->fillMarginX = 0; - inventoryPane->fillMarginY = 0; - //LOGI("Creating new pane: %d %p\n", inventoryItems.size(), inventoryPane); -} - -void ArmorScreen::drawSlotItemAt( Tesselator& t, int slot, const ItemInstance* item, int x, int y) -{ - float xx = (float)x; - float yy = (float)y; - - guiSlot->draw(t, xx, yy); - - if (item && !item->isNull()) { - ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, xx + 2, yy, true); - glDisable2(GL_TEXTURE_2D); - ItemRenderer::renderGuiItemDecorations(item, xx + 2, yy + 3); - glEnable2(GL_TEXTURE_2D); - //minecraft->gui.renderSlotText(item, xx + 3, yy + 3, true, true); - } else { - minecraft->textures->loadAndBindTexture("gui/items.png"); - blit(x + 2, y, 15 * 16, slot * 16, 16, 16, 16, 16); - } -} - -void ArmorScreen::takeAndClearSlot( int slot ) { - ItemInstance* item = player->getArmor(slot); - if (!item) - return; - - int oldSize = minecraft->player->inventory->getNumEmptySlots(); - - if (!minecraft->player->inventory->add(item)) - minecraft->player->drop(new ItemInstance(*item), false); - - player->setArmor(slot, NULL); - - int newSize = minecraft->player->inventory->getNumEmptySlots(); - setIfNotSet(doRecreatePane, newSize != oldSize); -} - -void ArmorScreen::renderPlayer(float xo, float yo) { - // Push GL and player state - glPushMatrix(); - - glTranslatef(xo, yo, -200); - float ss = 45; - glScalef(-ss, ss, ss); - - glRotatef(180, 0, 0, 1); - //glDisable(GL_DEPTH_TEST); - - Player* player = (Player*) minecraft->player; - float oybr = player->yBodyRot; - float oyr = player->yRot; - float oxr = player->xRot; - - float t = getTimeS(); - - float xd = 10 * Mth::sin(t);//(xo + 51) - xm; - float yd = 10 * Mth::cos(t * 0.05f);//(yo + 75 - 50) - ym; - - glRotatef(45 + 90, 0, 1, 0); - glRotatef(-45 - 90, 0, 1, 0); - - const float xtan = Mth::atan(xd / 40.0f) * +20; - const float ytan = Mth::atan(yd / 40.0f) * -20; - - glRotatef(ytan, 1, 0, 0); - - player->yBodyRot = xtan; - player->yRot = xtan + xtan; - player->xRot = ytan; - glTranslatef(0, player->heightOffset, 0); - - // Push walking anim - float oldWAP = player->walkAnimPos; - float oldWAS = player->walkAnimSpeed; - float oldWASO = player->walkAnimSpeedO; - - // Set new walking anim - player->walkAnimSpeedO = player->walkAnimSpeed = 0.25f; - player->walkAnimPos = getTimeS() * player->walkAnimSpeed * SharedConstants::TicksPerSecond; - - EntityRenderDispatcher* rd = EntityRenderDispatcher::getInstance(); - rd->playerRotY = 180; - rd->render(player, 0, 0, 0, 0, 1); - - // Pop walking anim - player->walkAnimPos = oldWAP; - player->walkAnimSpeed = oldWAS; - player->walkAnimSpeedO = oldWASO; - - //glEnable(GL_DEPTH_TEST); - // Pop GL and player state - player->yBodyRot = oybr; - player->yRot = oyr; - player->xRot = oxr; - - glPopMatrix(); -} +#include "ArmorScreen.hpp" +#include "client/gui/Screen.hpp" +#include "client/gui/components/NinePatch.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemCategory.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/level/Level.hpp" +#include "network/RakNetInstance.hpp" +#include "client/renderer/entity/EntityRenderDispatcher.hpp" +#include "world/item/ArmorItem.hpp" + +static void setIfNotSet(bool& ref, bool condition) { + ref = (ref || condition); +} + +const int descFrameWidth = 100; + +const int rgbActive = 0xfff0f0f0; +const int rgbInactive = 0xc0635558; +const int rgbInactiveShadow = 0xc0aaaaaa; + +#ifdef __APPLE__ + static const float BorderPixels = 4; + #ifdef DEMO_MODE + static const float BlockPixels = 22; + #else + static const float BlockPixels = 22; + #endif +#else + static const float BorderPixels = 4; + static const float BlockPixels = 24; +#endif +static const int ItemSize = (int)(BlockPixels + 2*BorderPixels); + +static const int Bx = 10; // Border Frame width +static const int By = 6; // Border Frame height + + +ArmorScreen::ArmorScreen(): + inventoryPane(NULL), + btnArmor0(0), + btnArmor1(1), + btnArmor2(2), + btnArmor3(3), + btnClose(4, ""), + bHeader (5, "Armor"), + guiBackground(NULL), + guiSlot(NULL), + guiPaneFrame(NULL), + guiPlayerBg(NULL), + doRecreatePane(false), + descWidth(90) + //guiSlotItem(NULL), + //guiSlotItemSelected(NULL) +{ + //LOGI("Creating ArmorScreen with %p, %d\n", furnace, furnace->runningId); +} + +ArmorScreen::~ArmorScreen() { + delete inventoryPane; + + delete guiBackground; + delete guiSlot; + delete guiPaneFrame; + delete guiPlayerBg; +} + +void ArmorScreen::init() { + super::init(); + + player = minecraft->player; + + ImageDef def; + def.name = "gui/spritesheet.png"; + def.x = 0; + def.y = 1; + def.width = def.height = 18; + def.setSrc(IntRectangle(60, 0, 18, 18)); + btnClose.setImageDef(def, true); + btnClose.scaleWhenPressed = false; + + buttons.push_back(&bHeader); + buttons.push_back(&btnClose); + + armorButtons[0] = &btnArmor0; + armorButtons[1] = &btnArmor1; + armorButtons[2] = &btnArmor2; + armorButtons[3] = &btnArmor3; + for (int i = 0; i < NUM_ARMORBUTTONS; ++i) + buttons.push_back(armorButtons[i]); + + // GUI - nine patches + NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); + + guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); + guiSlot = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 3, 3, 20, 20); + guiPaneFrame = builder.createSymmetrical(IntRectangle(28, 42, 4, 4), 1, 1)->setExcluded(1 << 4); + guiPlayerBg = builder.createSymmetrical(IntRectangle(0, 20, 8, 8), 3, 3); + + updateItems(); +} + +void ArmorScreen::setupPositions() { + // Left - Categories + bHeader.x = bHeader.y = 0; + bHeader.width = width;// - bDone.w; + + btnClose.width = btnClose.height = 19; + btnClose.x = width - btnClose.width; + btnClose.y = 0; + + // Inventory pane + const int maxWidth = (int)(width/1.8f) - Bx - Bx; + const int InventoryColumns = maxWidth / ItemSize; + const int realWidth = InventoryColumns * ItemSize; + const int paneWidth = realWidth + Bx + Bx; + const int realBx = (paneWidth - realWidth) / 2; + + inventoryPaneRect = IntRectangle(realBx, +#ifdef __APPLE__ + 26 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-28); +#else + 26 + By, realWidth, height-By-By-28); +#endif + + for (int i = 0; i < NUM_ARMORBUTTONS; ++i) { + Button& b = *armorButtons[i]; + b.x = paneWidth; + b.y = inventoryPaneRect.y + 24 * i; + b.width = 20; + b.height = 20; + } + + guiPlayerBgRect.y = inventoryPaneRect.y; + int xx = armorButtons[0]->x + armorButtons[0]->width; + int xw = width - xx; + guiPlayerBgRect.x = xx + xw / 10; + guiPlayerBgRect.w = xw - (xw / 10) * 2; + guiPlayerBgRect.h = inventoryPaneRect.h; + + guiPaneFrame->setSize((float)inventoryPaneRect.w + 2, (float)inventoryPaneRect.h + 2); + guiPlayerBg->setSize((float)guiPlayerBgRect.w, (float)guiPlayerBgRect.h); + guiBackground->setSize((float)width, (float)height); + + updateItems(); + setupInventoryPane(); +} + +void ArmorScreen::tick() { + if (inventoryPane) + inventoryPane->tick(); + + if (doRecreatePane) { + updateItems(); + setupInventoryPane(); + doRecreatePane = false; + } +} + +void ArmorScreen::handleRenderPane(Touch::InventoryPane* pane, Tesselator& t, int xm, int ym, float a) { + if (pane) { + pane->render(xm, ym, a); + guiPaneFrame->draw(t, (float)(pane->rect.x - 1), (float)(pane->rect.y - 1)); + } +} + +void ArmorScreen::render(int xm, int ym, float a) { + //renderBackground(); + + Tesselator& t = Tesselator::instance; + + t.addOffset(0, 0, -500); + guiBackground->draw(t, 0, 0); + t.addOffset(0, 0, 500); + glEnable2(GL_ALPHA_TEST); + + // Buttons (Left side + crafting) + super::render(xm, ym, a); + + handleRenderPane(inventoryPane, t, xm, ym, a); + + t.colorABGR(0xffffffff); + glColor4f2(1, 1, 1, 1); + + t.addOffset(0, 0, -490); + guiPlayerBg->draw(t, (float)guiPlayerBgRect.x, (float)guiPlayerBgRect.y); + t.addOffset(0, 0, 490); + renderPlayer((float)(guiPlayerBgRect.x + guiPlayerBgRect.w / 2), 0.85f * height); + + for (int i = 0; i < NUM_ARMORBUTTONS; ++i) { + drawSlotItemAt(t, i, player->getArmor(i), armorButtons[i]->x, armorButtons[i]->y); + } + glDisable2(GL_ALPHA_TEST); +} + +void ArmorScreen::buttonClicked(Button* button) { + if (button == &btnClose) { + minecraft->setScreen(NULL); + } + + if (button->id >= 0 && button->id <= 3) { + takeAndClearSlot(button->id); + } +} + +bool ArmorScreen::addItem(const Touch::InventoryPane* forPane, int itemIndex) { + const ItemInstance* instance = armorItems[itemIndex]; + if (!ItemInstance::isArmorItem(instance)) + return false; + + ArmorItem* item = (ArmorItem*) instance->getItem(); + ItemInstance* old = player->getArmor(item->slot); + ItemInstance oldArmor; + + if (ItemInstance::isArmorItem(old)) { + oldArmor = *old; + } + + player->setArmor(item->slot, instance); + + player->inventory->removeItem(instance); + //@attn: this is hugely important + armorItems[itemIndex] = NULL; + + if (!oldArmor.isNull()) { + if (!player->inventory->add(&oldArmor)) { + player->drop(new ItemInstance(oldArmor), false); + } + } + + doRecreatePane = true; + return true; +} + +bool ArmorScreen::isAllowed( int slot ) { + return true; +} + +bool ArmorScreen::renderGameBehind() { + return false; +} + +std::vector ArmorScreen::getItems( const Touch::InventoryPane* forPane ) { + return armorItems; +} + +void ArmorScreen::updateItems() { + armorItems.clear(); + + for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) { + ItemInstance* item = minecraft->player->inventory->getItem(i); + if (ItemInstance::isArmorItem(item)) + armorItems.push_back(item); + } +} + +bool ArmorScreen::canMoveToSlot(int slot, const ItemInstance* item) { + return ItemInstance::isArmorItem(item) + && ((ArmorItem*)item)->slot == slot; +} + +void ArmorScreen::setupInventoryPane() { + // IntRectangle(0, 0, 100, 100) + if (inventoryPane) delete inventoryPane; + inventoryPane = new Touch::InventoryPane(this, minecraft, inventoryPaneRect, inventoryPaneRect.w, BorderPixels, armorItems.size(), ItemSize, (int)BorderPixels); + inventoryPane->fillMarginX = 0; + inventoryPane->fillMarginY = 0; + //LOGI("Creating new pane: %d %p\n", inventoryItems.size(), inventoryPane); +} + +void ArmorScreen::drawSlotItemAt( Tesselator& t, int slot, const ItemInstance* item, int x, int y) +{ + float xx = (float)x; + float yy = (float)y; + + guiSlot->draw(t, xx, yy); + + if (item && !item->isNull()) { + ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, xx + 2, yy, true); + glDisable2(GL_TEXTURE_2D); + ItemRenderer::renderGuiItemDecorations(item, xx + 2, yy + 3); + glEnable2(GL_TEXTURE_2D); + //minecraft->gui.renderSlotText(item, xx + 3, yy + 3, true, true); + } else { + minecraft->textures->loadAndBindTexture("gui/items.png"); + blit(x + 2, y, 15 * 16, slot * 16, 16, 16, 16, 16); + } +} + +void ArmorScreen::takeAndClearSlot( int slot ) { + ItemInstance* item = player->getArmor(slot); + if (!item) + return; + + int oldSize = minecraft->player->inventory->getNumEmptySlots(); + + if (!minecraft->player->inventory->add(item)) + minecraft->player->drop(new ItemInstance(*item), false); + + player->setArmor(slot, NULL); + + int newSize = minecraft->player->inventory->getNumEmptySlots(); + setIfNotSet(doRecreatePane, newSize != oldSize); +} + +void ArmorScreen::renderPlayer(float xo, float yo) { + // Push GL and player state + glPushMatrix(); + + glTranslatef(xo, yo, -200); + float ss = 45; + glScalef(-ss, ss, ss); + + glRotatef(180, 0, 0, 1); + //glDisable(GL_DEPTH_TEST); + + Player* player = (Player*) minecraft->player; + float oybr = player->yBodyRot; + float oyr = player->yRot; + float oxr = player->xRot; + + float t = getTimeS(); + + float xd = 10 * Mth::sin(t);//(xo + 51) - xm; + float yd = 10 * Mth::cos(t * 0.05f);//(yo + 75 - 50) - ym; + + glRotatef(45 + 90, 0, 1, 0); + glRotatef(-45 - 90, 0, 1, 0); + + const float xtan = Mth::atan(xd / 40.0f) * +20; + const float ytan = Mth::atan(yd / 40.0f) * -20; + + glRotatef(ytan, 1, 0, 0); + + player->yBodyRot = xtan; + player->yRot = xtan + xtan; + player->xRot = ytan; + glTranslatef(0, player->heightOffset, 0); + + // Push walking anim + float oldWAP = player->walkAnimPos; + float oldWAS = player->walkAnimSpeed; + float oldWASO = player->walkAnimSpeedO; + + // Set new walking anim + player->walkAnimSpeedO = player->walkAnimSpeed = 0.25f; + player->walkAnimPos = getTimeS() * player->walkAnimSpeed * SharedConstants::TicksPerSecond; + + EntityRenderDispatcher* rd = EntityRenderDispatcher::getInstance(); + rd->playerRotY = 180; + rd->render(player, 0, 0, 0, 0, 1); + + // Pop walking anim + player->walkAnimPos = oldWAP; + player->walkAnimSpeed = oldWAS; + player->walkAnimSpeedO = oldWASO; + + //glEnable(GL_DEPTH_TEST); + // Pop GL and player state + player->yBodyRot = oybr; + player->yRot = oyr; + player->xRot = oxr; + + glPopMatrix(); +} diff --git a/src/client/gui/screens/ArmorScreen.h b/src/client/gui/screens/ArmorScreen.hpp similarity index 93% rename from src/client/gui/screens/ArmorScreen.h rename to src/client/gui/screens/ArmorScreen.hpp index 578c1c0..f5856eb 100755 --- a/src/client/gui/screens/ArmorScreen.h +++ b/src/client/gui/screens/ArmorScreen.hpp @@ -1,9 +1,9 @@ #pragma once -#include "BaseContainerScreen.h" +#include "BaseContainerScreen.hpp" -#include "../components/InventoryPane.h" -#include "../components/Button.h" +#include "client/gui/components/InventoryPane.hpp" +#include "client/gui/components/Button.hpp" class Font; class CItem; diff --git a/src/client/gui/screens/BaseContainerScreen.h b/src/client/gui/screens/BaseContainerScreen.hpp similarity index 88% rename from src/client/gui/screens/BaseContainerScreen.h rename to src/client/gui/screens/BaseContainerScreen.hpp index b06dbb1..c80e37e 100755 --- a/src/client/gui/screens/BaseContainerScreen.h +++ b/src/client/gui/screens/BaseContainerScreen.hpp @@ -3,9 +3,9 @@ //package net.minecraft.client.gui.screens; #include -#include "../Screen.h" -#include "../../Minecraft.h" -#include "../../player/LocalPlayer.h" +#include "client/gui/Screen.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" class BaseContainerMenu; diff --git a/src/client/gui/screens/ChatScreen.cpp b/src/client/gui/screens/ChatScreen.cpp index 925444f..31d4c87 100755 --- a/src/client/gui/screens/ChatScreen.cpp +++ b/src/client/gui/screens/ChatScreen.cpp @@ -1,24 +1,24 @@ -#include "ChatScreen.h" -#include "DialogDefinitions.h" -#include "../Gui.h" -#include "../../Minecraft.h" -#include "../../../AppPlatform.h" -#include "../../../platform/log.h" - -void ChatScreen::init() { - minecraft->platform()->createUserInput(DialogDefinitions::DIALOG_NEW_CHAT_MESSAGE); -} - -void ChatScreen::render(int xm, int ym, float a) -{ - int status = minecraft->platform()->getUserInputStatus(); - if (status > -1) { - if (status == 1) { - std::vector v = minecraft->platform()->getUserInput(); - if (v.size() && v[0].length() > 0) - minecraft->gui.addMessage(v[0]); - } - - minecraft->setScreen(NULL); - } -} +#include "ChatScreen.hpp" +#include "DialogDefinitions.hpp" +#include "client/gui/Gui.hpp" +#include "client/Minecraft.hpp" +#include "AppPlatform.hpp" +#include "platform/log.hpp" + +void ChatScreen::init() { + minecraft->platform()->createUserInput(DialogDefinitions::DIALOG_NEW_CHAT_MESSAGE); +} + +void ChatScreen::render(int xm, int ym, float a) +{ + int status = minecraft->platform()->getUserInputStatus(); + if (status > -1) { + if (status == 1) { + std::vector v = minecraft->platform()->getUserInput(); + if (v.size() && v[0].length() > 0) + minecraft->gui.addMessage(v[0]); + } + + minecraft->setScreen(NULL); + } +} diff --git a/src/client/gui/screens/ChatScreen.h b/src/client/gui/screens/ChatScreen.hpp similarity index 86% rename from src/client/gui/screens/ChatScreen.h rename to src/client/gui/screens/ChatScreen.hpp index 809a3bb..5978d49 100755 --- a/src/client/gui/screens/ChatScreen.h +++ b/src/client/gui/screens/ChatScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Screen.h" +#include "client/gui/Screen.hpp" class ChatScreen: public Screen { diff --git a/src/client/gui/screens/ChestScreen.cpp b/src/client/gui/screens/ChestScreen.cpp index 8521733..590dedb 100755 --- a/src/client/gui/screens/ChestScreen.cpp +++ b/src/client/gui/screens/ChestScreen.cpp @@ -1,474 +1,474 @@ -#include "ChestScreen.h" -#include "touch/TouchStartMenuScreen.h" -#include "../Screen.h" -#include "../components/NinePatch.h" -#include "../../Minecraft.h" -#include "../../player/LocalPlayer.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/entity/ItemRenderer.h" -#include "../../../world/item/Item.h" -#include "../../../world/item/ItemCategory.h" -#include "../../../world/entity/player/Inventory.h" -#include "../../../world/entity/item/ItemEntity.h" -#include "../../../world/level/Level.h" -#include "../../../locale/I18n.h" -#include "../../../util/StringUtils.h" -#include "../../../network/packet/ContainerSetSlotPacket.h" -#include "../../../network/RakNetInstance.h" -#include "../../../world/level/tile/entity/TileEntity.h" -#include "../../../world/level/tile/entity/ChestTileEntity.h" -#include "../../../world/inventory/ContainerMenu.h" -#include "../../../util/Mth.h" - -//static NinePatchLayer* guiPaneFrame = NULL; - -static inline void setIfNotSet(bool& ref, bool condition) { - ref = (ref || condition); -} - -template -T* upcast(V* x) { return x; } - -static int heldMs = -1; -static int percent = -1; -static const float MaxHoldMs = 500.0f; -static const int MinChargeMs = 200; - -class ItemDiffer { -public: - ItemDiffer(int size) - : size(size), - count(0) - { - base = new ItemInstance[size]; - } - ItemDiffer(const std::vector& v) - : size(v.size()), - count(0) - { - base = new ItemInstance[size]; - init(v); - } - - ~ItemDiffer() { - delete[] base; - } - - void init(const std::vector& v) { - for (int i = 0; i < size; ++i) { - if (v[i]) base[i] = *v[i]; - else base[i].setNull(); - } - } - - int getDiff(const std::vector& v, std::vector& outIndices) { - int diffLen = v.size() - size; - int minLen = Mth::Max((int)v.size(), size); - for (int i = 0; i < minLen; ++i) { - //LOGI("%s, %s\n", base[i].toString().c_str(), v[i]?v[i]->toString().c_str() : "null"); - if (!ItemInstance::matchesNulls(&base[i], v[i])) - outIndices.push_back(i); - } - return diffLen; - } - -private: - int size; - int count; - ItemInstance* base; -}; - -const int descFrameWidth = 100; - -const int rgbActive = 0xfff0f0f0; -const int rgbInactive = 0xc0635558; -const int rgbInactiveShadow = 0xc0aaaaaa; - -#ifdef __APPLE__ - static const float BorderPixels = 3; - #ifdef DEMO_MODE - static const float BlockPixels = 22; - #else - static const float BlockPixels = 22; - #endif -#else - static const float BorderPixels = 4; - static const float BlockPixels = 24; -#endif -static const int ItemSize = (int)(BlockPixels + 2*BorderPixels); - -static const int Bx = 10; // Border Frame width -static const int By = 6; // Border Frame height - -typedef struct FlyingItem { - ItemInstance item; - float startTime; - float sx, sy; - float dx, dy; -} FlyingItem ; - -static std::vector flyingItems; - -ChestScreen::ChestScreen(Player* player, ChestTileEntity* chest) -: super(new ContainerMenu(chest, chest->runningId)), //@huge @attn - inventoryPane(NULL), - chestPane(NULL), - btnClose(4, ""), - bHeader (5, "Inventory"), - bHeaderChest (6, "Chest"), - guiBackground(NULL), - guiSlot(NULL), - guiSlotMarked(NULL), - guiSlotMarker(NULL), - player(player), - chest(chest), - selectedSlot(-1), - doRecreatePane(false) - //guiSlotItem(NULL), - //guiSlotItemSelected(NULL) -{ -} - -ChestScreen::~ChestScreen() { - delete inventoryPane; - delete chestPane; - - delete guiBackground; - delete guiSlot; - delete guiSlotMarked; - delete guiSlotMarker; - delete guiPaneFrame; - - delete menu; - - if (chest->clientSideOnly) - delete chest; -} - -void ChestScreen::init() { - super::init(); - //printf("-> %d\n", width/2); - - ImageDef def; - def.name = "gui/spritesheet.png"; - def.x = 0; - def.y = 1; - def.width = def.height = 18; - def.setSrc(IntRectangle(60, 0, 18, 18)); - btnClose.setImageDef(def, true); - btnClose.scaleWhenPressed = false; - - buttons.push_back(&bHeader); - buttons.push_back(&bHeaderChest); - buttons.push_back(&btnClose); - - // GUI - nine patches - NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); - - guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); - guiSlot = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 3, 3); - guiSlotMarked = builder.createSymmetrical(IntRectangle(0, 44, 8, 8), 3, 3); - guiSlotMarker = builder.createSymmetrical(IntRectangle(10, 42, 16, 16), 5, 5); - guiPaneFrame = builder.createSymmetrical(IntRectangle(28, 42, 4, 4), 1, 1)->exclude(4); -} - -void ChestScreen::setupPositions() { - // Left - Categories - bHeader.x = 0; - bHeader.y = bHeaderChest.y = 0; - bHeader.width = bHeaderChest.width = width / 2;// - bDone.w; - bHeaderChest.x = bHeader.x + bHeader.width; - - // Right - Description - btnClose.width = btnClose.height = 19; - btnClose.x = width - btnClose.width; - btnClose.y = 0; - - //guiPaneFrame->setSize((float)paneFuelRect.w + 2, (float)paneFuelRect.h + 4); - guiBackground->setSize((float)width, (float)height); - //guiSlotItem->setSize((float)width, 22); //@todo - //guiSlotItemSelected->setSize((float)width, 22); - - setupPane(); -} - -void ChestScreen::tick() { - if (inventoryPane) - inventoryPane->tick(); - - if (chestPane) - chestPane->tick(); - - if (doRecreatePane) { - setupPane(); - doRecreatePane = false; - } -} - -void ChestScreen::handleRenderPane(Touch::InventoryPane* pane, Tesselator& t, int xm, int ym, float a) { - if (pane) { - int ms, id; - pane->markerIndex = -1; - if (pane->queryHoldTime(&id, &ms)) { - heldMs = ms; - - FillingContainer* c = (pane == inventoryPane)? - upcast(minecraft->player->inventory) - : upcast(chest); - - const int slotIndex = id + c->getNumLinkedSlots(); - ItemInstance* item = c->getItem(slotIndex); - int count = (item && !item->isNull())? item->count : 0; - float maxHoldMs = item? 700 + 10 * item->count: MaxHoldMs; - - if (count > 1) { - float share = (heldMs-MinChargeMs) / maxHoldMs; - pane->markerType = 1;//(heldMs >= MinChargeMs)? 1 : 0; - pane->markerIndex = id; - pane->markerShare = Mth::Max(share, 0.0f); - - percent = (int)Mth::clamp(100.0f * share, 0.0f, 100.0f); - if (percent >= 100) { - addItem(pane, id); - } - } - } - - pane->render(xm, ym, a); - guiPaneFrame->draw(t, (float)(pane->rect.x - 1), (float)(pane->rect.y - 1)); - //LOGI("query-iv: %d, %d\n", gridId, heldMs); - - } -} - -void ChestScreen::render(int xm, int ym, float a) { - const int N = 5; - static StopwatchNLast r(N); - //renderBackground(); - - Tesselator& t = Tesselator::instance; - guiBackground->draw(t, 0, 0); - glEnable2(GL_ALPHA_TEST); - - // Buttons (Left side + crafting) - super::render(xm, ym, a); - - heldMs = -1; - - handleRenderPane(inventoryPane, t, xm, ym, a); - handleRenderPane(chestPane, t, xm, ym, a); - - float now = getTimeS(); - float MaxTime = 0.3f; - std::vector flyingToSave; - - glEnable2(GL_BLEND); - glColor4f(1, 1, 1, 0.2f); - t.beginOverride(); - //t.color(1.0f, 0.0f, 0.0f, 0.2f); - //t.noColor(); - - glEnable2(GL_SCISSOR_TEST); - //LOGI("panesBox: %d, %d - %d, %d\n", panesBbox.x, panesBbox.y, panesBbox.w, panesBbox.h); - minecraft->gui.setScissorRect(panesBbox); - for (unsigned int i = 0; i < flyingItems.size(); ++i) { - FlyingItem& fi = flyingItems[i]; - float since = (now - fi.startTime); - if (since > MaxTime) continue; - float t = since / MaxTime; - t *= t; - //float xx = fi.sx + t * 100.0f; - - float xx = Mth::lerp(fi.sx, fi.dx, t); - float yy = Mth::lerp(fi.sy, fi.dy, t); - ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, &fi.item, xx + 7, yy + 8, true); - //minecraft->gui.renderSlotText(&fi.item, xx + 3, yy + 3, true, true); - - flyingToSave.push_back(fi); - } - t.enableColor(); - t.endOverrideAndDraw(); - glDisable2(GL_SCISSOR_TEST); - - flyingItems = flyingToSave; - - t.colorABGR(0xffffffff); - glDisable2(GL_BLEND); - - minecraft->textures->loadAndBindTexture("gui/spritesheet.png"); -} - -void ChestScreen::buttonClicked(Button* button) { - if (button == &btnClose) { - minecraft->player->closeContainer(); - } -} - -bool ChestScreen::handleAddItem(FillingContainer* from, FillingContainer* to, int itemIndex) { - const int itemOffset = from->getNumLinkedSlots(); - const int slotIndex = itemIndex + itemOffset; - ItemInstance* item = from->getItem(slotIndex); - - bool added = false; - bool fromChest = (from == chest); - Touch::InventoryPane* pane = fromChest? chestPane : inventoryPane; - Touch::InventoryPane* toPane = fromChest? inventoryPane : chestPane; - - int wantedCount = (item && !item->isNull())? item->count * percent / 100 : 0; - if ((item && !item->isNull()) && (!wantedCount || heldMs < MinChargeMs)) { - wantedCount = 1; - } - - if (wantedCount > 0) { - ItemInstance takenItem(*item); - takenItem.count = wantedCount; - - ItemDiffer differ(getItems(toPane)); - to->add(&takenItem); - - added = (takenItem.count != wantedCount); - - if (added) { - item->count -= (wantedCount - takenItem.count); - std::vector changed; - std::vector items = getItems(toPane); - differ.getDiff(items, changed); - - ScrollingPane::GridItem g, gTo; - pane->getGridItemFor_slow(itemIndex, g); - - //LOGI("Changed: %d\n", changed.size()); - for (unsigned int i = 0; i < changed.size(); ++i) { - FlyingItem fi; - fi.startTime = getTimeS(); - fi.item = *item; - - fi.sx = g.xf; - fi.sy = g.yf; - - int toIndex = changed[i]; - toPane->getGridItemFor_slow(toIndex, gTo); - - fi.dx = gTo.xf; - fi.dy = gTo.yf; - flyingItems.push_back(fi); - - if (!fromChest && minecraft->level->isClientSide) { - int j = toIndex; - ItemInstance item = items[j]? *items[j] : ItemInstance(); - ContainerSetSlotPacket p(menu->containerId, j, item); - minecraft->raknetInstance->send(p); - } - } - } - - // Send to server, needs a bit special handling - if (fromChest) { - ItemInstance ins(item->count <= 0? ItemInstance() : *item); - ContainerSetSlotPacket p(menu->containerId, slotIndex, ins); - minecraft->raknetInstance->send(p); - } - if (item->count <= 0) - from->clearSlot(slotIndex); - } - // Clear the marker indices - pane->markerIndex = toPane->markerIndex = -1; - - return added; -} - -bool ChestScreen::addItem(const Touch::InventoryPane* forPane, int itemIndex) { - //LOGI("items.size, index: %d, %d\n", inventoryItems.size(), itemIndex); - bool l2r = (forPane == inventoryPane); - return handleAddItem( l2r? upcast(minecraft->player->inventory) : upcast(chest), - l2r? upcast(chest) : upcast(minecraft->player->inventory), - itemIndex); -} - -bool ChestScreen::isAllowed( int slot ) -{ - return true; -} - -bool ChestScreen::renderGameBehind() -{ - return false; -} - -std::vector ChestScreen::getItems( const Touch::InventoryPane* forPane ) -{ - if (forPane == inventoryPane) { - for (int i = Inventory::MAX_SELECTION_SIZE, j = 0; i < minecraft->player->inventory->getContainerSize(); ++i, ++j) - inventoryItems[j] = minecraft->player->inventory->getItem(i); - return inventoryItems; - } - else { - for (int i = 0; i < chest->getContainerSize(); ++i) - chestItems[i] = chest->getItem(i); - return chestItems; - } -} - - -void ChestScreen::setupPane() -{ - inventoryItems.clear(); - for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) { - ItemInstance* item = minecraft->player->inventory->getItem(i); - /*if (!item || item->isNull()) continue;*/ - inventoryItems.push_back(item); - } - chestItems.clear(); - for (int i = 0; i < chest->getContainerSize(); ++i) { - ItemInstance* item = chest->getItem(i); - /*if (!item || item->isNull()) continue;*/ - chestItems.push_back(item); - } - - int maxWidth = width/2 - Bx/2;//- Bx - Bx/*- Bx*/; - int InventoryColumns = maxWidth / ItemSize; - const int realWidth = InventoryColumns * ItemSize; - int paneWidth = realWidth;// + Bx + Bx; - const int realBx = (width/2 - realWidth) / 2; - - IntRectangle rect(realBx, -#ifdef __APPLE__ - 24 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-24); -#else - 24 + By, realWidth, height-By-By-24); -#endif - // IntRectangle(0, 0, 100, 100) - if (inventoryPane) delete inventoryPane; - inventoryPane = new Touch::InventoryPane(this, minecraft, rect, paneWidth, BorderPixels, minecraft->player->inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE, ItemSize, (int)BorderPixels); - inventoryPane->fillMarginX = 0; - inventoryPane->fillMarginY = 0; - guiPaneFrame->setSize((float)rect.w + 2, (float)rect.h + 2); - - panesBbox = rect; - rect.x += width/2;// - rect.w - Bx; - panesBbox.w += (rect.x - panesBbox.x); - - if (chestPane) delete chestPane; - chestPane = new Touch::InventoryPane(this, minecraft, rect, paneWidth, BorderPixels, chest->getContainerSize(), ItemSize, (int)BorderPixels); - chestPane->fillMarginX = 0; - chestPane->fillMarginY = 0; - LOGI("Creating new panes\n:" - " Inventory %d %p\n" - " Chest %d %p\n", (int)inventoryItems.size(), inventoryPane, (int)chestItems.size(), chestPane); -} - -void ChestScreen::drawSlotItemAt( Tesselator& t, const ItemInstance* item, int x, int y, bool selected) -{ - float xx = (float)x; - float yy = (float)y; - - (selected? guiSlot/*Marked*/ : guiSlot)->draw(t, xx, yy); - - if (selected) - guiSlotMarker->draw(t, xx - 2, yy - 2); - - if (item && !item->isNull()) { - ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, xx + 7, yy + 8, true); - minecraft->gui.renderSlotText(item, xx + 3, yy + 3, true, true); - } -} +#include "ChestScreen.hpp" +#include "touch/TouchStartMenuScreen.hpp" +#include "client/gui/Screen.hpp" +#include "client/gui/components/NinePatch.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemCategory.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/level/Level.hpp" +#include "locale/I18n.hpp" +#include "util/StringUtils.hpp" +#include "network/packet/ContainerSetSlotPacket.hpp" +#include "network/RakNetInstance.hpp" +#include "world/level/tile/entity/TileEntity.hpp" +#include "world/level/tile/entity/ChestTileEntity.hpp" +#include "world/inventory/ContainerMenu.hpp" +#include "util/Mth.hpp" + +//static NinePatchLayer* guiPaneFrame = NULL; + +static inline void setIfNotSet(bool& ref, bool condition) { + ref = (ref || condition); +} + +template +T* upcast(V* x) { return x; } + +static int heldMs = -1; +static int percent = -1; +static const float MaxHoldMs = 500.0f; +static const int MinChargeMs = 200; + +class ItemDiffer { +public: + ItemDiffer(int size) + : size(size), + count(0) + { + base = new ItemInstance[size]; + } + ItemDiffer(const std::vector& v) + : size(v.size()), + count(0) + { + base = new ItemInstance[size]; + init(v); + } + + ~ItemDiffer() { + delete[] base; + } + + void init(const std::vector& v) { + for (int i = 0; i < size; ++i) { + if (v[i]) base[i] = *v[i]; + else base[i].setNull(); + } + } + + int getDiff(const std::vector& v, std::vector& outIndices) { + int diffLen = v.size() - size; + int minLen = Mth::Max((int)v.size(), size); + for (int i = 0; i < minLen; ++i) { + //LOGI("%s, %s\n", base[i].toString().c_str(), v[i]?v[i]->toString().c_str() : "null"); + if (!ItemInstance::matchesNulls(&base[i], v[i])) + outIndices.push_back(i); + } + return diffLen; + } + +private: + int size; + int count; + ItemInstance* base; +}; + +const int descFrameWidth = 100; + +const int rgbActive = 0xfff0f0f0; +const int rgbInactive = 0xc0635558; +const int rgbInactiveShadow = 0xc0aaaaaa; + +#ifdef __APPLE__ + static const float BorderPixels = 3; + #ifdef DEMO_MODE + static const float BlockPixels = 22; + #else + static const float BlockPixels = 22; + #endif +#else + static const float BorderPixels = 4; + static const float BlockPixels = 24; +#endif +static const int ItemSize = (int)(BlockPixels + 2*BorderPixels); + +static const int Bx = 10; // Border Frame width +static const int By = 6; // Border Frame height + +typedef struct FlyingItem { + ItemInstance item; + float startTime; + float sx, sy; + float dx, dy; +} FlyingItem ; + +static std::vector flyingItems; + +ChestScreen::ChestScreen(Player* player, ChestTileEntity* chest) +: super(new ContainerMenu(chest, chest->runningId)), //@huge @attn + inventoryPane(NULL), + chestPane(NULL), + btnClose(4, ""), + bHeader (5, "Inventory"), + bHeaderChest (6, "Chest"), + guiBackground(NULL), + guiSlot(NULL), + guiSlotMarked(NULL), + guiSlotMarker(NULL), + player(player), + chest(chest), + selectedSlot(-1), + doRecreatePane(false) + //guiSlotItem(NULL), + //guiSlotItemSelected(NULL) +{ +} + +ChestScreen::~ChestScreen() { + delete inventoryPane; + delete chestPane; + + delete guiBackground; + delete guiSlot; + delete guiSlotMarked; + delete guiSlotMarker; + delete guiPaneFrame; + + delete menu; + + if (chest->clientSideOnly) + delete chest; +} + +void ChestScreen::init() { + super::init(); + //printf("-> %d\n", width/2); + + ImageDef def; + def.name = "gui/spritesheet.png"; + def.x = 0; + def.y = 1; + def.width = def.height = 18; + def.setSrc(IntRectangle(60, 0, 18, 18)); + btnClose.setImageDef(def, true); + btnClose.scaleWhenPressed = false; + + buttons.push_back(&bHeader); + buttons.push_back(&bHeaderChest); + buttons.push_back(&btnClose); + + // GUI - nine patches + NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); + + guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); + guiSlot = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 3, 3); + guiSlotMarked = builder.createSymmetrical(IntRectangle(0, 44, 8, 8), 3, 3); + guiSlotMarker = builder.createSymmetrical(IntRectangle(10, 42, 16, 16), 5, 5); + guiPaneFrame = builder.createSymmetrical(IntRectangle(28, 42, 4, 4), 1, 1)->exclude(4); +} + +void ChestScreen::setupPositions() { + // Left - Categories + bHeader.x = 0; + bHeader.y = bHeaderChest.y = 0; + bHeader.width = bHeaderChest.width = width / 2;// - bDone.w; + bHeaderChest.x = bHeader.x + bHeader.width; + + // Right - Description + btnClose.width = btnClose.height = 19; + btnClose.x = width - btnClose.width; + btnClose.y = 0; + + //guiPaneFrame->setSize((float)paneFuelRect.w + 2, (float)paneFuelRect.h + 4); + guiBackground->setSize((float)width, (float)height); + //guiSlotItem->setSize((float)width, 22); //@todo + //guiSlotItemSelected->setSize((float)width, 22); + + setupPane(); +} + +void ChestScreen::tick() { + if (inventoryPane) + inventoryPane->tick(); + + if (chestPane) + chestPane->tick(); + + if (doRecreatePane) { + setupPane(); + doRecreatePane = false; + } +} + +void ChestScreen::handleRenderPane(Touch::InventoryPane* pane, Tesselator& t, int xm, int ym, float a) { + if (pane) { + int ms, id; + pane->markerIndex = -1; + if (pane->queryHoldTime(&id, &ms)) { + heldMs = ms; + + FillingContainer* c = (pane == inventoryPane)? + upcast(minecraft->player->inventory) + : upcast(chest); + + const int slotIndex = id + c->getNumLinkedSlots(); + ItemInstance* item = c->getItem(slotIndex); + int count = (item && !item->isNull())? item->count : 0; + float maxHoldMs = item? 700 + 10 * item->count: MaxHoldMs; + + if (count > 1) { + float share = (heldMs-MinChargeMs) / maxHoldMs; + pane->markerType = 1;//(heldMs >= MinChargeMs)? 1 : 0; + pane->markerIndex = id; + pane->markerShare = Mth::Max(share, 0.0f); + + percent = (int)Mth::clamp(100.0f * share, 0.0f, 100.0f); + if (percent >= 100) { + addItem(pane, id); + } + } + } + + pane->render(xm, ym, a); + guiPaneFrame->draw(t, (float)(pane->rect.x - 1), (float)(pane->rect.y - 1)); + //LOGI("query-iv: %d, %d\n", gridId, heldMs); + + } +} + +void ChestScreen::render(int xm, int ym, float a) { + const int N = 5; + static StopwatchNLast r(N); + //renderBackground(); + + Tesselator& t = Tesselator::instance; + guiBackground->draw(t, 0, 0); + glEnable2(GL_ALPHA_TEST); + + // Buttons (Left side + crafting) + super::render(xm, ym, a); + + heldMs = -1; + + handleRenderPane(inventoryPane, t, xm, ym, a); + handleRenderPane(chestPane, t, xm, ym, a); + + float now = getTimeS(); + float MaxTime = 0.3f; + std::vector flyingToSave; + + glEnable2(GL_BLEND); + glColor4f(1, 1, 1, 0.2f); + t.beginOverride(); + //t.color(1.0f, 0.0f, 0.0f, 0.2f); + //t.noColor(); + + glEnable2(GL_SCISSOR_TEST); + //LOGI("panesBox: %d, %d - %d, %d\n", panesBbox.x, panesBbox.y, panesBbox.w, panesBbox.h); + minecraft->gui.setScissorRect(panesBbox); + for (unsigned int i = 0; i < flyingItems.size(); ++i) { + FlyingItem& fi = flyingItems[i]; + float since = (now - fi.startTime); + if (since > MaxTime) continue; + float t = since / MaxTime; + t *= t; + //float xx = fi.sx + t * 100.0f; + + float xx = Mth::lerp(fi.sx, fi.dx, t); + float yy = Mth::lerp(fi.sy, fi.dy, t); + ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, &fi.item, xx + 7, yy + 8, true); + //minecraft->gui.renderSlotText(&fi.item, xx + 3, yy + 3, true, true); + + flyingToSave.push_back(fi); + } + t.enableColor(); + t.endOverrideAndDraw(); + glDisable2(GL_SCISSOR_TEST); + + flyingItems = flyingToSave; + + t.colorABGR(0xffffffff); + glDisable2(GL_BLEND); + + minecraft->textures->loadAndBindTexture("gui/spritesheet.png"); +} + +void ChestScreen::buttonClicked(Button* button) { + if (button == &btnClose) { + minecraft->player->closeContainer(); + } +} + +bool ChestScreen::handleAddItem(FillingContainer* from, FillingContainer* to, int itemIndex) { + const int itemOffset = from->getNumLinkedSlots(); + const int slotIndex = itemIndex + itemOffset; + ItemInstance* item = from->getItem(slotIndex); + + bool added = false; + bool fromChest = (from == chest); + Touch::InventoryPane* pane = fromChest? chestPane : inventoryPane; + Touch::InventoryPane* toPane = fromChest? inventoryPane : chestPane; + + int wantedCount = (item && !item->isNull())? item->count * percent / 100 : 0; + if ((item && !item->isNull()) && (!wantedCount || heldMs < MinChargeMs)) { + wantedCount = 1; + } + + if (wantedCount > 0) { + ItemInstance takenItem(*item); + takenItem.count = wantedCount; + + ItemDiffer differ(getItems(toPane)); + to->add(&takenItem); + + added = (takenItem.count != wantedCount); + + if (added) { + item->count -= (wantedCount - takenItem.count); + std::vector changed; + std::vector items = getItems(toPane); + differ.getDiff(items, changed); + + ScrollingPane::GridItem g, gTo; + pane->getGridItemFor_slow(itemIndex, g); + + //LOGI("Changed: %d\n", changed.size()); + for (unsigned int i = 0; i < changed.size(); ++i) { + FlyingItem fi; + fi.startTime = getTimeS(); + fi.item = *item; + + fi.sx = g.xf; + fi.sy = g.yf; + + int toIndex = changed[i]; + toPane->getGridItemFor_slow(toIndex, gTo); + + fi.dx = gTo.xf; + fi.dy = gTo.yf; + flyingItems.push_back(fi); + + if (!fromChest && minecraft->level->isClientSide) { + int j = toIndex; + ItemInstance item = items[j]? *items[j] : ItemInstance(); + ContainerSetSlotPacket p(menu->containerId, j, item); + minecraft->raknetInstance->send(p); + } + } + } + + // Send to server, needs a bit special handling + if (fromChest) { + ItemInstance ins(item->count <= 0? ItemInstance() : *item); + ContainerSetSlotPacket p(menu->containerId, slotIndex, ins); + minecraft->raknetInstance->send(p); + } + if (item->count <= 0) + from->clearSlot(slotIndex); + } + // Clear the marker indices + pane->markerIndex = toPane->markerIndex = -1; + + return added; +} + +bool ChestScreen::addItem(const Touch::InventoryPane* forPane, int itemIndex) { + //LOGI("items.size, index: %d, %d\n", inventoryItems.size(), itemIndex); + bool l2r = (forPane == inventoryPane); + return handleAddItem( l2r? upcast(minecraft->player->inventory) : upcast(chest), + l2r? upcast(chest) : upcast(minecraft->player->inventory), + itemIndex); +} + +bool ChestScreen::isAllowed( int slot ) +{ + return true; +} + +bool ChestScreen::renderGameBehind() +{ + return false; +} + +std::vector ChestScreen::getItems( const Touch::InventoryPane* forPane ) +{ + if (forPane == inventoryPane) { + for (int i = Inventory::MAX_SELECTION_SIZE, j = 0; i < minecraft->player->inventory->getContainerSize(); ++i, ++j) + inventoryItems[j] = minecraft->player->inventory->getItem(i); + return inventoryItems; + } + else { + for (int i = 0; i < chest->getContainerSize(); ++i) + chestItems[i] = chest->getItem(i); + return chestItems; + } +} + + +void ChestScreen::setupPane() +{ + inventoryItems.clear(); + for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) { + ItemInstance* item = minecraft->player->inventory->getItem(i); + /*if (!item || item->isNull()) continue;*/ + inventoryItems.push_back(item); + } + chestItems.clear(); + for (int i = 0; i < chest->getContainerSize(); ++i) { + ItemInstance* item = chest->getItem(i); + /*if (!item || item->isNull()) continue;*/ + chestItems.push_back(item); + } + + int maxWidth = width/2 - Bx/2;//- Bx - Bx/*- Bx*/; + int InventoryColumns = maxWidth / ItemSize; + const int realWidth = InventoryColumns * ItemSize; + int paneWidth = realWidth;// + Bx + Bx; + const int realBx = (width/2 - realWidth) / 2; + + IntRectangle rect(realBx, +#ifdef __APPLE__ + 24 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-24); +#else + 24 + By, realWidth, height-By-By-24); +#endif + // IntRectangle(0, 0, 100, 100) + if (inventoryPane) delete inventoryPane; + inventoryPane = new Touch::InventoryPane(this, minecraft, rect, paneWidth, BorderPixels, minecraft->player->inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE, ItemSize, (int)BorderPixels); + inventoryPane->fillMarginX = 0; + inventoryPane->fillMarginY = 0; + guiPaneFrame->setSize((float)rect.w + 2, (float)rect.h + 2); + + panesBbox = rect; + rect.x += width/2;// - rect.w - Bx; + panesBbox.w += (rect.x - panesBbox.x); + + if (chestPane) delete chestPane; + chestPane = new Touch::InventoryPane(this, minecraft, rect, paneWidth, BorderPixels, chest->getContainerSize(), ItemSize, (int)BorderPixels); + chestPane->fillMarginX = 0; + chestPane->fillMarginY = 0; + LOGI("Creating new panes\n:" + " Inventory %d %p\n" + " Chest %d %p\n", (int)inventoryItems.size(), inventoryPane, (int)chestItems.size(), chestPane); +} + +void ChestScreen::drawSlotItemAt( Tesselator& t, const ItemInstance* item, int x, int y, bool selected) +{ + float xx = (float)x; + float yy = (float)y; + + (selected? guiSlot/*Marked*/ : guiSlot)->draw(t, xx, yy); + + if (selected) + guiSlotMarker->draw(t, xx - 2, yy - 2); + + if (item && !item->isNull()) { + ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, xx + 7, yy + 8, true); + minecraft->gui.renderSlotText(item, xx + 3, yy + 3, true, true); + } +} diff --git a/src/client/gui/screens/ChestScreen.h b/src/client/gui/screens/ChestScreen.hpp similarity index 92% rename from src/client/gui/screens/ChestScreen.h rename to src/client/gui/screens/ChestScreen.hpp index 216b459..5db3f1b 100755 --- a/src/client/gui/screens/ChestScreen.h +++ b/src/client/gui/screens/ChestScreen.hpp @@ -1,9 +1,9 @@ #pragma once -#include "BaseContainerScreen.h" +#include "BaseContainerScreen.hpp" -#include "../components/InventoryPane.h" -#include "../components/Button.h" +#include "client/gui/components/InventoryPane.hpp" +#include "client/gui/components/Button.hpp" class Font; class CItem; diff --git a/src/client/gui/screens/ChooseLevelScreen.cpp b/src/client/gui/screens/ChooseLevelScreen.cpp index 1cef1c5..a622936 100755 --- a/src/client/gui/screens/ChooseLevelScreen.cpp +++ b/src/client/gui/screens/ChooseLevelScreen.cpp @@ -1,26 +1,26 @@ -#include "ChooseLevelScreen.h" -#include -#include -#include "../../Minecraft.h" - -void ChooseLevelScreen::init() { - loadLevelSource(); -} - -void ChooseLevelScreen::loadLevelSource() -{ - LevelStorageSource* levelSource = minecraft->getLevelSource(); - levelSource->getLevelList(levels); - std::sort(levels.begin(), levels.end()); -} - -std::string ChooseLevelScreen::getUniqueLevelName( const std::string& level ) { - std::set Set; - for (unsigned int i = 0; i < levels.size(); ++i) - Set.insert(levels[i].id); - - std::string s = level; - while ( Set.find(s) != Set.end() ) - s += "-"; - return s; -} +#include "ChooseLevelScreen.hpp" +#include +#include +#include "client/Minecraft.hpp" + +void ChooseLevelScreen::init() { + loadLevelSource(); +} + +void ChooseLevelScreen::loadLevelSource() +{ + LevelStorageSource* levelSource = minecraft->getLevelSource(); + levelSource->getLevelList(levels); + std::sort(levels.begin(), levels.end()); +} + +std::string ChooseLevelScreen::getUniqueLevelName( const std::string& level ) { + std::set Set; + for (unsigned int i = 0; i < levels.size(); ++i) + Set.insert(levels[i].id); + + std::string s = level; + while ( Set.find(s) != Set.end() ) + s += "-"; + return s; +} diff --git a/src/client/gui/screens/ChooseLevelScreen.h b/src/client/gui/screens/ChooseLevelScreen.hpp similarity index 71% rename from src/client/gui/screens/ChooseLevelScreen.h rename to src/client/gui/screens/ChooseLevelScreen.hpp index 069608a..27f0f72 100755 --- a/src/client/gui/screens/ChooseLevelScreen.h +++ b/src/client/gui/screens/ChooseLevelScreen.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../Screen.h" -#include "../../../world/level/storage/LevelStorageSource.h" +#include "client/gui/Screen.hpp" +#include "world/level/storage/LevelStorageSource.hpp" class ChooseLevelScreen: public Screen { diff --git a/src/client/gui/screens/ConfirmScreen.cpp b/src/client/gui/screens/ConfirmScreen.cpp index 2529549..8513cb7 100755 --- a/src/client/gui/screens/ConfirmScreen.cpp +++ b/src/client/gui/screens/ConfirmScreen.cpp @@ -1,84 +1,84 @@ -#include "ConfirmScreen.h" -#include "../components/Button.h" -#include "../../Minecraft.h" - -ConfirmScreen::ConfirmScreen(Screen* parent_, const std::string& title1_, const std::string& title2_, int id_) -: parent(parent_), - title1(title1_), - title2(title2_), - id(id_), - yesButtonText("Ok"), - noButtonText("Cancel"), - yesButton(0), - noButton(0) -{ -} - -ConfirmScreen::ConfirmScreen(Screen* parent_, const std::string& title1_, const std::string& title2_, const std::string& yesButton_, const std::string& noButton_, int id_ ) -: parent(parent_), - title1(title1_), - title2(title2_), - id(id_), - yesButtonText(yesButton_), - noButtonText(noButton_) -{ -} - -ConfirmScreen::~ConfirmScreen() { - delete yesButton; - delete noButton; -} - -void ConfirmScreen::init() -{ - if (/* minecraft->useTouchscreen() */ true) { - yesButton = new Touch::TButton(0, 0, 0, yesButtonText), - noButton = new Touch::TButton(1, 0, 0, noButtonText); - } else { - yesButton = new Button(0, 0, 0, yesButtonText), - noButton = new Button(1, 0, 0, noButtonText); - } - - buttons.push_back(yesButton); - buttons.push_back(noButton); - - tabButtons.push_back(yesButton); - tabButtons.push_back(noButton); -} - -void ConfirmScreen::setupPositions() { - const int ButtonWidth = 120; - const int ButtonHeight = 24; - yesButton->x = width / 2 - ButtonWidth - 4; - yesButton->y = height / 6 + 72; - noButton->x = width / 2 + 4; - noButton->y = height / 6 + 72; - yesButton->width = noButton->width = ButtonWidth; - yesButton->height = noButton->height = ButtonHeight; -} - -bool ConfirmScreen::handleBackEvent(bool isDown) { - if (!isDown) - postResult(false); - return true; -} - -void ConfirmScreen::render( int xm, int ym, float a ) -{ - renderBackground(); - - drawCenteredString(font, title1, width / 2, 50, 0xffffff); - drawCenteredString(font, title2, width / 2, 70, 0xffffff); - - super::render(xm, ym, a); -} - -void ConfirmScreen::buttonClicked( Button* button ) -{ - postResult(button->id == 0); -} - -void ConfirmScreen::postResult(bool isOk) -{ - parent->confirmResult(isOk, id); -} +#include "ConfirmScreen.hpp" +#include "client/gui/components/Button.hpp" +#include "client/Minecraft.hpp" + +ConfirmScreen::ConfirmScreen(Screen* parent_, const std::string& title1_, const std::string& title2_, int id_) +: parent(parent_), + title1(title1_), + title2(title2_), + id(id_), + yesButtonText("Ok"), + noButtonText("Cancel"), + yesButton(0), + noButton(0) +{ +} + +ConfirmScreen::ConfirmScreen(Screen* parent_, const std::string& title1_, const std::string& title2_, const std::string& yesButton_, const std::string& noButton_, int id_ ) +: parent(parent_), + title1(title1_), + title2(title2_), + id(id_), + yesButtonText(yesButton_), + noButtonText(noButton_) +{ +} + +ConfirmScreen::~ConfirmScreen() { + delete yesButton; + delete noButton; +} + +void ConfirmScreen::init() +{ + if (/* minecraft->useTouchscreen() */ true) { + yesButton = new Touch::TButton(0, 0, 0, yesButtonText), + noButton = new Touch::TButton(1, 0, 0, noButtonText); + } else { + yesButton = new Button(0, 0, 0, yesButtonText), + noButton = new Button(1, 0, 0, noButtonText); + } + + buttons.push_back(yesButton); + buttons.push_back(noButton); + + tabButtons.push_back(yesButton); + tabButtons.push_back(noButton); +} + +void ConfirmScreen::setupPositions() { + const int ButtonWidth = 120; + const int ButtonHeight = 24; + yesButton->x = width / 2 - ButtonWidth - 4; + yesButton->y = height / 6 + 72; + noButton->x = width / 2 + 4; + noButton->y = height / 6 + 72; + yesButton->width = noButton->width = ButtonWidth; + yesButton->height = noButton->height = ButtonHeight; +} + +bool ConfirmScreen::handleBackEvent(bool isDown) { + if (!isDown) + postResult(false); + return true; +} + +void ConfirmScreen::render( int xm, int ym, float a ) +{ + renderBackground(); + + drawCenteredString(font, title1, width / 2, 50, 0xffffff); + drawCenteredString(font, title2, width / 2, 70, 0xffffff); + + super::render(xm, ym, a); +} + +void ConfirmScreen::buttonClicked( Button* button ) +{ + postResult(button->id == 0); +} + +void ConfirmScreen::postResult(bool isOk) +{ + parent->confirmResult(isOk, id); +} diff --git a/src/client/gui/screens/ConfirmScreen.h b/src/client/gui/screens/ConfirmScreen.hpp similarity index 96% rename from src/client/gui/screens/ConfirmScreen.h rename to src/client/gui/screens/ConfirmScreen.hpp index db834ae..7036bba 100755 --- a/src/client/gui/screens/ConfirmScreen.h +++ b/src/client/gui/screens/ConfirmScreen.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.gui; -#include "../Screen.h" +#include "client/gui/Screen.hpp" #include class ConfirmScreen: public Screen diff --git a/src/client/gui/screens/ConsoleScreen.cpp b/src/client/gui/screens/ConsoleScreen.cpp index 939cb74..fec76b0 100644 --- a/src/client/gui/screens/ConsoleScreen.cpp +++ b/src/client/gui/screens/ConsoleScreen.cpp @@ -1,13 +1,13 @@ -#include "ConsoleScreen.h" -#include "../Gui.h" -#include "../../Minecraft.h" -#include "../../player/LocalPlayer.h" -#include "../../../platform/input/Keyboard.h" -#include "../../../world/level/Level.h" -#include "../../../network/RakNetInstance.h" -#include "../../../network/ServerSideNetworkHandler.h" -#include "../../../network/packet/ChatPacket.h" -#include "../../../platform/log.h" +#include "ConsoleScreen.hpp" +#include "client/gui/Gui.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" +#include "platform/input/Keyboard.hpp" +#include "world/level/Level.hpp" +#include "network/RakNetInstance.hpp" +#include "network/ServerSideNetworkHandler.hpp" +#include "network/packet/ChatPacket.hpp" +#include "platform/log.hpp" #include #include diff --git a/src/client/gui/screens/ConsoleScreen.h b/src/client/gui/screens/ConsoleScreen.hpp similarity index 95% rename from src/client/gui/screens/ConsoleScreen.h rename to src/client/gui/screens/ConsoleScreen.hpp index f366ff9..4defcfc 100644 --- a/src/client/gui/screens/ConsoleScreen.h +++ b/src/client/gui/screens/ConsoleScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Screen.h" +#include "client/gui/Screen.hpp" #include class ConsoleScreen: public Screen diff --git a/src/client/gui/screens/CreditsScreen.cpp b/src/client/gui/screens/CreditsScreen.cpp index 02114da..a87e053 100644 --- a/src/client/gui/screens/CreditsScreen.cpp +++ b/src/client/gui/screens/CreditsScreen.cpp @@ -1,10 +1,10 @@ -#include "CreditsScreen.h" -#include "StartMenuScreen.h" -#include "OptionsScreen.h" -#include "../../Minecraft.h" -#include "../components/Button.h" -#include "../components/ImageButton.h" -#include "platform/input/Mouse.h" +#include "CreditsScreen.hpp" +#include "StartMenuScreen.hpp" +#include "OptionsScreen.hpp" +#include "client/Minecraft.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "platform/input/Mouse.hpp" CreditsScreen::CreditsScreen() : bHeader(NULL), btnBack(NULL) diff --git a/src/client/gui/screens/CreditsScreen.h b/src/client/gui/screens/CreditsScreen.hpp similarity index 87% rename from src/client/gui/screens/CreditsScreen.h rename to src/client/gui/screens/CreditsScreen.hpp index 8739307..0a035f5 100644 --- a/src/client/gui/screens/CreditsScreen.h +++ b/src/client/gui/screens/CreditsScreen.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../Screen.h" -#include "../components/Button.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/Button.hpp" class ImageButton; diff --git a/src/client/gui/screens/DeathScreen.cpp b/src/client/gui/screens/DeathScreen.cpp index 411b148..cbdcd2a 100755 --- a/src/client/gui/screens/DeathScreen.cpp +++ b/src/client/gui/screens/DeathScreen.cpp @@ -1,83 +1,83 @@ -#include "DeathScreen.h" -#include "ScreenChooser.h" -#include "../components/Button.h" -#include "../../Minecraft.h" -#include "../../player/LocalPlayer.h" -#include "../../../platform/time.h" - -static const int WAIT_TICKS = 30; - -DeathScreen::DeathScreen() -: bRespawn(0), - bTitle(0), - _hasChosen(false), - _tick(0) -{ -} - -DeathScreen::~DeathScreen() -{ - delete bRespawn; - delete bTitle; -} - -void DeathScreen::init() -{ - if (/* minecraft->useTouchscreen() */ true) { - bRespawn = new Touch::TButton(1, "Respawn!"); - bTitle = new Touch::TButton(2, "Main menu"); - } else { - bRespawn = new Button(1, "Respawn!"); - bTitle = new Button(2, "Main menu"); - } - buttons.push_back(bRespawn); - buttons.push_back(bTitle); - - tabButtons.push_back(bRespawn); - tabButtons.push_back(bTitle); -} - -void DeathScreen::setupPositions() -{ - bRespawn->width = bTitle->width = width / 4; - - bRespawn->y = bTitle->y = height / 2; - bRespawn->x = width/2 - bRespawn->width - 10; - bTitle->x = width/2 + 10; - - LOGI("xyz: %d, %d (%d, %d)\n", bTitle->x, bTitle->y, width, height); -} - -void DeathScreen::tick() { - ++_tick; -} - -void DeathScreen::render( int xm, int ym, float a ) -{ - fillGradient(0, 0, width, height, 0x60500000, 0xa0803030); - - glPushMatrix2(); - glScalef2(2, 2, 2); - drawCenteredString(font, "You died!", width / 2 / 2, height / 8, 0xffffff); - glPopMatrix2(); - - if (_tick >= WAIT_TICKS) - Screen::render(xm, ym, a); -} - -void DeathScreen::buttonClicked( Button* button ) -{ - if (_tick < WAIT_TICKS) return; - - if (button == bRespawn) { - //RespawnPacket packet(); - //minecraft->raknetInstance->send(packet); - - minecraft->player->respawn(); - //minecraft->raknetInstance->send(); - minecraft->setScreen(NULL); - } - - if (button == bTitle) - minecraft->leaveGame(); -} +#include "DeathScreen.hpp" +#include "ScreenChooser.hpp" +#include "client/gui/components/Button.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" +#include "platform/time.hpp" + +static const int WAIT_TICKS = 30; + +DeathScreen::DeathScreen() +: bRespawn(0), + bTitle(0), + _hasChosen(false), + _tick(0) +{ +} + +DeathScreen::~DeathScreen() +{ + delete bRespawn; + delete bTitle; +} + +void DeathScreen::init() +{ + if (/* minecraft->useTouchscreen() */ true) { + bRespawn = new Touch::TButton(1, "Respawn!"); + bTitle = new Touch::TButton(2, "Main menu"); + } else { + bRespawn = new Button(1, "Respawn!"); + bTitle = new Button(2, "Main menu"); + } + buttons.push_back(bRespawn); + buttons.push_back(bTitle); + + tabButtons.push_back(bRespawn); + tabButtons.push_back(bTitle); +} + +void DeathScreen::setupPositions() +{ + bRespawn->width = bTitle->width = width / 4; + + bRespawn->y = bTitle->y = height / 2; + bRespawn->x = width/2 - bRespawn->width - 10; + bTitle->x = width/2 + 10; + + LOGI("xyz: %d, %d (%d, %d)\n", bTitle->x, bTitle->y, width, height); +} + +void DeathScreen::tick() { + ++_tick; +} + +void DeathScreen::render( int xm, int ym, float a ) +{ + fillGradient(0, 0, width, height, 0x60500000, 0xa0803030); + + glPushMatrix2(); + glScalef2(2, 2, 2); + drawCenteredString(font, "You died!", width / 2 / 2, height / 8, 0xffffff); + glPopMatrix2(); + + if (_tick >= WAIT_TICKS) + Screen::render(xm, ym, a); +} + +void DeathScreen::buttonClicked( Button* button ) +{ + if (_tick < WAIT_TICKS) return; + + if (button == bRespawn) { + //RespawnPacket packet(); + //minecraft->raknetInstance->send(packet); + + minecraft->player->respawn(); + //minecraft->raknetInstance->send(); + minecraft->setScreen(NULL); + } + + if (button == bTitle) + minecraft->leaveGame(); +} diff --git a/src/client/gui/screens/DeathScreen.h b/src/client/gui/screens/DeathScreen.hpp similarity index 90% rename from src/client/gui/screens/DeathScreen.h rename to src/client/gui/screens/DeathScreen.hpp index ba1e6ed..7dc11c5 100755 --- a/src/client/gui/screens/DeathScreen.h +++ b/src/client/gui/screens/DeathScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Screen.h" +#include "client/gui/Screen.hpp" class Button; class DeathScreen: public Screen diff --git a/src/client/gui/screens/DialogDefinitions.h b/src/client/gui/screens/DialogDefinitions.hpp similarity index 100% rename from src/client/gui/screens/DialogDefinitions.h rename to src/client/gui/screens/DialogDefinitions.hpp diff --git a/src/client/gui/screens/DisconnectionScreen.h b/src/client/gui/screens/DisconnectionScreen.hpp similarity index 87% rename from src/client/gui/screens/DisconnectionScreen.h rename to src/client/gui/screens/DisconnectionScreen.hpp index fb2a331..f78351f 100755 --- a/src/client/gui/screens/DisconnectionScreen.h +++ b/src/client/gui/screens/DisconnectionScreen.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../Screen.h" -#include "../Font.h" -#include "../components/Button.h" -#include "../../Minecraft.h" +#include "client/gui/Screen.hpp" +#include "client/gui/Font.hpp" +#include "client/gui/components/Button.hpp" +#include "client/Minecraft.hpp" #include class DisconnectionScreen: public Screen diff --git a/src/client/gui/screens/FurnaceScreen.cpp b/src/client/gui/screens/FurnaceScreen.cpp index 58d6df2..6d3e5ec 100755 --- a/src/client/gui/screens/FurnaceScreen.cpp +++ b/src/client/gui/screens/FurnaceScreen.cpp @@ -1,555 +1,555 @@ -#include "FurnaceScreen.h" -#include "crafting/PaneCraftingScreen.h" -#include "../Screen.h" -#include "../components/NinePatch.h" -#include "../../Minecraft.h" -#include "../../player/LocalPlayer.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/entity/ItemRenderer.h" -#include "../../../world/item/Item.h" -#include "../../../world/item/crafting/Recipes.h" -#include "../../../world/item/ItemCategory.h" -#include "../../../world/entity/player/Inventory.h" -#include "../../../world/entity/item/ItemEntity.h" -#include "../../../world/level/Level.h" -#include "../../../world/item/DyePowderItem.h" -#include "../../../world/item/crafting/FurnaceRecipes.h" -#include "../../../world/level/tile/entity/FurnaceTileEntity.h" -#include "../../../locale/I18n.h" -#include "../../../util/StringUtils.h" -#include "../../../world/inventory/FurnaceMenu.h" -#include "../../../network/packet/ContainerSetSlotPacket.h" -#include "../../../network/RakNetInstance.h" - -static int heldMs = -1; -static int percent = -1; -static const float MaxHoldMs = 500.0f; -static const int MinChargeMs = 200; - -static void setIfNotSet(bool& ref, bool condition) { - ref = (ref || condition); -} - -const int descFrameWidth = 100; - -const int rgbActive = 0xfff0f0f0; -const int rgbInactive = 0xc0635558; -const int rgbInactiveShadow = 0xc0aaaaaa; - -#ifdef __APPLE__ - static const float BorderPixels = 4; - #ifdef DEMO_MODE - static const float BlockPixels = 22; - #else - static const float BlockPixels = 22; - #endif -#else - static const float BorderPixels = 4; - static const float BlockPixels = 24; -#endif -static const int ItemSize = (int)(BlockPixels + 2*BorderPixels); - -static const int Bx = 10; // Border Frame width -static const int By = 6; // Border Frame height - - -FurnaceScreen::FurnaceScreen(Player* player, FurnaceTileEntity* furnace) -: super(new FurnaceMenu(furnace)), //@huge @attn - inventoryPane(NULL), - btnFuel(FurnaceTileEntity::SLOT_FUEL), - btnIngredient(FurnaceTileEntity::SLOT_INGREDIENT), - btnResult(FurnaceTileEntity::SLOT_RESULT), - btnClose(4, ""), - bHeader (5, "Furnace"), - guiBackground(NULL), - guiSlot(NULL), - guiSlotMarked(NULL), - guiSlotMarker(NULL), - guiPaneFrame(NULL), - player(player), - furnace(furnace), - selectedSlot(FurnaceTileEntity::SLOT_INGREDIENT), - doRecreatePane(false), - lastBurnTypeId(0), - descWidth(90) - //guiSlotItem(NULL), - //guiSlotItemSelected(NULL) -{ - //LOGI("Creating FurnaceScreen with %p, %d\n", furnace, furnace->runningId); -} - -FurnaceScreen::~FurnaceScreen() { - clearItems(); - - delete inventoryPane; - - delete guiBackground; - delete guiSlot; - delete guiSlotMarked; - delete guiSlotMarker; - delete guiPaneFrame; - - delete menu; - - if (furnace->clientSideOnly) - delete furnace; -} - -void FurnaceScreen::init() { - super::init(); - //printf("-> %d\n", width/2); - - ImageDef def; - def.name = "gui/spritesheet.png"; - def.x = 0; - def.y = 1; - def.width = def.height = 18; - def.setSrc(IntRectangle(60, 0, 18, 18)); - btnClose.setImageDef(def, true); - btnClose.scaleWhenPressed = false; - - buttons.push_back(&bHeader); - buttons.push_back(&btnIngredient); - buttons.push_back(&btnFuel); - buttons.push_back(&btnResult); - buttons.push_back(&btnClose); - - // GUI - nine patches - NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); - - guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); - guiSlot = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 3, 3); - guiSlotMarked = builder.createSymmetrical(IntRectangle(0, 44, 8, 8), 3, 3); - guiSlotMarker = builder.createSymmetrical(IntRectangle(10, 42, 16, 16), 5, 5); - guiPaneFrame = builder.createSymmetrical(IntRectangle(28, 42, 4, 4), 1, 1)->setExcluded(1 << 4); - - recheckRecipes(); -} - -void FurnaceScreen::setupPositions() { - // Left - Categories - bHeader.x = bHeader.y = 0; - bHeader.width = width;// - bDone.w; - - btnClose.width = btnClose.height = 19; - btnClose.x = width - btnClose.width; - btnClose.y = 0; - - // Inventory pane - const int maxWidth = width/2 - Bx - Bx; - const int InventoryColumns = maxWidth / ItemSize; - const int realWidth = InventoryColumns * ItemSize; - const int paneWidth = realWidth + Bx + Bx; - const int realBx = (paneWidth - realWidth) / 2; - - inventoryPaneRect = IntRectangle(realBx, -#ifdef __APPLE__ - 26 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-28); -#else - 26 + By, realWidth, height-By-By-28); -#endif - - // Right - Slots, description etc - { - int cx = (inventoryPaneRect.x + inventoryPaneRect.w); - int rightWidth = width - cx; - - btnIngredient.width = btnFuel.width = btnResult.width = (int)guiSlot->getWidth(); - btnIngredient.height = btnFuel.height = btnResult.height = (int)guiSlot->getHeight(); - int space = rightWidth - (2 * btnFuel.width + 40); - int margin = space/2; - int bx0 = cx + margin; - int bx1 = width - margin - btnFuel.width; - btnIngredient.x = btnFuel.x = bx0; - descWidth = (float)Mth::Min(90, width - bx1 + 24 - 4); - - int by = 36;// + (height-20) / 6; - btnIngredient.y = by; - btnFuel.y = by + 20 + btnFuel.height; - - btnResult.x = bx1; - btnResult.y = (btnIngredient.y + btnFuel.y) / 2; - - guiBackground->setSize((float)width, (float)height); - guiSlotMarker->setSize((float)btnFuel.width + 4, (float)btnFuel.height + 4); - - recheckRecipes(); - setupInventoryPane(); - } -} - -void FurnaceScreen::tick() { - if (inventoryPane) - inventoryPane->tick(); - - if (doRecreatePane) { - recheckRecipes(); - setupInventoryPane(); - doRecreatePane = false; - } -} - -void FurnaceScreen::handleRenderPane(Touch::InventoryPane* pane, Tesselator& t, int xm, int ym, float a) { - if (pane) { - int ms, id; - pane->markerIndex = -1; - if (pane->queryHoldTime(&id, &ms)) { - heldMs = ms; - - const ItemInstance* item = inventoryItems[id]; - int count = (item && !item->isNull())? item->count : 0; - float maxHoldMs = item? 700 + 10 * item->count: MaxHoldMs; - - if (count > 1 && canMoveToFurnace(id, item)) { - float share = (heldMs-MinChargeMs) / maxHoldMs; - pane->markerType = 1;//(heldMs >= MinChargeMs)? 1 : 0; - pane->markerIndex = id; - pane->markerShare = Mth::Max(share, 0.0f); - - percent = (int)Mth::clamp(100.0f * share, 0.0f, 100.0f); - if (percent >= 100) { - addItem(pane, id); - } - } - } - - pane->render(xm, ym, a); - guiPaneFrame->draw(t, (float)(pane->rect.x - 1), (float)(pane->rect.y - 1)); - //LOGI("query-iv: %d, %d\n", gridId, heldMs); - - } -} - -void FurnaceScreen::render(int xm, int ym, float a) { - const int N = 5; - static StopwatchNLast r(N); - //renderBackground(); - - updateResult(furnace->getItem(FurnaceTileEntity::SLOT_INGREDIENT)); - - Tesselator& t = Tesselator::instance; - guiBackground->draw(t, 0, 0); - glEnable2(GL_ALPHA_TEST); - - // Buttons (Left side + crafting) - super::render(xm, ym, a); - - handleRenderPane(inventoryPane, t, xm, ym, a); - - t.colorABGR(0xffffffff); - - drawSlotItemAt(t, furnace->getItem(btnIngredient.id), btnIngredient.x, btnIngredient.y, btnIngredient.id == selectedSlot); - drawSlotItemAt(t, furnace->getItem(btnFuel.id), btnFuel.x, btnFuel.y, btnFuel.id == selectedSlot); - - const ItemInstance* resultSlotItem = furnace->getItem(btnResult.id); - drawSlotItemAt(t, resultSlotItem, btnResult.x, btnResult.y, btnResult.id == selectedSlot); - - if (!burnResult.isNull()) { - if (!resultSlotItem || resultSlotItem->isNull()) { - glEnable2(GL_BLEND); - t.beginOverride(); - t.colorABGR(0x33ffffff); - t.noColor(); - ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, &burnResult, (float)(btnResult.x + 7), (float)(btnResult.y + 8), true); - t.endOverrideAndDraw(); - glDisable2(GL_BLEND); - } - minecraft->font->drawWordWrap(currentItemDesc, (float)btnResult.x - 24, (float)(btnResult.y + btnResult.height + 6), descWidth, rgbActive); - } - - minecraft->textures->loadAndBindTexture("gui/spritesheet.png"); - int yy = btnResult.y + 8; - int fpx = furnace->getLitProgress(14) + 2; - int xx0 = btnIngredient.x + 8; - blit(xx0, yy, 80, 40, 16, 16, 32, 32); - blit(xx0, yy + 16 - fpx, 112, 40 + 32-fpx-fpx, 16, fpx, 32, fpx+fpx); - - int bpx = furnace->getBurnProgress(24); - int xx1 = btnIngredient.x + 40; - blit(xx1, yy, 144, 40, 24, 16, 48, 32); - blit(xx1, yy, 144, 72, bpx, 16, bpx+bpx, 32); -} - -void FurnaceScreen::buttonClicked(Button* button) { - int slot = button->id; - - if (button == &btnClose) { - minecraft->player->closeContainer(); - } - - if (slot >= FurnaceTileEntity::SLOT_INGREDIENT - && slot <= FurnaceTileEntity::SLOT_RESULT) { - // Can't highlight the Result slot - int oldSlot = selectedSlot; - if (slot != FurnaceTileEntity::SLOT_RESULT) - selectedSlot = slot; - - if (oldSlot == selectedSlot) - takeAndClearSlot(slot); - } -} - -static bool sortCanCraftPredicate(const CItem* a, const CItem* b) { - //if (a->maxBuildCount == 0 && b->maxBuildCount > 0) return false; - //if (b->maxBuildCount == 0 && a->maxBuildCount > 0) return true; - return a->sortText < b->sortText; -} - -void FurnaceScreen::recheckRecipes() -{ - clearItems(); - - Stopwatch w; - w.start(); - - const FurnaceRecipes* recipes = FurnaceRecipes::getInstance(); - ItemPack ip; - // Check for fuel, and items to burn - if (minecraft->player && minecraft->player->inventory) { - Inventory* inv = (minecraft->player)->inventory; - - for (int i = Inventory::MAX_SELECTION_SIZE; i < inv->getContainerSize(); ++i) { - if (ItemInstance* item = inv->getItem(i)) { - // Fuel material - if (FurnaceTileEntity::isFuel(*item)) { - CItem* ci = new CItem(*item, NULL, "");//item->getName()); - //LOGI("Adding fuel: %s\n", item->getName()); - listFuel.push_back(ci); - } - // Ingredient/burn material - if (recipes->isFurnaceItem(item->id)) { - CItem* ci = new CItem(*item, NULL, "");//item->getName()); - //LOGI("Adding item to burn: %s\n", item->getName()); - listIngredient.push_back(ci); - } - //ip.add(ItemPack::getIdForItemInstance(item), item->count); - } - } - } - - ip.print(); - - w.stop(); - w.printEvery(1, "> craft "); - - updateItems(); - //std::stable_sort(_categories[c].begin(), _categories[c].end(), sortCanCraftPredicate); -} - -bool FurnaceScreen::addItem(const Touch::InventoryPane* forPane, int itemIndex) { - //LOGI("items.size, index: %d, %d\n", inventoryItems.size(), itemIndex); - const ItemInstance* item = inventoryItems[itemIndex]; - if (!item || item->isNull()) return false; - - setIfNotSet(doRecreatePane, handleAddItem(selectedSlot, item)); - - if (doRecreatePane) { - int slot = inventorySlots[itemIndex]; - if (player->inventory->getItem(slot)) { - // fix: if we deplete a slot we didn't click on (but had same type), - // we need to NULLify the slot that actually was depleted - for (unsigned int i = 0; i < inventorySlots.size(); ++i) { - slot = inventorySlots[i]; - if (!player->inventory->getItem(slot)) { - LOGI("Changed! removing slot %d (was: %d)\n", i, itemIndex); - itemIndex = i; - break; - } - } - } - inventoryItems[itemIndex] = NULL; - } - //LOGI("Pressed button: %d\n", itemIndexInCurrentCategory); - return true; -} - -bool FurnaceScreen::isAllowed( int slot ) -{ //LOGI("items.size, index: %d, %d\n", inventoryItems.size(), slot); - if (slot >= (int)inventoryItems.size()) return false; - if (!inventoryItems[slot]) return false; - const ItemInstance& item = *inventoryItems[slot]; - - if (selectedSlot == btnFuel.id) - return (FurnaceTileEntity::getBurnDuration(item) > 0); - else - if (selectedSlot == btnIngredient.id) - return !FurnaceRecipes::getInstance()->getResult(item.id).isNull(); - return false; -} - -bool FurnaceScreen::renderGameBehind() -{ - return false; -} - -std::vector FurnaceScreen::getItems( const Touch::InventoryPane* forPane ) -{ - return inventoryItems; -} - -void FurnaceScreen::clearItems() -{ - for (unsigned int i = 0; i < listFuel.size(); ++i) delete listFuel[i]; - for (unsigned int i = 0; i < listIngredient.size(); ++i) delete listIngredient[i]; - listFuel.clear(); - listIngredient.clear(); -} - -void FurnaceScreen::updateItems() { - inventoryItems.clear(); - inventorySlots.clear(); - - ItemList all(listFuel.begin(), listFuel.end()); - all.insert(all.end(), listIngredient.begin(), listIngredient.end()); - for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) { - ItemInstance* item = minecraft->player->inventory->getItem(i); - if (!item) continue; - //LOGI("ItemInstance (%p) Id/aux/count: %d, %d, %d\n", item, item->id, item->getAuxValue(), item->count); - bool added = false; - for (unsigned int j = 0; j < listFuel.size(); ++j) { - if (ItemInstance::matches(item, &listFuel[j]->item)) { - inventorySlots.push_back(i); - inventoryItems.push_back(item); - added = true; - break; - } - } - if (added) continue; - for (unsigned int j = 0; j < listIngredient.size(); ++j) { - if (ItemInstance::matches(item, &listIngredient[j]->item)) { - inventorySlots.push_back(i); - inventoryItems.push_back(item); - added = true; - break; - } - } - } -} - -bool FurnaceScreen::canMoveToFurnace(int inventorySlot, const ItemInstance* item) { - if (!isAllowed(inventorySlot)) return false; - ItemInstance* jitem = furnace->getItem(selectedSlot); - if (!jitem || jitem->isNull()) return true; - if (ItemInstance::isStackable(item, jitem) && jitem->count < jitem->getMaxStackSize()) - return true; - - return false; -} - -void FurnaceScreen::updateResult( const ItemInstance* item ) -{ - const ItemInstance* result = furnace->getItem(FurnaceTileEntity::SLOT_RESULT); - if (!result->isNull()) { - int id = result->id; - if (id == lastBurnTypeId) return; - currentItemDesc = I18n::getDescriptionString(*result); - lastBurnTypeId = id; - this->burnResult = *result; - } else { - int id = (item? item->id : 0); - if (id == lastBurnTypeId) return; - - ItemInstance burnResult = FurnaceRecipes::getInstance()->getResult(id); - if (!burnResult.isNull()) - currentItemDesc = I18n::getDescriptionString(burnResult); - else - currentItemDesc = ""; - lastBurnTypeId = id; - this->burnResult = burnResult; - } -} - -void FurnaceScreen::setupInventoryPane() -{ - // IntRectangle(0, 0, 100, 100) - if (inventoryPane) delete inventoryPane; - inventoryPane = new Touch::InventoryPane(this, minecraft, inventoryPaneRect, inventoryPaneRect.w, BorderPixels, inventoryItems.size(), ItemSize, (int)BorderPixels); - inventoryPane->fillMarginX = 0; - inventoryPane->fillMarginY = 0; - guiPaneFrame->setSize((float)inventoryPaneRect.w + 2, (float)inventoryPaneRect.h + 2); - //LOGI("Creating new pane: %d %p\n", inventoryItems.size(), inventoryPane); -} - -void FurnaceScreen::drawSlotItemAt( Tesselator& t, const ItemInstance* item, int x, int y, bool selected) -{ - float xx = (float)x; - float yy = (float)y; - - (selected? guiSlot/*Marked*/ : guiSlot)->draw(t, xx, yy); - - if (selected) - guiSlotMarker->draw(t, xx - 2, yy - 2); - - if (item && !item->isNull()) { - ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, xx + 7, yy + 8, true); - minecraft->gui.renderSlotText(item, xx + 3, yy + 3, true, true); - } -} - -ItemInstance FurnaceScreen::moveOver(const ItemInstance* item, int maxCount) { - int wantedCount = item->count * percent / 100; - if (!wantedCount || heldMs < MinChargeMs) - wantedCount = 1; - - wantedCount = Mth::Min(wantedCount, maxCount); - - ItemInstance removed(item->id, wantedCount, item->getAuxValue()); - int oldSize = minecraft->player->inventory->getNumEmptySlots(); - if (minecraft->player->inventory->removeResource(removed)) { - int newSize = minecraft->player->inventory->getNumEmptySlots(); - setIfNotSet(doRecreatePane, newSize != oldSize); - return removed; - } - return ItemInstance(); -} - -void FurnaceScreen::takeAndClearSlot( int slot ) -{ - //if (selectedSlot == btnBurn.id && !furnace->isSlotEmpty(btnBurn.id)) - ItemInstance oldItem = *furnace->getItem(slot); - ItemInstance blank; - - furnace->setItem(slot, &blank); - if (minecraft->level->isClientSide) { - ContainerSetSlotPacket p(menu->containerId, slot, blank); - minecraft->raknetInstance->send(p); - } - - int oldSize = minecraft->player->inventory->getNumEmptySlots(); - - if (!minecraft->player->inventory->add(&oldItem)) - minecraft->player->drop(new ItemInstance(oldItem), false); - - int newSize = minecraft->player->inventory->getNumEmptySlots(); - setIfNotSet(doRecreatePane, newSize != oldSize); -} - -bool FurnaceScreen::handleAddItem( int slot, const ItemInstance* item ) -{ - ItemInstance* furnaceItem = furnace->getItem(slot); - int oldSize = minecraft->player->inventory->getNumEmptySlots(); - - if (item->id == furnaceItem->id) { - // If stackable, stack them! Else deny the addition - const int maxMovedCount = furnaceItem->getMaxStackSize() - furnaceItem->count; - if (maxMovedCount <= 0) - return false; - - ItemInstance added = moveOver(item, maxMovedCount); - furnaceItem->count += added.count; - } else { - if (!furnace->isSlotEmpty(slot)) - return false;//takeAndClearSlot(slot); - - ItemInstance moved = moveOver(item, item->getMaxStackSize()); - player->containerMenu->setSlot(slot, &moved); - } - - if (minecraft->level->isClientSide) { - ContainerSetSlotPacket p(menu->containerId, slot, *furnaceItem); - minecraft->raknetInstance->send(p); - } - - int newSize = minecraft->player->inventory->getNumEmptySlots(); - return (newSize != oldSize); -} +#include "FurnaceScreen.hpp" +#include "crafting/PaneCraftingScreen.hpp" +#include "client/gui/Screen.hpp" +#include "client/gui/components/NinePatch.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "world/item/Item.hpp" +#include "world/item/crafting/Recipes.hpp" +#include "world/item/ItemCategory.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/level/Level.hpp" +#include "world/item/DyePowderItem.hpp" +#include "world/item/crafting/FurnaceRecipes.hpp" +#include "world/level/tile/entity/FurnaceTileEntity.hpp" +#include "locale/I18n.hpp" +#include "util/StringUtils.hpp" +#include "world/inventory/FurnaceMenu.hpp" +#include "network/packet/ContainerSetSlotPacket.hpp" +#include "network/RakNetInstance.hpp" + +static int heldMs = -1; +static int percent = -1; +static const float MaxHoldMs = 500.0f; +static const int MinChargeMs = 200; + +static void setIfNotSet(bool& ref, bool condition) { + ref = (ref || condition); +} + +const int descFrameWidth = 100; + +const int rgbActive = 0xfff0f0f0; +const int rgbInactive = 0xc0635558; +const int rgbInactiveShadow = 0xc0aaaaaa; + +#ifdef __APPLE__ + static const float BorderPixels = 4; + #ifdef DEMO_MODE + static const float BlockPixels = 22; + #else + static const float BlockPixels = 22; + #endif +#else + static const float BorderPixels = 4; + static const float BlockPixels = 24; +#endif +static const int ItemSize = (int)(BlockPixels + 2*BorderPixels); + +static const int Bx = 10; // Border Frame width +static const int By = 6; // Border Frame height + + +FurnaceScreen::FurnaceScreen(Player* player, FurnaceTileEntity* furnace) +: super(new FurnaceMenu(furnace)), //@huge @attn + inventoryPane(NULL), + btnFuel(FurnaceTileEntity::SLOT_FUEL), + btnIngredient(FurnaceTileEntity::SLOT_INGREDIENT), + btnResult(FurnaceTileEntity::SLOT_RESULT), + btnClose(4, ""), + bHeader (5, "Furnace"), + guiBackground(NULL), + guiSlot(NULL), + guiSlotMarked(NULL), + guiSlotMarker(NULL), + guiPaneFrame(NULL), + player(player), + furnace(furnace), + selectedSlot(FurnaceTileEntity::SLOT_INGREDIENT), + doRecreatePane(false), + lastBurnTypeId(0), + descWidth(90) + //guiSlotItem(NULL), + //guiSlotItemSelected(NULL) +{ + //LOGI("Creating FurnaceScreen with %p, %d\n", furnace, furnace->runningId); +} + +FurnaceScreen::~FurnaceScreen() { + clearItems(); + + delete inventoryPane; + + delete guiBackground; + delete guiSlot; + delete guiSlotMarked; + delete guiSlotMarker; + delete guiPaneFrame; + + delete menu; + + if (furnace->clientSideOnly) + delete furnace; +} + +void FurnaceScreen::init() { + super::init(); + //printf("-> %d\n", width/2); + + ImageDef def; + def.name = "gui/spritesheet.png"; + def.x = 0; + def.y = 1; + def.width = def.height = 18; + def.setSrc(IntRectangle(60, 0, 18, 18)); + btnClose.setImageDef(def, true); + btnClose.scaleWhenPressed = false; + + buttons.push_back(&bHeader); + buttons.push_back(&btnIngredient); + buttons.push_back(&btnFuel); + buttons.push_back(&btnResult); + buttons.push_back(&btnClose); + + // GUI - nine patches + NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); + + guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); + guiSlot = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 3, 3); + guiSlotMarked = builder.createSymmetrical(IntRectangle(0, 44, 8, 8), 3, 3); + guiSlotMarker = builder.createSymmetrical(IntRectangle(10, 42, 16, 16), 5, 5); + guiPaneFrame = builder.createSymmetrical(IntRectangle(28, 42, 4, 4), 1, 1)->setExcluded(1 << 4); + + recheckRecipes(); +} + +void FurnaceScreen::setupPositions() { + // Left - Categories + bHeader.x = bHeader.y = 0; + bHeader.width = width;// - bDone.w; + + btnClose.width = btnClose.height = 19; + btnClose.x = width - btnClose.width; + btnClose.y = 0; + + // Inventory pane + const int maxWidth = width/2 - Bx - Bx; + const int InventoryColumns = maxWidth / ItemSize; + const int realWidth = InventoryColumns * ItemSize; + const int paneWidth = realWidth + Bx + Bx; + const int realBx = (paneWidth - realWidth) / 2; + + inventoryPaneRect = IntRectangle(realBx, +#ifdef __APPLE__ + 26 + By - ((width==240)?1:0), realWidth, ((width==240)?1:0) + height-By-By-28); +#else + 26 + By, realWidth, height-By-By-28); +#endif + + // Right - Slots, description etc + { + int cx = (inventoryPaneRect.x + inventoryPaneRect.w); + int rightWidth = width - cx; + + btnIngredient.width = btnFuel.width = btnResult.width = (int)guiSlot->getWidth(); + btnIngredient.height = btnFuel.height = btnResult.height = (int)guiSlot->getHeight(); + int space = rightWidth - (2 * btnFuel.width + 40); + int margin = space/2; + int bx0 = cx + margin; + int bx1 = width - margin - btnFuel.width; + btnIngredient.x = btnFuel.x = bx0; + descWidth = (float)Mth::Min(90, width - bx1 + 24 - 4); + + int by = 36;// + (height-20) / 6; + btnIngredient.y = by; + btnFuel.y = by + 20 + btnFuel.height; + + btnResult.x = bx1; + btnResult.y = (btnIngredient.y + btnFuel.y) / 2; + + guiBackground->setSize((float)width, (float)height); + guiSlotMarker->setSize((float)btnFuel.width + 4, (float)btnFuel.height + 4); + + recheckRecipes(); + setupInventoryPane(); + } +} + +void FurnaceScreen::tick() { + if (inventoryPane) + inventoryPane->tick(); + + if (doRecreatePane) { + recheckRecipes(); + setupInventoryPane(); + doRecreatePane = false; + } +} + +void FurnaceScreen::handleRenderPane(Touch::InventoryPane* pane, Tesselator& t, int xm, int ym, float a) { + if (pane) { + int ms, id; + pane->markerIndex = -1; + if (pane->queryHoldTime(&id, &ms)) { + heldMs = ms; + + const ItemInstance* item = inventoryItems[id]; + int count = (item && !item->isNull())? item->count : 0; + float maxHoldMs = item? 700 + 10 * item->count: MaxHoldMs; + + if (count > 1 && canMoveToFurnace(id, item)) { + float share = (heldMs-MinChargeMs) / maxHoldMs; + pane->markerType = 1;//(heldMs >= MinChargeMs)? 1 : 0; + pane->markerIndex = id; + pane->markerShare = Mth::Max(share, 0.0f); + + percent = (int)Mth::clamp(100.0f * share, 0.0f, 100.0f); + if (percent >= 100) { + addItem(pane, id); + } + } + } + + pane->render(xm, ym, a); + guiPaneFrame->draw(t, (float)(pane->rect.x - 1), (float)(pane->rect.y - 1)); + //LOGI("query-iv: %d, %d\n", gridId, heldMs); + + } +} + +void FurnaceScreen::render(int xm, int ym, float a) { + const int N = 5; + static StopwatchNLast r(N); + //renderBackground(); + + updateResult(furnace->getItem(FurnaceTileEntity::SLOT_INGREDIENT)); + + Tesselator& t = Tesselator::instance; + guiBackground->draw(t, 0, 0); + glEnable2(GL_ALPHA_TEST); + + // Buttons (Left side + crafting) + super::render(xm, ym, a); + + handleRenderPane(inventoryPane, t, xm, ym, a); + + t.colorABGR(0xffffffff); + + drawSlotItemAt(t, furnace->getItem(btnIngredient.id), btnIngredient.x, btnIngredient.y, btnIngredient.id == selectedSlot); + drawSlotItemAt(t, furnace->getItem(btnFuel.id), btnFuel.x, btnFuel.y, btnFuel.id == selectedSlot); + + const ItemInstance* resultSlotItem = furnace->getItem(btnResult.id); + drawSlotItemAt(t, resultSlotItem, btnResult.x, btnResult.y, btnResult.id == selectedSlot); + + if (!burnResult.isNull()) { + if (!resultSlotItem || resultSlotItem->isNull()) { + glEnable2(GL_BLEND); + t.beginOverride(); + t.colorABGR(0x33ffffff); + t.noColor(); + ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, &burnResult, (float)(btnResult.x + 7), (float)(btnResult.y + 8), true); + t.endOverrideAndDraw(); + glDisable2(GL_BLEND); + } + minecraft->font->drawWordWrap(currentItemDesc, (float)btnResult.x - 24, (float)(btnResult.y + btnResult.height + 6), descWidth, rgbActive); + } + + minecraft->textures->loadAndBindTexture("gui/spritesheet.png"); + int yy = btnResult.y + 8; + int fpx = furnace->getLitProgress(14) + 2; + int xx0 = btnIngredient.x + 8; + blit(xx0, yy, 80, 40, 16, 16, 32, 32); + blit(xx0, yy + 16 - fpx, 112, 40 + 32-fpx-fpx, 16, fpx, 32, fpx+fpx); + + int bpx = furnace->getBurnProgress(24); + int xx1 = btnIngredient.x + 40; + blit(xx1, yy, 144, 40, 24, 16, 48, 32); + blit(xx1, yy, 144, 72, bpx, 16, bpx+bpx, 32); +} + +void FurnaceScreen::buttonClicked(Button* button) { + int slot = button->id; + + if (button == &btnClose) { + minecraft->player->closeContainer(); + } + + if (slot >= FurnaceTileEntity::SLOT_INGREDIENT + && slot <= FurnaceTileEntity::SLOT_RESULT) { + // Can't highlight the Result slot + int oldSlot = selectedSlot; + if (slot != FurnaceTileEntity::SLOT_RESULT) + selectedSlot = slot; + + if (oldSlot == selectedSlot) + takeAndClearSlot(slot); + } +} + +static bool sortCanCraftPredicate(const CItem* a, const CItem* b) { + //if (a->maxBuildCount == 0 && b->maxBuildCount > 0) return false; + //if (b->maxBuildCount == 0 && a->maxBuildCount > 0) return true; + return a->sortText < b->sortText; +} + +void FurnaceScreen::recheckRecipes() +{ + clearItems(); + + Stopwatch w; + w.start(); + + const FurnaceRecipes* recipes = FurnaceRecipes::getInstance(); + ItemPack ip; + // Check for fuel, and items to burn + if (minecraft->player && minecraft->player->inventory) { + Inventory* inv = (minecraft->player)->inventory; + + for (int i = Inventory::MAX_SELECTION_SIZE; i < inv->getContainerSize(); ++i) { + if (ItemInstance* item = inv->getItem(i)) { + // Fuel material + if (FurnaceTileEntity::isFuel(*item)) { + CItem* ci = new CItem(*item, NULL, "");//item->getName()); + //LOGI("Adding fuel: %s\n", item->getName()); + listFuel.push_back(ci); + } + // Ingredient/burn material + if (recipes->isFurnaceItem(item->id)) { + CItem* ci = new CItem(*item, NULL, "");//item->getName()); + //LOGI("Adding item to burn: %s\n", item->getName()); + listIngredient.push_back(ci); + } + //ip.add(ItemPack::getIdForItemInstance(item), item->count); + } + } + } + + ip.print(); + + w.stop(); + w.printEvery(1, "> craft "); + + updateItems(); + //std::stable_sort(_categories[c].begin(), _categories[c].end(), sortCanCraftPredicate); +} + +bool FurnaceScreen::addItem(const Touch::InventoryPane* forPane, int itemIndex) { + //LOGI("items.size, index: %d, %d\n", inventoryItems.size(), itemIndex); + const ItemInstance* item = inventoryItems[itemIndex]; + if (!item || item->isNull()) return false; + + setIfNotSet(doRecreatePane, handleAddItem(selectedSlot, item)); + + if (doRecreatePane) { + int slot = inventorySlots[itemIndex]; + if (player->inventory->getItem(slot)) { + // fix: if we deplete a slot we didn't click on (but had same type), + // we need to NULLify the slot that actually was depleted + for (unsigned int i = 0; i < inventorySlots.size(); ++i) { + slot = inventorySlots[i]; + if (!player->inventory->getItem(slot)) { + LOGI("Changed! removing slot %d (was: %d)\n", i, itemIndex); + itemIndex = i; + break; + } + } + } + inventoryItems[itemIndex] = NULL; + } + //LOGI("Pressed button: %d\n", itemIndexInCurrentCategory); + return true; +} + +bool FurnaceScreen::isAllowed( int slot ) +{ //LOGI("items.size, index: %d, %d\n", inventoryItems.size(), slot); + if (slot >= (int)inventoryItems.size()) return false; + if (!inventoryItems[slot]) return false; + const ItemInstance& item = *inventoryItems[slot]; + + if (selectedSlot == btnFuel.id) + return (FurnaceTileEntity::getBurnDuration(item) > 0); + else + if (selectedSlot == btnIngredient.id) + return !FurnaceRecipes::getInstance()->getResult(item.id).isNull(); + return false; +} + +bool FurnaceScreen::renderGameBehind() +{ + return false; +} + +std::vector FurnaceScreen::getItems( const Touch::InventoryPane* forPane ) +{ + return inventoryItems; +} + +void FurnaceScreen::clearItems() +{ + for (unsigned int i = 0; i < listFuel.size(); ++i) delete listFuel[i]; + for (unsigned int i = 0; i < listIngredient.size(); ++i) delete listIngredient[i]; + listFuel.clear(); + listIngredient.clear(); +} + +void FurnaceScreen::updateItems() { + inventoryItems.clear(); + inventorySlots.clear(); + + ItemList all(listFuel.begin(), listFuel.end()); + all.insert(all.end(), listIngredient.begin(), listIngredient.end()); + for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) { + ItemInstance* item = minecraft->player->inventory->getItem(i); + if (!item) continue; + //LOGI("ItemInstance (%p) Id/aux/count: %d, %d, %d\n", item, item->id, item->getAuxValue(), item->count); + bool added = false; + for (unsigned int j = 0; j < listFuel.size(); ++j) { + if (ItemInstance::matches(item, &listFuel[j]->item)) { + inventorySlots.push_back(i); + inventoryItems.push_back(item); + added = true; + break; + } + } + if (added) continue; + for (unsigned int j = 0; j < listIngredient.size(); ++j) { + if (ItemInstance::matches(item, &listIngredient[j]->item)) { + inventorySlots.push_back(i); + inventoryItems.push_back(item); + added = true; + break; + } + } + } +} + +bool FurnaceScreen::canMoveToFurnace(int inventorySlot, const ItemInstance* item) { + if (!isAllowed(inventorySlot)) return false; + ItemInstance* jitem = furnace->getItem(selectedSlot); + if (!jitem || jitem->isNull()) return true; + if (ItemInstance::isStackable(item, jitem) && jitem->count < jitem->getMaxStackSize()) + return true; + + return false; +} + +void FurnaceScreen::updateResult( const ItemInstance* item ) +{ + const ItemInstance* result = furnace->getItem(FurnaceTileEntity::SLOT_RESULT); + if (!result->isNull()) { + int id = result->id; + if (id == lastBurnTypeId) return; + currentItemDesc = I18n::getDescriptionString(*result); + lastBurnTypeId = id; + this->burnResult = *result; + } else { + int id = (item? item->id : 0); + if (id == lastBurnTypeId) return; + + ItemInstance burnResult = FurnaceRecipes::getInstance()->getResult(id); + if (!burnResult.isNull()) + currentItemDesc = I18n::getDescriptionString(burnResult); + else + currentItemDesc = ""; + lastBurnTypeId = id; + this->burnResult = burnResult; + } +} + +void FurnaceScreen::setupInventoryPane() +{ + // IntRectangle(0, 0, 100, 100) + if (inventoryPane) delete inventoryPane; + inventoryPane = new Touch::InventoryPane(this, minecraft, inventoryPaneRect, inventoryPaneRect.w, BorderPixels, inventoryItems.size(), ItemSize, (int)BorderPixels); + inventoryPane->fillMarginX = 0; + inventoryPane->fillMarginY = 0; + guiPaneFrame->setSize((float)inventoryPaneRect.w + 2, (float)inventoryPaneRect.h + 2); + //LOGI("Creating new pane: %d %p\n", inventoryItems.size(), inventoryPane); +} + +void FurnaceScreen::drawSlotItemAt( Tesselator& t, const ItemInstance* item, int x, int y, bool selected) +{ + float xx = (float)x; + float yy = (float)y; + + (selected? guiSlot/*Marked*/ : guiSlot)->draw(t, xx, yy); + + if (selected) + guiSlotMarker->draw(t, xx - 2, yy - 2); + + if (item && !item->isNull()) { + ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, xx + 7, yy + 8, true); + minecraft->gui.renderSlotText(item, xx + 3, yy + 3, true, true); + } +} + +ItemInstance FurnaceScreen::moveOver(const ItemInstance* item, int maxCount) { + int wantedCount = item->count * percent / 100; + if (!wantedCount || heldMs < MinChargeMs) + wantedCount = 1; + + wantedCount = Mth::Min(wantedCount, maxCount); + + ItemInstance removed(item->id, wantedCount, item->getAuxValue()); + int oldSize = minecraft->player->inventory->getNumEmptySlots(); + if (minecraft->player->inventory->removeResource(removed)) { + int newSize = minecraft->player->inventory->getNumEmptySlots(); + setIfNotSet(doRecreatePane, newSize != oldSize); + return removed; + } + return ItemInstance(); +} + +void FurnaceScreen::takeAndClearSlot( int slot ) +{ + //if (selectedSlot == btnBurn.id && !furnace->isSlotEmpty(btnBurn.id)) + ItemInstance oldItem = *furnace->getItem(slot); + ItemInstance blank; + + furnace->setItem(slot, &blank); + if (minecraft->level->isClientSide) { + ContainerSetSlotPacket p(menu->containerId, slot, blank); + minecraft->raknetInstance->send(p); + } + + int oldSize = minecraft->player->inventory->getNumEmptySlots(); + + if (!minecraft->player->inventory->add(&oldItem)) + minecraft->player->drop(new ItemInstance(oldItem), false); + + int newSize = minecraft->player->inventory->getNumEmptySlots(); + setIfNotSet(doRecreatePane, newSize != oldSize); +} + +bool FurnaceScreen::handleAddItem( int slot, const ItemInstance* item ) +{ + ItemInstance* furnaceItem = furnace->getItem(slot); + int oldSize = minecraft->player->inventory->getNumEmptySlots(); + + if (item->id == furnaceItem->id) { + // If stackable, stack them! Else deny the addition + const int maxMovedCount = furnaceItem->getMaxStackSize() - furnaceItem->count; + if (maxMovedCount <= 0) + return false; + + ItemInstance added = moveOver(item, maxMovedCount); + furnaceItem->count += added.count; + } else { + if (!furnace->isSlotEmpty(slot)) + return false;//takeAndClearSlot(slot); + + ItemInstance moved = moveOver(item, item->getMaxStackSize()); + player->containerMenu->setSlot(slot, &moved); + } + + if (minecraft->level->isClientSide) { + ContainerSetSlotPacket p(menu->containerId, slot, *furnaceItem); + minecraft->raknetInstance->send(p); + } + + int newSize = minecraft->player->inventory->getNumEmptySlots(); + return (newSize != oldSize); +} diff --git a/src/client/gui/screens/FurnaceScreen.h b/src/client/gui/screens/FurnaceScreen.hpp similarity index 93% rename from src/client/gui/screens/FurnaceScreen.h rename to src/client/gui/screens/FurnaceScreen.hpp index 61dc95f..9f29bf2 100755 --- a/src/client/gui/screens/FurnaceScreen.h +++ b/src/client/gui/screens/FurnaceScreen.hpp @@ -1,9 +1,9 @@ #pragma once -#include "BaseContainerScreen.h" +#include "BaseContainerScreen.hpp" -#include "../components/InventoryPane.h" -#include "../components/Button.h" +#include "client/gui/components/InventoryPane.hpp" +#include "client/gui/components/Button.hpp" class Font; class CItem; diff --git a/src/client/gui/screens/InBedScreen.cpp b/src/client/gui/screens/InBedScreen.cpp index 3adadc7..571fbcf 100755 --- a/src/client/gui/screens/InBedScreen.cpp +++ b/src/client/gui/screens/InBedScreen.cpp @@ -1,49 +1,49 @@ -#include "InBedScreen.h" -#include "ScreenChooser.h" -#include "../components/Button.h" -#include "../../Minecraft.h" -#include "../../player/LocalPlayer.h" -#include "../../../platform/time.h" - -static const int WAIT_TICKS = 30; - -InBedScreen::InBedScreen() - : bWakeUp(0) -{ -} - -InBedScreen::~InBedScreen() { - delete bWakeUp; -} - -void InBedScreen::init() { - if (/* minecraft->useTouchscreen() */ true) { - bWakeUp = new Touch::TButton(1, "Leave Bed"); - } else { - bWakeUp = new Button(1, "Leave Bed"); - } - buttons.push_back(bWakeUp); - - tabButtons.push_back(bWakeUp); -} - -void InBedScreen::setupPositions() { - bWakeUp->width = width / 2; - bWakeUp->height = int(height * 0.2f); - bWakeUp->y = height - int(bWakeUp->height * 1.5); - bWakeUp->x = width/2 - bWakeUp->width/2; -} - -void InBedScreen::render( int xm, int ym, float a ) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - Screen::render(xm, ym, a); - glDisable(GL_BLEND); -} - -void InBedScreen::buttonClicked( Button* button ) { - if (button == bWakeUp) { - minecraft->player->stopSleepInBed(true, true, true); - minecraft->setScreen(NULL); - } -} +#include "InBedScreen.hpp" +#include "ScreenChooser.hpp" +#include "client/gui/components/Button.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" +#include "platform/time.hpp" + +static const int WAIT_TICKS = 30; + +InBedScreen::InBedScreen() + : bWakeUp(0) +{ +} + +InBedScreen::~InBedScreen() { + delete bWakeUp; +} + +void InBedScreen::init() { + if (/* minecraft->useTouchscreen() */ true) { + bWakeUp = new Touch::TButton(1, "Leave Bed"); + } else { + bWakeUp = new Button(1, "Leave Bed"); + } + buttons.push_back(bWakeUp); + + tabButtons.push_back(bWakeUp); +} + +void InBedScreen::setupPositions() { + bWakeUp->width = width / 2; + bWakeUp->height = int(height * 0.2f); + bWakeUp->y = height - int(bWakeUp->height * 1.5); + bWakeUp->x = width/2 - bWakeUp->width/2; +} + +void InBedScreen::render( int xm, int ym, float a ) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Screen::render(xm, ym, a); + glDisable(GL_BLEND); +} + +void InBedScreen::buttonClicked( Button* button ) { + if (button == bWakeUp) { + minecraft->player->stopSleepInBed(true, true, true); + minecraft->setScreen(NULL); + } +} diff --git a/src/client/gui/screens/InBedScreen.h b/src/client/gui/screens/InBedScreen.hpp similarity index 88% rename from src/client/gui/screens/InBedScreen.h rename to src/client/gui/screens/InBedScreen.hpp index 1fa8121..395f3e3 100755 --- a/src/client/gui/screens/InBedScreen.h +++ b/src/client/gui/screens/InBedScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Screen.h" +#include "client/gui/Screen.hpp" class Button; class InBedScreen: public Screen diff --git a/src/client/gui/screens/IngameBlockSelectionScreen.cpp b/src/client/gui/screens/IngameBlockSelectionScreen.cpp index a8a7952..a797159 100755 --- a/src/client/gui/screens/IngameBlockSelectionScreen.cpp +++ b/src/client/gui/screens/IngameBlockSelectionScreen.cpp @@ -1,341 +1,341 @@ -#include "IngameBlockSelectionScreen.h" -#include "../../renderer/TileRenderer.h" -#include "../../player/LocalPlayer.h" -#include "../../renderer/gles.h" -#include "../../Minecraft.h" -#include "../../sound/SoundEngine.h" -#include "../../../world/entity/player/Inventory.h" -#include "../../../platform/input/Mouse.h" - -#include "../Gui.h" -#include "../../renderer/Textures.h" -#include -#include "ArmorScreen.h" -#include "../components/Button.h" - -#if defined(__APPLE__) - static const std::string demoVersionString("Not available in the Lite version"); -#else - static const std::string demoVersionString("Not available in the demo version"); -#endif - -IngameBlockSelectionScreen::IngameBlockSelectionScreen() -: selectedItem(0), - _area(0,0,0,0), - _pendingQuit(false), - InventoryRows(1), - InventoryCols(1), - InventorySize(1), - bArmor(1, "Armor") -{ -} - -void IngameBlockSelectionScreen::init() -{ - Inventory* inventory = minecraft->player->inventory; - InventoryCols = minecraft->isCreativeMode()? 13 : 9; - InventorySize = inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE; - InventoryRows = 1 + (InventorySize - 1) / InventoryCols; - - _area = RectangleArea( (float)getSlotPosX(0) - 4, - (float)getSlotPosY(0) - 4, - (float)getSlotPosX(InventoryCols) + 4, - (float)getSlotPosY(InventoryRows) + 4); - - ItemInstance* selected = inventory->getSelected(); - if (!selected || selected->isNull()) { - selectedItem = 0; - return; - } - - for (int i = Inventory::MAX_SELECTION_SIZE; i < InventorySize; i++) { - if (selected == minecraft->player->inventory->getItem(i)) - { - selectedItem = i - Inventory::MAX_SELECTION_SIZE; - break; - } - } - if (!isAllowed(selectedItem)) - selectedItem = 0; - - if (!minecraft->isCreativeMode()) { - bArmor.width = 42; - bArmor.x = 0; - bArmor.y = height - bArmor.height; - buttons.push_back(&bArmor); - } -} - -void IngameBlockSelectionScreen::removed() -{ - minecraft->gui.inventoryUpdated(); -} - -void IngameBlockSelectionScreen::renderSlots() -{ - //static Stopwatch w; - //w.start(); - - glColor4f2(1, 1, 1, 1); - - blitOffset = -90; - - //glEnable2(GL_RESCALE_NORMAL); - //glPushMatrix2(); - //glRotatef2(180, 1, 0, 0); - //Lighting::turnOn(); - //glPopMatrix2(); - - minecraft->textures->loadAndBindTexture("gui/gui.png"); - for (int r = 0; r < InventoryRows; r++) - { - int x = getSlotPosX(0) - 3; - int y = getSlotPosY(r) - 3; - - if (InventoryCols == 9) { - blit(x, y, 0, 0, 182, 22); - } else { - // first 8 slots - blit(x, y, 0, 0, 182-20, 22); - // last k slots - const int k = 5; - const int w = k * 20; - blit(x + 162, y, 182-w, 0, w, 22); - } - } - if (selectedItem >= 0) - { - int x = getSlotPosX(selectedItem % InventoryCols) - 4;// width / 2 - 182 / 2 - 1 + () * 20; - int y = getSlotPosY(selectedItem / InventoryCols) - 4;// height - 22 * 3 - 1 - (selectedItem / InventoryCols) * 22; - blit(x, y, 0, 22, 24, 22); - } - - for (int r = 0; r < InventoryRows; r++) - { - int y = getSlotPosY(r); - for (int i = 0; i < InventoryCols; i++) { - int x = getSlotPosX(i); - renderSlot(r * InventoryCols + i + Inventory::MAX_SELECTION_SIZE, x, y, 0); - } - } - - //w.stop(); - //w.printEvery(1000, "render-blocksel"); - - //glDisable2(GL_RESCALE_NORMAL); - //Lighting::turnOn(); -} - -int IngameBlockSelectionScreen::getSlotPosX(int slotX) { - return width / 2 - InventoryCols * 10 + slotX * 20 + 2; -} - -int IngameBlockSelectionScreen::getSlotPosY(int slotY) { - //return height - 63 - 22 * (3 - slotY); - int yy = InventoryCols==9? 8 : 3; - return yy + slotY * getSlotHeight(); -} - -//int IngameBlockSelectionScreen::getLinearSlotId(int x, int y) { -// return -//} - - -#include "../../../world/item/ItemInstance.h" -#include "../../renderer/entity/ItemRenderer.h" - -void IngameBlockSelectionScreen::renderSlot(int slot, int x, int y, float a) -{ - ItemInstance* item = minecraft->player->inventory->getItem(slot); - if (!item) return; - - ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, (float)x, (float)y, true); - - if (minecraft->gameMode->isCreativeType()) return; - if (!isAllowed(slot - Inventory::MAX_SELECTION_SIZE)) return; - - glPushMatrix2(); - glScalef2(Gui::InvGuiScale + Gui::InvGuiScale, Gui::InvGuiScale + Gui::InvGuiScale, 1); - const float k = 0.5f * Gui::GuiScale; - minecraft->gui.renderSlotText(item, k*x, k*y, true, true); - glPopMatrix2(); -} - -void IngameBlockSelectionScreen::keyPressed(int eventKey) -{ - int selX = selectedItem % InventoryCols; - int selY = selectedItem / InventoryCols; - - int tmpSelectedSlot = selectedItem; - - Options& o = minecraft->options; - if (eventKey == o.getIntValue(OPTIONS_KEY_LEFT) && selX > 0) - { - tmpSelectedSlot -= 1; - } - else if (eventKey == o.getIntValue(OPTIONS_KEY_RIGHT) && selX < (InventoryCols - 1)) - { - tmpSelectedSlot += 1; - } - else if (eventKey == o.getIntValue(OPTIONS_KEY_BACK) && selY < (InventoryRows - 1)) - { - tmpSelectedSlot += InventoryCols; - } - else if (eventKey == o.getIntValue(OPTIONS_KEY_FORWARD) && selY > 0) - { - tmpSelectedSlot -= InventoryCols; - } - - if (isAllowed(tmpSelectedSlot)) - selectedItem = tmpSelectedSlot; - - if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_OK)) - selectSlotAndClose(); - -#ifdef RPI - if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_CANCEL) - || eventKey == Keyboard::KEY_ESCAPE) - minecraft->setScreen(NULL); -#else - if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_CANCEL)) - minecraft->setScreen(NULL); -#endif -} - -//------------------------------------------------------------------------------ -// wheel support for creative inventory; scroll moves selection vertically -void IngameBlockSelectionScreen::mouseWheel(int dx, int dy, int xm, int ym) -{ - if (dy == 0) return; - // just move selection up/down one row; desktop UI doesn't have a pane - int cols = InventoryCols; - int maxIndex = InventorySize - 1; - int idx = selectedItem; - if (dy > 0) { - // wheel up -> previous row - if (idx >= cols) idx -= cols; - } else { - // wheel down -> next row - if (idx + cols <= maxIndex) idx += cols; - } - selectedItem = idx; -} - -int IngameBlockSelectionScreen::getSelectedSlot(int x, int y) -{ - int left = width / 2 - InventoryCols * 10; - int top = -4 + getSlotPosY(0); - - if (x >= left && y >= top) - { - int xSlot = (x - left) / 20; - if (xSlot < InventoryCols) { - int row = ((y-top) / getSlotHeight()); - return row * InventoryCols + xSlot; - } - } - return -1; -} - -void IngameBlockSelectionScreen::mouseClicked(int x, int y, int buttonNum) -{ - if (buttonNum == MouseAction::ACTION_LEFT) { - - int slot = getSelectedSlot(x, y); - if (isAllowed(slot)) - { - selectedItem = slot; - //minecraft->soundEngine->playUI("random.click", 1, 1); - } else { - _pendingQuit = !_area.isInside((float)x, (float)y) - && !bArmor.isInside(x, y); - } - } - if (!_pendingQuit) - super::mouseClicked(x, y, buttonNum); -} - -void IngameBlockSelectionScreen::mouseReleased(int x, int y, int buttonNum) -{ - if (buttonNum == MouseAction::ACTION_LEFT) { - - int slot = getSelectedSlot(x, y); - if (isAllowed(slot) && slot == selectedItem) - { - selectSlotAndClose(); - } else { - if (_pendingQuit && !_area.isInside((float)x, (float)y)) - minecraft->setScreen(NULL); - } - } - if (!_pendingQuit) - super::mouseReleased(x, y, buttonNum); -} - -void IngameBlockSelectionScreen::selectSlotAndClose() -{ - Inventory* inventory = minecraft->player->inventory; - // Flash the selected gui item - //inventory->moveToSelectedSlot(selectedItem + Inventory::MAX_SELECTION_SIZE, true); - inventory->moveToSelectionSlot(0, selectedItem + Inventory::MAX_SELECTION_SIZE, true); - inventory->selectSlot(0); - minecraft->gui.flashSlot(inventory->selected); - - minecraft->soundEngine->playUI("random.click", 1, 1); - minecraft->setScreen(NULL); -} - -void IngameBlockSelectionScreen::render( int xm, int ym, float a ) -{ - glDisable2(GL_DEPTH_TEST); - fill(0, 0, width, height, (0x80) << 24); - glEnable2(GL_BLEND); - - glDisable2(GL_ALPHA_TEST); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - renderSlots(); - renderDemoOverlay(); - - glEnable2(GL_ALPHA_TEST); - glDisable2(GL_BLEND); - - glEnable2(GL_DEPTH_TEST); - - Screen::render(xm, ym, a); -} - -void IngameBlockSelectionScreen::renderDemoOverlay() { -#ifdef DEMO_MODE - fill( getSlotPosX(0) - 3, getSlotPosY(3) - 3, - getSlotPosX(InventoryCols) - 3, getSlotPosY(InventoryRows) - 3, 0xa0 << 24); - - const int centerX = (getSlotPosX(4) + getSlotPosX(5)) / 2; - const int centerY = (getSlotPosY(3) + getSlotPosY(InventoryRows-1)) / 2 + 5; - drawCenteredString(minecraft->font, demoVersionString, centerX, centerY, 0xffffffff); -#endif /*DEMO_MODE*/ -} - -bool IngameBlockSelectionScreen::isAllowed(int slot) { - if (slot < 0 || slot >= InventorySize) - return false; - - #ifdef DEMO_MODE - return slot < (minecraft->isCreativeMode()? 28 : 27); - #endif /*DEMO_MODE*/ - - return true; -} - -int IngameBlockSelectionScreen::getSlotHeight() { - return InventoryCols==9? 22 : 20; -} - -void IngameBlockSelectionScreen::buttonClicked( Button* button ) -{ - if (button == &bArmor) { - minecraft->setScreen(new ArmorScreen()); - } - super::buttonClicked(button); -} +#include "IngameBlockSelectionScreen.hpp" +#include "client/renderer/TileRenderer.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/gles.hpp" +#include "client/Minecraft.hpp" +#include "client/sound/SoundEngine.hpp" +#include "world/entity/player/Inventory.hpp" +#include "platform/input/Mouse.hpp" + +#include "client/gui/Gui.hpp" +#include "client/renderer/Textures.hpp" +#include +#include "ArmorScreen.hpp" +#include "client/gui/components/Button.hpp" + +#if defined(__APPLE__) + static const std::string demoVersionString("Not available in the Lite version"); +#else + static const std::string demoVersionString("Not available in the demo version"); +#endif + +IngameBlockSelectionScreen::IngameBlockSelectionScreen() +: selectedItem(0), + _area(0,0,0,0), + _pendingQuit(false), + InventoryRows(1), + InventoryCols(1), + InventorySize(1), + bArmor(1, "Armor") +{ +} + +void IngameBlockSelectionScreen::init() +{ + Inventory* inventory = minecraft->player->inventory; + InventoryCols = minecraft->isCreativeMode()? 13 : 9; + InventorySize = inventory->getContainerSize() - Inventory::MAX_SELECTION_SIZE; + InventoryRows = 1 + (InventorySize - 1) / InventoryCols; + + _area = RectangleArea( (float)getSlotPosX(0) - 4, + (float)getSlotPosY(0) - 4, + (float)getSlotPosX(InventoryCols) + 4, + (float)getSlotPosY(InventoryRows) + 4); + + ItemInstance* selected = inventory->getSelected(); + if (!selected || selected->isNull()) { + selectedItem = 0; + return; + } + + for (int i = Inventory::MAX_SELECTION_SIZE; i < InventorySize; i++) { + if (selected == minecraft->player->inventory->getItem(i)) + { + selectedItem = i - Inventory::MAX_SELECTION_SIZE; + break; + } + } + if (!isAllowed(selectedItem)) + selectedItem = 0; + + if (!minecraft->isCreativeMode()) { + bArmor.width = 42; + bArmor.x = 0; + bArmor.y = height - bArmor.height; + buttons.push_back(&bArmor); + } +} + +void IngameBlockSelectionScreen::removed() +{ + minecraft->gui.inventoryUpdated(); +} + +void IngameBlockSelectionScreen::renderSlots() +{ + //static Stopwatch w; + //w.start(); + + glColor4f2(1, 1, 1, 1); + + blitOffset = -90; + + //glEnable2(GL_RESCALE_NORMAL); + //glPushMatrix2(); + //glRotatef2(180, 1, 0, 0); + //Lighting::turnOn(); + //glPopMatrix2(); + + minecraft->textures->loadAndBindTexture("gui/gui.png"); + for (int r = 0; r < InventoryRows; r++) + { + int x = getSlotPosX(0) - 3; + int y = getSlotPosY(r) - 3; + + if (InventoryCols == 9) { + blit(x, y, 0, 0, 182, 22); + } else { + // first 8 slots + blit(x, y, 0, 0, 182-20, 22); + // last k slots + const int k = 5; + const int w = k * 20; + blit(x + 162, y, 182-w, 0, w, 22); + } + } + if (selectedItem >= 0) + { + int x = getSlotPosX(selectedItem % InventoryCols) - 4;// width / 2 - 182 / 2 - 1 + () * 20; + int y = getSlotPosY(selectedItem / InventoryCols) - 4;// height - 22 * 3 - 1 - (selectedItem / InventoryCols) * 22; + blit(x, y, 0, 22, 24, 22); + } + + for (int r = 0; r < InventoryRows; r++) + { + int y = getSlotPosY(r); + for (int i = 0; i < InventoryCols; i++) { + int x = getSlotPosX(i); + renderSlot(r * InventoryCols + i + Inventory::MAX_SELECTION_SIZE, x, y, 0); + } + } + + //w.stop(); + //w.printEvery(1000, "render-blocksel"); + + //glDisable2(GL_RESCALE_NORMAL); + //Lighting::turnOn(); +} + +int IngameBlockSelectionScreen::getSlotPosX(int slotX) { + return width / 2 - InventoryCols * 10 + slotX * 20 + 2; +} + +int IngameBlockSelectionScreen::getSlotPosY(int slotY) { + //return height - 63 - 22 * (3 - slotY); + int yy = InventoryCols==9? 8 : 3; + return yy + slotY * getSlotHeight(); +} + +//int IngameBlockSelectionScreen::getLinearSlotId(int x, int y) { +// return +//} + + +#include "world/item/ItemInstance.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" + +void IngameBlockSelectionScreen::renderSlot(int slot, int x, int y, float a) +{ + ItemInstance* item = minecraft->player->inventory->getItem(slot); + if (!item) return; + + ItemRenderer::renderGuiItem(minecraft->font, minecraft->textures, item, (float)x, (float)y, true); + + if (minecraft->gameMode->isCreativeType()) return; + if (!isAllowed(slot - Inventory::MAX_SELECTION_SIZE)) return; + + glPushMatrix2(); + glScalef2(Gui::InvGuiScale + Gui::InvGuiScale, Gui::InvGuiScale + Gui::InvGuiScale, 1); + const float k = 0.5f * Gui::GuiScale; + minecraft->gui.renderSlotText(item, k*x, k*y, true, true); + glPopMatrix2(); +} + +void IngameBlockSelectionScreen::keyPressed(int eventKey) +{ + int selX = selectedItem % InventoryCols; + int selY = selectedItem / InventoryCols; + + int tmpSelectedSlot = selectedItem; + + Options& o = minecraft->options; + if (eventKey == o.getIntValue(OPTIONS_KEY_LEFT) && selX > 0) + { + tmpSelectedSlot -= 1; + } + else if (eventKey == o.getIntValue(OPTIONS_KEY_RIGHT) && selX < (InventoryCols - 1)) + { + tmpSelectedSlot += 1; + } + else if (eventKey == o.getIntValue(OPTIONS_KEY_BACK) && selY < (InventoryRows - 1)) + { + tmpSelectedSlot += InventoryCols; + } + else if (eventKey == o.getIntValue(OPTIONS_KEY_FORWARD) && selY > 0) + { + tmpSelectedSlot -= InventoryCols; + } + + if (isAllowed(tmpSelectedSlot)) + selectedItem = tmpSelectedSlot; + + if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_OK)) + selectSlotAndClose(); + +#ifdef RPI + if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_CANCEL) + || eventKey == Keyboard::KEY_ESCAPE) + minecraft->setScreen(NULL); +#else + if (eventKey == o.getIntValue(OPTIONS_KEY_MENU_CANCEL)) + minecraft->setScreen(NULL); +#endif +} + +//------------------------------------------------------------------------------ +// wheel support for creative inventory; scroll moves selection vertically +void IngameBlockSelectionScreen::mouseWheel(int dx, int dy, int xm, int ym) +{ + if (dy == 0) return; + // just move selection up/down one row; desktop UI doesn't have a pane + int cols = InventoryCols; + int maxIndex = InventorySize - 1; + int idx = selectedItem; + if (dy > 0) { + // wheel up -> previous row + if (idx >= cols) idx -= cols; + } else { + // wheel down -> next row + if (idx + cols <= maxIndex) idx += cols; + } + selectedItem = idx; +} + +int IngameBlockSelectionScreen::getSelectedSlot(int x, int y) +{ + int left = width / 2 - InventoryCols * 10; + int top = -4 + getSlotPosY(0); + + if (x >= left && y >= top) + { + int xSlot = (x - left) / 20; + if (xSlot < InventoryCols) { + int row = ((y-top) / getSlotHeight()); + return row * InventoryCols + xSlot; + } + } + return -1; +} + +void IngameBlockSelectionScreen::mouseClicked(int x, int y, int buttonNum) +{ + if (buttonNum == MouseAction::ACTION_LEFT) { + + int slot = getSelectedSlot(x, y); + if (isAllowed(slot)) + { + selectedItem = slot; + //minecraft->soundEngine->playUI("random.click", 1, 1); + } else { + _pendingQuit = !_area.isInside((float)x, (float)y) + && !bArmor.isInside(x, y); + } + } + if (!_pendingQuit) + super::mouseClicked(x, y, buttonNum); +} + +void IngameBlockSelectionScreen::mouseReleased(int x, int y, int buttonNum) +{ + if (buttonNum == MouseAction::ACTION_LEFT) { + + int slot = getSelectedSlot(x, y); + if (isAllowed(slot) && slot == selectedItem) + { + selectSlotAndClose(); + } else { + if (_pendingQuit && !_area.isInside((float)x, (float)y)) + minecraft->setScreen(NULL); + } + } + if (!_pendingQuit) + super::mouseReleased(x, y, buttonNum); +} + +void IngameBlockSelectionScreen::selectSlotAndClose() +{ + Inventory* inventory = minecraft->player->inventory; + // Flash the selected gui item + //inventory->moveToSelectedSlot(selectedItem + Inventory::MAX_SELECTION_SIZE, true); + inventory->moveToSelectionSlot(0, selectedItem + Inventory::MAX_SELECTION_SIZE, true); + inventory->selectSlot(0); + minecraft->gui.flashSlot(inventory->selected); + + minecraft->soundEngine->playUI("random.click", 1, 1); + minecraft->setScreen(NULL); +} + +void IngameBlockSelectionScreen::render( int xm, int ym, float a ) +{ + glDisable2(GL_DEPTH_TEST); + fill(0, 0, width, height, (0x80) << 24); + glEnable2(GL_BLEND); + + glDisable2(GL_ALPHA_TEST); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + renderSlots(); + renderDemoOverlay(); + + glEnable2(GL_ALPHA_TEST); + glDisable2(GL_BLEND); + + glEnable2(GL_DEPTH_TEST); + + Screen::render(xm, ym, a); +} + +void IngameBlockSelectionScreen::renderDemoOverlay() { +#ifdef DEMO_MODE + fill( getSlotPosX(0) - 3, getSlotPosY(3) - 3, + getSlotPosX(InventoryCols) - 3, getSlotPosY(InventoryRows) - 3, 0xa0 << 24); + + const int centerX = (getSlotPosX(4) + getSlotPosX(5)) / 2; + const int centerY = (getSlotPosY(3) + getSlotPosY(InventoryRows-1)) / 2 + 5; + drawCenteredString(minecraft->font, demoVersionString, centerX, centerY, 0xffffffff); +#endif /*DEMO_MODE*/ +} + +bool IngameBlockSelectionScreen::isAllowed(int slot) { + if (slot < 0 || slot >= InventorySize) + return false; + + #ifdef DEMO_MODE + return slot < (minecraft->isCreativeMode()? 28 : 27); + #endif /*DEMO_MODE*/ + + return true; +} + +int IngameBlockSelectionScreen::getSlotHeight() { + return InventoryCols==9? 22 : 20; +} + +void IngameBlockSelectionScreen::buttonClicked( Button* button ) +{ + if (button == &bArmor) { + minecraft->setScreen(new ArmorScreen()); + } + super::buttonClicked(button); +} diff --git a/src/client/gui/screens/IngameBlockSelectionScreen.h b/src/client/gui/screens/IngameBlockSelectionScreen.hpp similarity index 89% rename from src/client/gui/screens/IngameBlockSelectionScreen.h rename to src/client/gui/screens/IngameBlockSelectionScreen.hpp index cbe3b6e..88e0c61 100755 --- a/src/client/gui/screens/IngameBlockSelectionScreen.h +++ b/src/client/gui/screens/IngameBlockSelectionScreen.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../Screen.h" -#include "../../player/input/touchscreen/TouchAreaModel.h" -#include "../components/Button.h" +#include "client/gui/Screen.hpp" +#include "client/player/input/touchscreen/TouchAreaModel.hpp" +#include "client/gui/components/Button.hpp" class IngameBlockSelectionScreen : public Screen { diff --git a/src/client/gui/screens/JoinByIPScreen.cpp b/src/client/gui/screens/JoinByIPScreen.cpp index 47cd44a..3c9bb27 100644 --- a/src/client/gui/screens/JoinByIPScreen.cpp +++ b/src/client/gui/screens/JoinByIPScreen.cpp @@ -1,14 +1,14 @@ -#include "JoinByIPScreen.h" +#include "JoinByIPScreen.hpp" -#include "JoinGameScreen.h" -#include "StartMenuScreen.h" -#include "ProgressScreen.h" -#include "../Font.h" -#include "../../../network/RakNetInstance.h" -#include "client/Options.h" -#include "client/gui/Screen.h" -#include "client/gui/components/TextBox.h" -#include "network/ClientSideNetworkHandler.h" +#include "JoinGameScreen.hpp" +#include "StartMenuScreen.hpp" +#include "ProgressScreen.hpp" +#include "client/gui/Font.hpp" +#include "network/RakNetInstance.hpp" +#include "client/Options.hpp" +#include "client/gui/Screen.hpp" +#include "client/gui/components/TextBox.hpp" +#include "network/ClientSideNetworkHandler.hpp" JoinByIPScreen::JoinByIPScreen() : tIP(0, "Server IP"), diff --git a/src/client/gui/screens/JoinByIPScreen.h b/src/client/gui/screens/JoinByIPScreen.hpp similarity index 67% rename from src/client/gui/screens/JoinByIPScreen.h rename to src/client/gui/screens/JoinByIPScreen.hpp index 5ee2b16..42ef2a1 100644 --- a/src/client/gui/screens/JoinByIPScreen.h +++ b/src/client/gui/screens/JoinByIPScreen.hpp @@ -1,9 +1,9 @@ -#include "../Screen.h" -#include "../components/Button.h" -#include "../../Minecraft.h" -#include "client/gui/components/ImageButton.h" -#include "client/gui/components/TextBox.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/Button.hpp" +#include "client/Minecraft.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "client/gui/components/TextBox.hpp" class JoinByIPScreen: public Screen { diff --git a/src/client/gui/screens/JoinGameScreen.cpp b/src/client/gui/screens/JoinGameScreen.cpp index 8626103..f45bb01 100755 --- a/src/client/gui/screens/JoinGameScreen.cpp +++ b/src/client/gui/screens/JoinGameScreen.cpp @@ -1,167 +1,167 @@ -#include "JoinGameScreen.h" -#include "StartMenuScreen.h" -#include "ProgressScreen.h" -#include "../Font.h" -#include "../../../network/RakNetInstance.h" - -JoinGameScreen::JoinGameScreen() -: bJoin( 2, "Join Game"), - bBack( 3, "Back"), - gamesList(NULL) -{ - bJoin.active = false; - //gamesList->yInertia = 0.5f; -} - -JoinGameScreen::~JoinGameScreen() -{ - delete gamesList; -} - -void JoinGameScreen::buttonClicked(Button* button) -{ - if (button->id == bJoin.id) - { - if (isIndexValid(gamesList->selectedItem)) - { - PingedCompatibleServer selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; - minecraft->joinMultiplayer(selectedServer); - { - bJoin.active = false; - bBack.active = false; - minecraft->setScreen(new ProgressScreen()); - } - } - //minecraft->locateMultiplayer(); - //minecraft->setScreen(new JoinGameScreen()); - } - if (button->id == bBack.id) - { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } -} - -bool JoinGameScreen::handleBackEvent(bool isDown) -{ - if (!isDown) - { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } - return true; -} - - -bool JoinGameScreen::isIndexValid( int index ) -{ - return gamesList && index >= 0 && index < gamesList->getNumberOfItems(); -} - -void JoinGameScreen::tick() -{ - const ServerList& orgServerList = minecraft->raknetInstance->getServerList(); - ServerList serverList; - for (unsigned int i = 0; i < orgServerList.size(); ++i) - if (orgServerList[i].name.GetLength() > 0) - serverList.push_back(orgServerList[i]); - - if (serverList.size() != gamesList->copiedServerList.size()) - { - // copy the currently selected item - PingedCompatibleServer selectedServer; - bool hasSelection = false; - if (isIndexValid(gamesList->selectedItem)) - { - selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; - hasSelection = true; - } - - gamesList->copiedServerList = serverList; - gamesList->selectItem(-1, false); - - // re-select previous item if it still exists - if (hasSelection) - { - for (unsigned int i = 0; i < gamesList->copiedServerList.size(); i++) - { - if (gamesList->copiedServerList[i].address == selectedServer.address) - { - gamesList->selectItem(i, false); - break; - } - } - } - } else { - for (int i = (int)gamesList->copiedServerList.size()-1; i >= 0 ; --i) { - for (int j = 0; j < (int) serverList.size(); ++j) - if (serverList[j].address == gamesList->copiedServerList[i].address) - gamesList->copiedServerList[i].name = serverList[j].name; - } - } - - bJoin.active = isIndexValid(gamesList->selectedItem); -} - -void JoinGameScreen::init() -{ - buttons.push_back(&bJoin); - buttons.push_back(&bBack); - - minecraft->raknetInstance->clearServerList(); - gamesList = new AvailableGamesList(minecraft, width, height); - -#ifdef ANDROID - tabButtons.push_back(&bJoin); - tabButtons.push_back(&bBack); -#endif -} - -void JoinGameScreen::setupPositions() { - int yBase = height - 26; - - //#ifdef ANDROID - bJoin.y = yBase; - bBack.y = yBase; - - bBack.width = bJoin.width = 120; - //#endif - - // Center buttons - bJoin.x = width / 2 - 4 - bJoin.width; - bBack.x = width / 2 + 4; -} - -void JoinGameScreen::render( int xm, int ym, float a ) -{ - bool hasNetwork = minecraft->platform()->isNetworkEnabled(true); -#ifdef WIN32 - hasNetwork = hasNetwork && !GetAsyncKeyState(VK_TAB); -#endif - - renderBackground(); - if (hasNetwork) gamesList->render(xm, ym, a); - Screen::render(xm, ym, a); - - if (hasNetwork) { -#ifdef RPI - std::string s = "Scanning for Local Network Games..."; -#else - std::string s = "Scanning for WiFi Games..."; -#endif - drawCenteredString(minecraft->font, s, width / 2, 8, 0xffffffff); - - const int textWidth = minecraft->font->width(s); - const int spinnerX = width/2 + textWidth / 2 + 6; - - static const char* spinnerTexts[] = {"-", "\\", "|", "/"}; - int n = ((int)(5.5f * getTimeS()) % 4); - drawCenteredString(minecraft->font, spinnerTexts[n], spinnerX, 8, 0xffffffff); - } else { - std::string s = "WiFi is disabled"; - const int yy = height / 2 - 8; - drawCenteredString(minecraft->font, s, width / 2, yy, 0xffffffff); - } -} - -bool JoinGameScreen::isInGameScreen() { return false; } +#include "JoinGameScreen.hpp" +#include "StartMenuScreen.hpp" +#include "ProgressScreen.hpp" +#include "client/gui/Font.hpp" +#include "network/RakNetInstance.hpp" + +JoinGameScreen::JoinGameScreen() +: bJoin( 2, "Join Game"), + bBack( 3, "Back"), + gamesList(NULL) +{ + bJoin.active = false; + //gamesList->yInertia = 0.5f; +} + +JoinGameScreen::~JoinGameScreen() +{ + delete gamesList; +} + +void JoinGameScreen::buttonClicked(Button* button) +{ + if (button->id == bJoin.id) + { + if (isIndexValid(gamesList->selectedItem)) + { + PingedCompatibleServer selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; + minecraft->joinMultiplayer(selectedServer); + { + bJoin.active = false; + bBack.active = false; + minecraft->setScreen(new ProgressScreen()); + } + } + //minecraft->locateMultiplayer(); + //minecraft->setScreen(new JoinGameScreen()); + } + if (button->id == bBack.id) + { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } +} + +bool JoinGameScreen::handleBackEvent(bool isDown) +{ + if (!isDown) + { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } + return true; +} + + +bool JoinGameScreen::isIndexValid( int index ) +{ + return gamesList && index >= 0 && index < gamesList->getNumberOfItems(); +} + +void JoinGameScreen::tick() +{ + const ServerList& orgServerList = minecraft->raknetInstance->getServerList(); + ServerList serverList; + for (unsigned int i = 0; i < orgServerList.size(); ++i) + if (orgServerList[i].name.GetLength() > 0) + serverList.push_back(orgServerList[i]); + + if (serverList.size() != gamesList->copiedServerList.size()) + { + // copy the currently selected item + PingedCompatibleServer selectedServer; + bool hasSelection = false; + if (isIndexValid(gamesList->selectedItem)) + { + selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; + hasSelection = true; + } + + gamesList->copiedServerList = serverList; + gamesList->selectItem(-1, false); + + // re-select previous item if it still exists + if (hasSelection) + { + for (unsigned int i = 0; i < gamesList->copiedServerList.size(); i++) + { + if (gamesList->copiedServerList[i].address == selectedServer.address) + { + gamesList->selectItem(i, false); + break; + } + } + } + } else { + for (int i = (int)gamesList->copiedServerList.size()-1; i >= 0 ; --i) { + for (int j = 0; j < (int) serverList.size(); ++j) + if (serverList[j].address == gamesList->copiedServerList[i].address) + gamesList->copiedServerList[i].name = serverList[j].name; + } + } + + bJoin.active = isIndexValid(gamesList->selectedItem); +} + +void JoinGameScreen::init() +{ + buttons.push_back(&bJoin); + buttons.push_back(&bBack); + + minecraft->raknetInstance->clearServerList(); + gamesList = new AvailableGamesList(minecraft, width, height); + +#ifdef ANDROID + tabButtons.push_back(&bJoin); + tabButtons.push_back(&bBack); +#endif +} + +void JoinGameScreen::setupPositions() { + int yBase = height - 26; + + //#ifdef ANDROID + bJoin.y = yBase; + bBack.y = yBase; + + bBack.width = bJoin.width = 120; + //#endif + + // Center buttons + bJoin.x = width / 2 - 4 - bJoin.width; + bBack.x = width / 2 + 4; +} + +void JoinGameScreen::render( int xm, int ym, float a ) +{ + bool hasNetwork = minecraft->platform()->isNetworkEnabled(true); +#ifdef WIN32 + hasNetwork = hasNetwork && !GetAsyncKeyState(VK_TAB); +#endif + + renderBackground(); + if (hasNetwork) gamesList->render(xm, ym, a); + Screen::render(xm, ym, a); + + if (hasNetwork) { +#ifdef RPI + std::string s = "Scanning for Local Network Games..."; +#else + std::string s = "Scanning for WiFi Games..."; +#endif + drawCenteredString(minecraft->font, s, width / 2, 8, 0xffffffff); + + const int textWidth = minecraft->font->width(s); + const int spinnerX = width/2 + textWidth / 2 + 6; + + static const char* spinnerTexts[] = {"-", "\\", "|", "/"}; + int n = ((int)(5.5f * getTimeS()) % 4); + drawCenteredString(minecraft->font, spinnerTexts[n], spinnerX, 8, 0xffffffff); + } else { + std::string s = "WiFi is disabled"; + const int yy = height / 2 - 8; + drawCenteredString(minecraft->font, s, width / 2, yy, 0xffffffff); + } +} + +bool JoinGameScreen::isInGameScreen() { return false; } diff --git a/src/client/gui/screens/JoinGameScreen.h b/src/client/gui/screens/JoinGameScreen.hpp similarity index 86% rename from src/client/gui/screens/JoinGameScreen.h rename to src/client/gui/screens/JoinGameScreen.hpp index c0cba87..119877f 100755 --- a/src/client/gui/screens/JoinGameScreen.h +++ b/src/client/gui/screens/JoinGameScreen.hpp @@ -1,10 +1,10 @@ #pragma once -#include "../Screen.h" -#include "../components/Button.h" -#include "../components/ScrolledSelectionList.h" -#include "../../Minecraft.h" -#include "../../../network/RakNetInstance.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/ScrolledSelectionList.hpp" +#include "client/Minecraft.hpp" +#include "network/RakNetInstance.hpp" class JoinGameScreen; diff --git a/src/client/gui/screens/OptionsScreen.cpp b/src/client/gui/screens/OptionsScreen.cpp index 11b87c1..da01fa0 100755 --- a/src/client/gui/screens/OptionsScreen.cpp +++ b/src/client/gui/screens/OptionsScreen.cpp @@ -1,267 +1,267 @@ -#include "OptionsScreen.h" - -#include "StartMenuScreen.h" -#include "UsernameScreen.h" -#include "DialogDefinitions.h" -#include "../../Minecraft.h" -#include "../../../AppPlatform.h" -#include "CreditsScreen.h" - -#include "../components/ImageButton.h" -#include "../components/OptionsGroup.h" -#include "platform/input/Keyboard.h" - -OptionsScreen::OptionsScreen() - : btnClose(NULL), - bHeader(NULL), - btnCredits(NULL), - selectedCategory(0) { -} - -OptionsScreen::~OptionsScreen() { - if (btnClose != NULL) { - delete btnClose; - btnClose = NULL; - } - - if (bHeader != NULL) { - delete bHeader; - bHeader = NULL; - } - - if (btnCredits != NULL) { - delete btnCredits; - btnCredits = NULL; - } - - for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { - if (*it != NULL) { - delete* it; - *it = NULL; - } - } - - for (std::vector::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) { - if (*it != NULL) { - delete* it; - *it = NULL; - } - } - - categoryButtons.clear(); -} - -void OptionsScreen::init() { - bHeader = new Touch::THeader(0, "Options"); - - btnClose = new ImageButton(1, ""); - - ImageDef def; - def.name = "gui/touchgui.png"; - def.width = 34; - def.height = 26; - - def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); - btnClose->setImageDef(def, true); - - categoryButtons.push_back(new Touch::TButton(2, "General")); - categoryButtons.push_back(new Touch::TButton(3, "Game")); - categoryButtons.push_back(new Touch::TButton(4, "Controls")); - categoryButtons.push_back(new Touch::TButton(5, "Graphics")); - categoryButtons.push_back(new Touch::TButton(6, "Tweaks")); - - btnCredits = new Touch::TButton(11, "Credits"); - - buttons.push_back(bHeader); - buttons.push_back(btnClose); - buttons.push_back(btnCredits); - - for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { - buttons.push_back(*it); - tabButtons.push_back(*it); - } - - generateOptionScreens(); - // start with first category selected - selectCategory(0); -} - -void OptionsScreen::setupPositions() { - int buttonHeight = btnClose->height; - - btnClose->x = width - btnClose->width; - btnClose->y = 0; - - int offsetNum = 1; - - for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { - - (*it)->x = 0; - (*it)->y = offsetNum * buttonHeight; - (*it)->selected = false; - - offsetNum++; - } - - bHeader->x = 0; - bHeader->y = 0; - bHeader->width = width - btnClose->width; - bHeader->height = btnClose->height; - - // Credits button (bottom-right) - if (btnCredits != NULL) { - btnCredits->x = width - btnCredits->width; - btnCredits->y = height - btnCredits->height; - } - - for (std::vector::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) { - - if (categoryButtons.size() > 0 && categoryButtons[0] != NULL) { - - (*it)->x = categoryButtons[0]->width; - (*it)->y = bHeader->height; - (*it)->width = width - categoryButtons[0]->width; - - (*it)->setupPositions(); - } - } - - // don't override user selection on resize -} - - -void OptionsScreen::render(int xm, int ym, float a) { - renderBackground(); - - int xmm = xm * width / minecraft->width; - int ymm = ym * height / minecraft->height - 1; - - if (currentOptionsGroup != NULL) - currentOptionsGroup->render(minecraft, xmm, ymm); - - super::render(xm, ym, a); -} - -void OptionsScreen::removed() { -} - -void OptionsScreen::buttonClicked(Button* button) { - if (button == btnClose) { - minecraft->options.save(); - if (minecraft->screen != NULL) { - minecraft->setScreen(NULL); - } else { - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } - } - else if (button->id > 1 && button->id < 7) { - int categoryButton = button->id - categoryButtons[0]->id; - selectCategory(categoryButton); - } - else if (button == btnCredits) { - minecraft->setScreen(new CreditsScreen()); - } -} - -void OptionsScreen::selectCategory(int index) { - int currentIndex = 0; - - for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { - - if (index == currentIndex) - (*it)->selected = true; - else - (*it)->selected = false; - - currentIndex++; - } - - if (index < (int)optionPanes.size()) - currentOptionsGroup = optionPanes[index]; -} - -void OptionsScreen::generateOptionScreens() { - // how the fuck it works - - optionPanes.push_back(new OptionsGroup("options.group.general")); - optionPanes.push_back(new OptionsGroup("options.group.game")); - optionPanes.push_back(new OptionsGroup("options.group.controls")); - optionPanes.push_back(new OptionsGroup("options.group.graphics")); - optionPanes.push_back(new OptionsGroup("options.group.tweaks")); - - // General Pane - optionPanes[0]->addOptionItem(OPTIONS_USERNAME, minecraft) - .addOptionItem(OPTIONS_SENSITIVITY, minecraft); - - // Game Pane - optionPanes[1]->addOptionItem(OPTIONS_DIFFICULTY, minecraft) - .addOptionItem(OPTIONS_SERVER_VISIBLE, minecraft) - .addOptionItem(OPTIONS_THIRD_PERSON_VIEW, minecraft) - .addOptionItem(OPTIONS_GUI_SCALE, minecraft) - .addOptionItem(OPTIONS_SENSITIVITY, minecraft) - .addOptionItem(OPTIONS_MUSIC_VOLUME, minecraft) - .addOptionItem(OPTIONS_SOUND_VOLUME, minecraft) - .addOptionItem(OPTIONS_SMOOTH_CAMERA, minecraft) - .addOptionItem(OPTIONS_DESTROY_VIBRATION, minecraft) - .addOptionItem(OPTIONS_IS_LEFT_HANDED, minecraft); - - // // Controls Pane - optionPanes[2]->addOptionItem(OPTIONS_INVERT_Y_MOUSE, minecraft) - .addOptionItem(OPTIONS_USE_TOUCHSCREEN, minecraft) - .addOptionItem(OPTIONS_AUTOJUMP, minecraft); - - for (int i = OPTIONS_KEY_FORWARD; i <= OPTIONS_KEY_USE; i++) { - optionPanes[2]->addOptionItem((OptionId)i, minecraft); - } - - // // Graphics Pane - optionPanes[3]->addOptionItem(OPTIONS_FANCY_GRAPHICS, minecraft) - .addOptionItem(OPTIONS_LIMIT_FRAMERATE, minecraft) - .addOptionItem(OPTIONS_VSYNC, minecraft) - .addOptionItem(OPTIONS_RENDER_DEBUG, minecraft) - .addOptionItem(OPTIONS_ANAGLYPH_3D, minecraft) - .addOptionItem(OPTIONS_VIEW_BOBBING, minecraft) - .addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft); - - optionPanes[4]->addOptionItem(OPTIONS_ALLOW_SPRINT, minecraft) - .addOptionItem(OPTIONS_BAR_ON_TOP, minecraft) - .addOptionItem(OPTIONS_RPI_CURSOR, minecraft); -} - -void OptionsScreen::mouseClicked(int x, int y, int buttonNum) { - if (currentOptionsGroup != NULL) - currentOptionsGroup->mouseClicked(minecraft, x, y, buttonNum); - - super::mouseClicked(x, y, buttonNum); -} - -void OptionsScreen::mouseReleased(int x, int y, int buttonNum) { - if (currentOptionsGroup != NULL) - currentOptionsGroup->mouseReleased(minecraft, x, y, buttonNum); - - super::mouseReleased(x, y, buttonNum); -} - -void OptionsScreen::keyPressed(int eventKey) { - if (currentOptionsGroup != NULL) - currentOptionsGroup->keyPressed(minecraft, eventKey); - if (eventKey == Keyboard::KEY_ESCAPE) - minecraft->options.save(); - - super::keyPressed(eventKey); -} - -void OptionsScreen::charPressed(char inputChar) { - if (currentOptionsGroup != NULL) - currentOptionsGroup->charPressed(minecraft, inputChar); - - super::keyPressed(inputChar); -} - -void OptionsScreen::tick() { - - if (currentOptionsGroup != NULL) - currentOptionsGroup->tick(minecraft); - - super::tick(); +#include "OptionsScreen.hpp" + +#include "StartMenuScreen.hpp" +#include "UsernameScreen.hpp" +#include "DialogDefinitions.hpp" +#include "client/Minecraft.hpp" +#include "AppPlatform.hpp" +#include "CreditsScreen.hpp" + +#include "client/gui/components/ImageButton.hpp" +#include "client/gui/components/OptionsGroup.hpp" +#include "platform/input/Keyboard.hpp" + +OptionsScreen::OptionsScreen() + : btnClose(NULL), + bHeader(NULL), + btnCredits(NULL), + selectedCategory(0) { +} + +OptionsScreen::~OptionsScreen() { + if (btnClose != NULL) { + delete btnClose; + btnClose = NULL; + } + + if (bHeader != NULL) { + delete bHeader; + bHeader = NULL; + } + + if (btnCredits != NULL) { + delete btnCredits; + btnCredits = NULL; + } + + for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { + if (*it != NULL) { + delete* it; + *it = NULL; + } + } + + for (std::vector::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) { + if (*it != NULL) { + delete* it; + *it = NULL; + } + } + + categoryButtons.clear(); +} + +void OptionsScreen::init() { + bHeader = new Touch::THeader(0, "Options"); + + btnClose = new ImageButton(1, ""); + + ImageDef def; + def.name = "gui/touchgui.png"; + def.width = 34; + def.height = 26; + + def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); + btnClose->setImageDef(def, true); + + categoryButtons.push_back(new Touch::TButton(2, "General")); + categoryButtons.push_back(new Touch::TButton(3, "Game")); + categoryButtons.push_back(new Touch::TButton(4, "Controls")); + categoryButtons.push_back(new Touch::TButton(5, "Graphics")); + categoryButtons.push_back(new Touch::TButton(6, "Tweaks")); + + btnCredits = new Touch::TButton(11, "Credits"); + + buttons.push_back(bHeader); + buttons.push_back(btnClose); + buttons.push_back(btnCredits); + + for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { + buttons.push_back(*it); + tabButtons.push_back(*it); + } + + generateOptionScreens(); + // start with first category selected + selectCategory(0); +} + +void OptionsScreen::setupPositions() { + int buttonHeight = btnClose->height; + + btnClose->x = width - btnClose->width; + btnClose->y = 0; + + int offsetNum = 1; + + for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { + + (*it)->x = 0; + (*it)->y = offsetNum * buttonHeight; + (*it)->selected = false; + + offsetNum++; + } + + bHeader->x = 0; + bHeader->y = 0; + bHeader->width = width - btnClose->width; + bHeader->height = btnClose->height; + + // Credits button (bottom-right) + if (btnCredits != NULL) { + btnCredits->x = width - btnCredits->width; + btnCredits->y = height - btnCredits->height; + } + + for (std::vector::iterator it = optionPanes.begin(); it != optionPanes.end(); ++it) { + + if (categoryButtons.size() > 0 && categoryButtons[0] != NULL) { + + (*it)->x = categoryButtons[0]->width; + (*it)->y = bHeader->height; + (*it)->width = width - categoryButtons[0]->width; + + (*it)->setupPositions(); + } + } + + // don't override user selection on resize +} + + +void OptionsScreen::render(int xm, int ym, float a) { + renderBackground(); + + int xmm = xm * width / minecraft->width; + int ymm = ym * height / minecraft->height - 1; + + if (currentOptionsGroup != NULL) + currentOptionsGroup->render(minecraft, xmm, ymm); + + super::render(xm, ym, a); +} + +void OptionsScreen::removed() { +} + +void OptionsScreen::buttonClicked(Button* button) { + if (button == btnClose) { + minecraft->options.save(); + if (minecraft->screen != NULL) { + minecraft->setScreen(NULL); + } else { + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } + } + else if (button->id > 1 && button->id < 7) { + int categoryButton = button->id - categoryButtons[0]->id; + selectCategory(categoryButton); + } + else if (button == btnCredits) { + minecraft->setScreen(new CreditsScreen()); + } +} + +void OptionsScreen::selectCategory(int index) { + int currentIndex = 0; + + for (std::vector::iterator it = categoryButtons.begin(); it != categoryButtons.end(); ++it) { + + if (index == currentIndex) + (*it)->selected = true; + else + (*it)->selected = false; + + currentIndex++; + } + + if (index < (int)optionPanes.size()) + currentOptionsGroup = optionPanes[index]; +} + +void OptionsScreen::generateOptionScreens() { + // how the fuck it works + + optionPanes.push_back(new OptionsGroup("options.group.general")); + optionPanes.push_back(new OptionsGroup("options.group.game")); + optionPanes.push_back(new OptionsGroup("options.group.controls")); + optionPanes.push_back(new OptionsGroup("options.group.graphics")); + optionPanes.push_back(new OptionsGroup("options.group.tweaks")); + + // General Pane + optionPanes[0]->addOptionItem(OPTIONS_USERNAME, minecraft) + .addOptionItem(OPTIONS_SENSITIVITY, minecraft); + + // Game Pane + optionPanes[1]->addOptionItem(OPTIONS_DIFFICULTY, minecraft) + .addOptionItem(OPTIONS_SERVER_VISIBLE, minecraft) + .addOptionItem(OPTIONS_THIRD_PERSON_VIEW, minecraft) + .addOptionItem(OPTIONS_GUI_SCALE, minecraft) + .addOptionItem(OPTIONS_SENSITIVITY, minecraft) + .addOptionItem(OPTIONS_MUSIC_VOLUME, minecraft) + .addOptionItem(OPTIONS_SOUND_VOLUME, minecraft) + .addOptionItem(OPTIONS_SMOOTH_CAMERA, minecraft) + .addOptionItem(OPTIONS_DESTROY_VIBRATION, minecraft) + .addOptionItem(OPTIONS_IS_LEFT_HANDED, minecraft); + + // // Controls Pane + optionPanes[2]->addOptionItem(OPTIONS_INVERT_Y_MOUSE, minecraft) + .addOptionItem(OPTIONS_USE_TOUCHSCREEN, minecraft) + .addOptionItem(OPTIONS_AUTOJUMP, minecraft); + + for (int i = OPTIONS_KEY_FORWARD; i <= OPTIONS_KEY_USE; i++) { + optionPanes[2]->addOptionItem((OptionId)i, minecraft); + } + + // // Graphics Pane + optionPanes[3]->addOptionItem(OPTIONS_FANCY_GRAPHICS, minecraft) + .addOptionItem(OPTIONS_LIMIT_FRAMERATE, minecraft) + .addOptionItem(OPTIONS_VSYNC, minecraft) + .addOptionItem(OPTIONS_RENDER_DEBUG, minecraft) + .addOptionItem(OPTIONS_ANAGLYPH_3D, minecraft) + .addOptionItem(OPTIONS_VIEW_BOBBING, minecraft) + .addOptionItem(OPTIONS_AMBIENT_OCCLUSION, minecraft); + + optionPanes[4]->addOptionItem(OPTIONS_ALLOW_SPRINT, minecraft) + .addOptionItem(OPTIONS_BAR_ON_TOP, minecraft) + .addOptionItem(OPTIONS_RPI_CURSOR, minecraft); +} + +void OptionsScreen::mouseClicked(int x, int y, int buttonNum) { + if (currentOptionsGroup != NULL) + currentOptionsGroup->mouseClicked(minecraft, x, y, buttonNum); + + super::mouseClicked(x, y, buttonNum); +} + +void OptionsScreen::mouseReleased(int x, int y, int buttonNum) { + if (currentOptionsGroup != NULL) + currentOptionsGroup->mouseReleased(minecraft, x, y, buttonNum); + + super::mouseReleased(x, y, buttonNum); +} + +void OptionsScreen::keyPressed(int eventKey) { + if (currentOptionsGroup != NULL) + currentOptionsGroup->keyPressed(minecraft, eventKey); + if (eventKey == Keyboard::KEY_ESCAPE) + minecraft->options.save(); + + super::keyPressed(eventKey); +} + +void OptionsScreen::charPressed(char inputChar) { + if (currentOptionsGroup != NULL) + currentOptionsGroup->charPressed(minecraft, inputChar); + + super::keyPressed(inputChar); +} + +void OptionsScreen::tick() { + + if (currentOptionsGroup != NULL) + currentOptionsGroup->tick(minecraft); + + super::tick(); } \ No newline at end of file diff --git a/src/client/gui/screens/OptionsScreen.h b/src/client/gui/screens/OptionsScreen.hpp similarity index 86% rename from src/client/gui/screens/OptionsScreen.h rename to src/client/gui/screens/OptionsScreen.hpp index 41589e7..727bd3a 100755 --- a/src/client/gui/screens/OptionsScreen.h +++ b/src/client/gui/screens/OptionsScreen.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../Screen.h" -#include "../components/Button.h" -#include "../components/OptionsGroup.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/OptionsGroup.hpp" class ImageButton; class OptionsPane; diff --git a/src/client/gui/screens/PauseScreen.cpp b/src/client/gui/screens/PauseScreen.cpp index ab30ecb..83b0e9d 100755 --- a/src/client/gui/screens/PauseScreen.cpp +++ b/src/client/gui/screens/PauseScreen.cpp @@ -1,201 +1,201 @@ -#include "PauseScreen.h" -#include "StartMenuScreen.h" -#include "../components/ImageButton.h" -#include "../../Minecraft.h" -#include "../../../util/Mth.h" -#include "../../../network/RakNetInstance.h" -#include "../../../network/ServerSideNetworkHandler.h" -#include "client/Options.h" -#include "client/gui/components/Button.h" -#include "client/gui/screens/OptionsScreen.h" - -PauseScreen::PauseScreen(bool wasBackPaused) -: saveStep(0), - visibleTime(0), - bContinue(0), - bQuit(0), - bOptions(0), - bQuitAndSaveLocally(0), - bServerVisibility(0), -// bThirdPerson(0), - wasBackPaused(wasBackPaused), - // bSound(OPTIONS_SOUND_VOLUME, 1, 0), - bThirdPerson(OPTIONS_THIRD_PERSON_VIEW), - bHideGui(OPTIONS_HIDEGUI) -{ - ImageDef def; - def.setSrc(IntRectangle(160, 144, 39, 31)); - def.name = "gui/touchgui.png"; - IntRectangle& defSrc = *def.getSrc(); - - def.width = defSrc.w * 0.666667f; - def.height = defSrc.h * 0.666667f; - - // bSound.setImageDef(def, true); - defSrc.y += defSrc.h; - bThirdPerson.setImageDef(def, true); - bHideGui.setImageDef(def, true); - //void setImageDef(ImageDef& imageDef, bool setButtonSize); -} - -PauseScreen::~PauseScreen() { - delete bContinue; - delete bQuit; - delete bQuitAndSaveLocally; - delete bServerVisibility; - delete bOptions; -// delete bThirdPerson; -} - -void PauseScreen::init() { - if (/* minecraft->useTouchscreen() */ true) { - bContinue = new Touch::TButton(1, "Back to game"); - bOptions = new Touch::TButton(5, "Options"); - bQuit = new Touch::TButton(2, "Quit to title"); - bQuitAndSaveLocally = new Touch::TButton(3, "Quit and copy map"); - bServerVisibility = new Touch::TButton(4, ""); -// bThirdPerson = new Touch::TButton(5, "Toggle 3:rd person view"); - } else { - bContinue = new Button(1, "Back to game"); - bOptions = new Button(5, "Options"); - bQuit = new Button(2, "Quit to title"); - bQuitAndSaveLocally = new Button(3, "Quit and copy map"); - bServerVisibility = new Button(4, ""); -// bThirdPerson = new Button(5, "Toggle 3:rd person view"); - } - - buttons.push_back(bContinue); - buttons.push_back(bQuit); - buttons.push_back(bOptions); - // bSound.updateImage(&minecraft->options); - bThirdPerson.updateImage(&minecraft->options); - bHideGui.updateImage(&minecraft->options); - // buttons.push_back(&bSound); - buttons.push_back(&bThirdPerson); - //buttons.push_back(&bHideGui); - - // If Back wasn't pressed, set up additional items (more than Quit to menu - // and Back to game) here - - #if !defined(APPLE_DEMO_PROMOTION) && !defined(RPI) - if (true || !wasBackPaused) { - if (minecraft->raknetInstance) { - if (minecraft->raknetInstance->isServer()) { - updateServerVisibilityText(); - buttons.push_back(bServerVisibility); - } - else { - #if !defined(DEMO_MODE) - buttons.push_back(bQuitAndSaveLocally); - #endif - } - } - } - #endif -// buttons.push_back(bThirdPerson); - - for (unsigned int i = 0; i < buttons.size(); ++i) { - // if (buttons[i] == &bSound) continue; - if (buttons[i] == &bThirdPerson) continue; - if (buttons[i] == &bHideGui) continue; - tabButtons.push_back(buttons[i]); - } -} - -void PauseScreen::setupPositions() { - saveStep = 0; - int yBase = 16; - - bContinue->width = bOptions->width = bQuit->width = /*bThirdPerson->w =*/ 160; - bQuitAndSaveLocally->width = bServerVisibility->width = 160; - - bContinue->x = (width - bContinue->width) / 2; - bContinue->y = yBase + 32 * 1; - - bOptions->x = (width - bOptions->width) / 2; - bOptions->y = yBase + 32 * 2; - - bQuit->x = (width - bQuit->width) / 2; - bQuit->y = yBase + 32 * 3; - -#if APPLE_DEMO_PROMOTION - bQuit->y += 16; -#endif - - bQuitAndSaveLocally->x = bServerVisibility->x = (width - bQuitAndSaveLocally->width) / 2; - bQuitAndSaveLocally->y = bServerVisibility->y = yBase + 32 * 4; - - // bSound.y = bThirdPerson.y = 8; - // bSound.x = 4; - // bThirdPerson.x = bSound.x + 4 + bSound.width; - // bHideGui.x = bThirdPerson.x + 4 + bThirdPerson.width; - - //bThirdPerson->x = (width - bThirdPerson->w) / 2; - //bThirdPerson->y = yBase + 32 * 4; -} - -void PauseScreen::tick() { - super::tick(); - visibleTime++; -} - -void PauseScreen::render(int xm, int ym, float a) { - renderBackground(); - - //bool isSaving = !minecraft->level.pauseSave(saveStep++); - //if (isSaving || visibleTime < 20) { - // float col = ((visibleTime % 10) + a) / 10.0f; - // col = Mth::sin(col * Mth::PI * 2) * 0.2f + 0.8f; - // int br = (int) (255 * col); - - // drawString(font, "Saving level..", 8, height - 16, br << 16 | br << 8 | br); - //} - - drawCenteredString(font, "Game menu", width / 2, 24, 0xffffff); - - super::render(xm, ym, a); -} - -void PauseScreen::buttonClicked(Button* button) { - if (button->id == bContinue->id) { - minecraft->setScreen(NULL); - //minecraft->grabMouse(); - } - if (button->id == bQuit->id) { - minecraft->leaveGame(); - } - if (button->id == bQuitAndSaveLocally->id) { - minecraft->leaveGame(true); - } - if (button->id == bOptions->id) { - minecraft->setScreen(new OptionsScreen()); - } - if (button->id == bServerVisibility->id) { - if (minecraft->raknetInstance && minecraft->netCallback && minecraft->raknetInstance->isServer()) { - ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) minecraft->netCallback; - bool allows = !ss->allowsIncomingConnections(); - ss->allowIncomingConnections(allows); - - updateServerVisibilityText(); - } - } - - if (button->id == OptionButton::ButtonId) { - ((OptionButton*)button)->toggle(&minecraft->options); - } - - //if (button->id == bThirdPerson->id) { - // minecraft->options.thirdPersonView = !minecraft->options.thirdPersonView; - //} -} - -void PauseScreen::updateServerVisibilityText() -{ - if (!minecraft->raknetInstance || !minecraft->raknetInstance->isServer()) - return; - - ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) minecraft->netCallback; - bServerVisibility->msg = ss->allowsIncomingConnections()? - "Server is visible" - : "Server is invisible"; -} +#include "PauseScreen.hpp" +#include "StartMenuScreen.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "client/Minecraft.hpp" +#include "util/Mth.hpp" +#include "network/RakNetInstance.hpp" +#include "network/ServerSideNetworkHandler.hpp" +#include "client/Options.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/screens/OptionsScreen.hpp" + +PauseScreen::PauseScreen(bool wasBackPaused) +: saveStep(0), + visibleTime(0), + bContinue(0), + bQuit(0), + bOptions(0), + bQuitAndSaveLocally(0), + bServerVisibility(0), +// bThirdPerson(0), + wasBackPaused(wasBackPaused), + // bSound(OPTIONS_SOUND_VOLUME, 1, 0), + bThirdPerson(OPTIONS_THIRD_PERSON_VIEW), + bHideGui(OPTIONS_HIDEGUI) +{ + ImageDef def; + def.setSrc(IntRectangle(160, 144, 39, 31)); + def.name = "gui/touchgui.png"; + IntRectangle& defSrc = *def.getSrc(); + + def.width = defSrc.w * 0.666667f; + def.height = defSrc.h * 0.666667f; + + // bSound.setImageDef(def, true); + defSrc.y += defSrc.h; + bThirdPerson.setImageDef(def, true); + bHideGui.setImageDef(def, true); + //void setImageDef(ImageDef& imageDef, bool setButtonSize); +} + +PauseScreen::~PauseScreen() { + delete bContinue; + delete bQuit; + delete bQuitAndSaveLocally; + delete bServerVisibility; + delete bOptions; +// delete bThirdPerson; +} + +void PauseScreen::init() { + if (/* minecraft->useTouchscreen() */ true) { + bContinue = new Touch::TButton(1, "Back to game"); + bOptions = new Touch::TButton(5, "Options"); + bQuit = new Touch::TButton(2, "Quit to title"); + bQuitAndSaveLocally = new Touch::TButton(3, "Quit and copy map"); + bServerVisibility = new Touch::TButton(4, ""); +// bThirdPerson = new Touch::TButton(5, "Toggle 3:rd person view"); + } else { + bContinue = new Button(1, "Back to game"); + bOptions = new Button(5, "Options"); + bQuit = new Button(2, "Quit to title"); + bQuitAndSaveLocally = new Button(3, "Quit and copy map"); + bServerVisibility = new Button(4, ""); +// bThirdPerson = new Button(5, "Toggle 3:rd person view"); + } + + buttons.push_back(bContinue); + buttons.push_back(bQuit); + buttons.push_back(bOptions); + // bSound.updateImage(&minecraft->options); + bThirdPerson.updateImage(&minecraft->options); + bHideGui.updateImage(&minecraft->options); + // buttons.push_back(&bSound); + buttons.push_back(&bThirdPerson); + //buttons.push_back(&bHideGui); + + // If Back wasn't pressed, set up additional items (more than Quit to menu + // and Back to game) here + + #if !defined(APPLE_DEMO_PROMOTION) && !defined(RPI) + if (true || !wasBackPaused) { + if (minecraft->raknetInstance) { + if (minecraft->raknetInstance->isServer()) { + updateServerVisibilityText(); + buttons.push_back(bServerVisibility); + } + else { + #if !defined(DEMO_MODE) + buttons.push_back(bQuitAndSaveLocally); + #endif + } + } + } + #endif +// buttons.push_back(bThirdPerson); + + for (unsigned int i = 0; i < buttons.size(); ++i) { + // if (buttons[i] == &bSound) continue; + if (buttons[i] == &bThirdPerson) continue; + if (buttons[i] == &bHideGui) continue; + tabButtons.push_back(buttons[i]); + } +} + +void PauseScreen::setupPositions() { + saveStep = 0; + int yBase = 16; + + bContinue->width = bOptions->width = bQuit->width = /*bThirdPerson->w =*/ 160; + bQuitAndSaveLocally->width = bServerVisibility->width = 160; + + bContinue->x = (width - bContinue->width) / 2; + bContinue->y = yBase + 32 * 1; + + bOptions->x = (width - bOptions->width) / 2; + bOptions->y = yBase + 32 * 2; + + bQuit->x = (width - bQuit->width) / 2; + bQuit->y = yBase + 32 * 3; + +#if APPLE_DEMO_PROMOTION + bQuit->y += 16; +#endif + + bQuitAndSaveLocally->x = bServerVisibility->x = (width - bQuitAndSaveLocally->width) / 2; + bQuitAndSaveLocally->y = bServerVisibility->y = yBase + 32 * 4; + + // bSound.y = bThirdPerson.y = 8; + // bSound.x = 4; + // bThirdPerson.x = bSound.x + 4 + bSound.width; + // bHideGui.x = bThirdPerson.x + 4 + bThirdPerson.width; + + //bThirdPerson->x = (width - bThirdPerson->w) / 2; + //bThirdPerson->y = yBase + 32 * 4; +} + +void PauseScreen::tick() { + super::tick(); + visibleTime++; +} + +void PauseScreen::render(int xm, int ym, float a) { + renderBackground(); + + //bool isSaving = !minecraft->level.pauseSave(saveStep++); + //if (isSaving || visibleTime < 20) { + // float col = ((visibleTime % 10) + a) / 10.0f; + // col = Mth::sin(col * Mth::PI * 2) * 0.2f + 0.8f; + // int br = (int) (255 * col); + + // drawString(font, "Saving level..", 8, height - 16, br << 16 | br << 8 | br); + //} + + drawCenteredString(font, "Game menu", width / 2, 24, 0xffffff); + + super::render(xm, ym, a); +} + +void PauseScreen::buttonClicked(Button* button) { + if (button->id == bContinue->id) { + minecraft->setScreen(NULL); + //minecraft->grabMouse(); + } + if (button->id == bQuit->id) { + minecraft->leaveGame(); + } + if (button->id == bQuitAndSaveLocally->id) { + minecraft->leaveGame(true); + } + if (button->id == bOptions->id) { + minecraft->setScreen(new OptionsScreen()); + } + if (button->id == bServerVisibility->id) { + if (minecraft->raknetInstance && minecraft->netCallback && minecraft->raknetInstance->isServer()) { + ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) minecraft->netCallback; + bool allows = !ss->allowsIncomingConnections(); + ss->allowIncomingConnections(allows); + + updateServerVisibilityText(); + } + } + + if (button->id == OptionButton::ButtonId) { + ((OptionButton*)button)->toggle(&minecraft->options); + } + + //if (button->id == bThirdPerson->id) { + // minecraft->options.thirdPersonView = !minecraft->options.thirdPersonView; + //} +} + +void PauseScreen::updateServerVisibilityText() +{ + if (!minecraft->raknetInstance || !minecraft->raknetInstance->isServer()) + return; + + ServerSideNetworkHandler* ss = (ServerSideNetworkHandler*) minecraft->netCallback; + bServerVisibility->msg = ss->allowsIncomingConnections()? + "Server is visible" + : "Server is invisible"; +} diff --git a/src/client/gui/screens/PauseScreen.h b/src/client/gui/screens/PauseScreen.hpp similarity index 88% rename from src/client/gui/screens/PauseScreen.h rename to src/client/gui/screens/PauseScreen.hpp index 54ad654..298f57c 100755 --- a/src/client/gui/screens/PauseScreen.h +++ b/src/client/gui/screens/PauseScreen.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.gui; -#include "../Screen.h" -#include "../components/ImageButton.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/ImageButton.hpp" class Button; diff --git a/src/client/gui/screens/PrerenderTilesScreen.h b/src/client/gui/screens/PrerenderTilesScreen.hpp similarity index 90% rename from src/client/gui/screens/PrerenderTilesScreen.h rename to src/client/gui/screens/PrerenderTilesScreen.hpp index 558e0bc..595025d 100755 --- a/src/client/gui/screens/PrerenderTilesScreen.h +++ b/src/client/gui/screens/PrerenderTilesScreen.hpp @@ -1,18 +1,18 @@ #pragma once -#include "../Screen.h" +#include "client/gui/Screen.hpp" -#include "../../renderer/GameRenderer.h" -#include "../../renderer/entity/ItemRenderer.h" -#include "../../../world/item/ItemInstance.h" -#include "../../../world/level/tile/Tile.h" +#include "client/renderer/GameRenderer.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/tile/Tile.hpp" -#include "../../../world/entity/player/Inventory.h" -#include "../../renderer/Tesselator.h" -#include "../../../world/item/crafting/Recipes.h" -#include "../../../world/item/crafting/FurnaceRecipes.h" -#include "../../../world/level/tile/LeafTile.h" -#include "../../renderer/TileRenderer.h" +#include "world/entity/player/Inventory.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/item/crafting/Recipes.hpp" +#include "world/item/crafting/FurnaceRecipes.hpp" +#include "world/level/tile/LeafTile.hpp" +#include "client/renderer/TileRenderer.hpp" class PrerenderTilesScreen: public Screen { diff --git a/src/client/gui/screens/ProgressScreen.cpp b/src/client/gui/screens/ProgressScreen.cpp index 1bab3e5..984161c 100755 --- a/src/client/gui/screens/ProgressScreen.cpp +++ b/src/client/gui/screens/ProgressScreen.cpp @@ -1,99 +1,99 @@ -#include "ProgressScreen.h" -#include "DisconnectionScreen.h" -#include "../Gui.h" -#include "../Font.h" -#include "../../Minecraft.h" -#include "../../renderer/Tesselator.h" -#include "../../../SharedConstants.h" -#include "../../renderer/Textures.h" - -ProgressScreen::ProgressScreen() -: ticks(0) -{ -} - -void ProgressScreen::render( int xm, int ym, float a ) -{ - if (minecraft->isLevelGenerated()) { - minecraft->setScreen(NULL); - return; - } - - Tesselator& t = Tesselator::instance; - renderBackground(); - - minecraft->textures->loadAndBindTexture("gui/background.png"); - - const float s = 32; - t.begin(); - t.color(0x404040); - t.vertexUV(0, (float)height, 0, 0, height / s); - t.vertexUV((float)width, (float)height, 0, width / s, height / s); - t.vertexUV((float)width, 0, 0, width / s, 0); - t.vertexUV(0, 0, 0, 0, 0); - t.draw(); - - int i = minecraft->progressStagePercentage; - - if (i >= 0) { - int w = 100; - int h = 2; - int x = width / 2 - w / 2; - int y = height / 2 + 16; - - //printf("%d, %d - %d, %d\n", x, y, x + w, y + h); - - glDisable2(GL_TEXTURE_2D); - t.begin(); - t.color(0x808080); - t.vertex((float)x, (float)y, 0); - t.vertex((float)x, (float)(y + h), 0); - t.vertex((float)(x + w), (float)(y + h), 0); - t.vertex((float)(x + w), (float)y, 0); - - t.color(0x80ff80); - t.vertex((float)x, (float)y, 0); - t.vertex((float)x, (float)(y + h), 0); - t.vertex((float)(x + i), (float)(y + h), 0); - t.vertex((float)(x + i), (float)y, 0); - t.draw(); - glEnable2(GL_TEXTURE_2D); - } - - glEnable2(GL_BLEND); - - const char* title = "Generating world"; - minecraft->font->drawShadow(title, (float)((width - minecraft->font->width(title)) / 2), (float)(height / 2 - 4 - 16), 0xffffff); - - const char* status = minecraft->getProgressMessage(); - const int progressWidth = minecraft->font->width(status); - const int progressLeft = (width - progressWidth) / 2; - const int progressY = height / 2 - 4 + 8; - minecraft->font->drawShadow(status, (float)progressLeft, (float)progressY, 0xffffff); - -#if APPLE_DEMO_PROMOTION - drawCenteredString(minecraft->font, "This demonstration version", width/2, progressY + 36, 0xffffff); - drawCenteredString(minecraft->font, "does not allow saving games", width/2, progressY + 46, 0xffffff); -#endif - - // If we're locating the server, show our famous spinner! - bool isLocating = (minecraft->getProgressStatusId() == 0); - if (isLocating) { - const int spinnerX = progressLeft + progressWidth + 6; - static const char* spinnerTexts[] = {"-", "\\", "|", "/"}; - int n = ((int)(5.5f * getTimeS()) % 4); - drawCenteredString(minecraft->font, spinnerTexts[n], spinnerX, progressY, 0xffffffff); - } - - glDisable2(GL_BLEND); - sleepMs(50); -} - -bool ProgressScreen::isInGameScreen() { return false; } - -void ProgressScreen::tick() { - // After 10 seconds of not connecting -> write an error message and go back - if (++ticks == 10 * SharedConstants::TicksPerSecond && minecraft->getProgressStatusId() == 0) { - minecraft->setScreen( new DisconnectionScreen("Could not connect to server. Try again.") ); - } -} +#include "ProgressScreen.hpp" +#include "DisconnectionScreen.hpp" +#include "client/gui/Gui.hpp" +#include "client/gui/Font.hpp" +#include "client/Minecraft.hpp" +#include "client/renderer/Tesselator.hpp" +#include "SharedConstants.hpp" +#include "client/renderer/Textures.hpp" + +ProgressScreen::ProgressScreen() +: ticks(0) +{ +} + +void ProgressScreen::render( int xm, int ym, float a ) +{ + if (minecraft->isLevelGenerated()) { + minecraft->setScreen(NULL); + return; + } + + Tesselator& t = Tesselator::instance; + renderBackground(); + + minecraft->textures->loadAndBindTexture("gui/background.png"); + + const float s = 32; + t.begin(); + t.color(0x404040); + t.vertexUV(0, (float)height, 0, 0, height / s); + t.vertexUV((float)width, (float)height, 0, width / s, height / s); + t.vertexUV((float)width, 0, 0, width / s, 0); + t.vertexUV(0, 0, 0, 0, 0); + t.draw(); + + int i = minecraft->progressStagePercentage; + + if (i >= 0) { + int w = 100; + int h = 2; + int x = width / 2 - w / 2; + int y = height / 2 + 16; + + //printf("%d, %d - %d, %d\n", x, y, x + w, y + h); + + glDisable2(GL_TEXTURE_2D); + t.begin(); + t.color(0x808080); + t.vertex((float)x, (float)y, 0); + t.vertex((float)x, (float)(y + h), 0); + t.vertex((float)(x + w), (float)(y + h), 0); + t.vertex((float)(x + w), (float)y, 0); + + t.color(0x80ff80); + t.vertex((float)x, (float)y, 0); + t.vertex((float)x, (float)(y + h), 0); + t.vertex((float)(x + i), (float)(y + h), 0); + t.vertex((float)(x + i), (float)y, 0); + t.draw(); + glEnable2(GL_TEXTURE_2D); + } + + glEnable2(GL_BLEND); + + const char* title = "Generating world"; + minecraft->font->drawShadow(title, (float)((width - minecraft->font->width(title)) / 2), (float)(height / 2 - 4 - 16), 0xffffff); + + const char* status = minecraft->getProgressMessage(); + const int progressWidth = minecraft->font->width(status); + const int progressLeft = (width - progressWidth) / 2; + const int progressY = height / 2 - 4 + 8; + minecraft->font->drawShadow(status, (float)progressLeft, (float)progressY, 0xffffff); + +#if APPLE_DEMO_PROMOTION + drawCenteredString(minecraft->font, "This demonstration version", width/2, progressY + 36, 0xffffff); + drawCenteredString(minecraft->font, "does not allow saving games", width/2, progressY + 46, 0xffffff); +#endif + + // If we're locating the server, show our famous spinner! + bool isLocating = (minecraft->getProgressStatusId() == 0); + if (isLocating) { + const int spinnerX = progressLeft + progressWidth + 6; + static const char* spinnerTexts[] = {"-", "\\", "|", "/"}; + int n = ((int)(5.5f * getTimeS()) % 4); + drawCenteredString(minecraft->font, spinnerTexts[n], spinnerX, progressY, 0xffffffff); + } + + glDisable2(GL_BLEND); + sleepMs(50); +} + +bool ProgressScreen::isInGameScreen() { return false; } + +void ProgressScreen::tick() { + // After 10 seconds of not connecting -> write an error message and go back + if (++ticks == 10 * SharedConstants::TicksPerSecond && minecraft->getProgressStatusId() == 0) { + minecraft->setScreen( new DisconnectionScreen("Could not connect to server. Try again.") ); + } +} diff --git a/src/client/gui/screens/ProgressScreen.h b/src/client/gui/screens/ProgressScreen.hpp similarity index 87% rename from src/client/gui/screens/ProgressScreen.h rename to src/client/gui/screens/ProgressScreen.hpp index 8e4d9f4..bd503c0 100755 --- a/src/client/gui/screens/ProgressScreen.h +++ b/src/client/gui/screens/ProgressScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Screen.h" +#include "client/gui/Screen.hpp" class ProgressScreen: public Screen { diff --git a/src/client/gui/screens/ScreenChooser.cpp b/src/client/gui/screens/ScreenChooser.cpp index f404618..afaf8e9 100755 --- a/src/client/gui/screens/ScreenChooser.cpp +++ b/src/client/gui/screens/ScreenChooser.cpp @@ -1,64 +1,64 @@ -#include "ScreenChooser.h" -#include "StartMenuScreen.h" -#include "MinecraftClient.h" -#include "SelectWorldScreen.h" -#include "JoinGameScreen.h" -#include "PauseScreen.h" -#include "RenameMPLevelScreen.h" -#include "ConsoleScreen.h" -#include "IngameBlockSelectionScreen.h" -#include "JoinByIPScreen.h" -#include "touch/TouchStartMenuScreen.h" -#include "touch/TouchSelectWorldScreen.h" -#include "touch/TouchJoinGameScreen.h" -#include "touch/TouchIngameBlockSelectionScreen.h" - -#include "../../Minecraft.h" - -#include - -Screen* ScreenChooser::createScreen( ScreenId id ) -{ - Screen* screen = NULL; - - // :sob: - if (/* _mc->useTouchscreen() */ true) { - switch (id) { - case SCREEN_STARTMENU: screen = new Touch::StartMenuScreen(); break; - case SCREEN_SELECTWORLD: screen = new Touch::SelectWorldScreen();break; - case SCREEN_JOINGAME: screen = new Touch::JoinGameScreen(); break; - case SCREEN_PAUSE: screen = new PauseScreen(false); break; - case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break; - case SCREEN_BLOCKSELECTION: screen = new Touch::IngameBlockSelectionScreen(); break; - case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break; - case SCREEN_CONSOLE: screen = new ConsoleScreen(); break; - case SCREEN_NONE: - default: - // Do nothing - break; - } - } else { - switch (id) { - case SCREEN_STARTMENU: screen = new StartMenuScreen(); break; - case SCREEN_SELECTWORLD: screen = new SelectWorldScreen();break; - case SCREEN_JOINGAME: screen = new JoinGameScreen(); break; - case SCREEN_PAUSE: screen = new PauseScreen(false); break; - case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break; - case SCREEN_BLOCKSELECTION: screen = new IngameBlockSelectionScreen(); break; - case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break; - case SCREEN_CONSOLE: screen = new ConsoleScreen(); break; - case SCREEN_NONE: - default: - // Do nothing - break; - } - } - return screen; -} - -Screen* ScreenChooser::setScreen(ScreenId id) -{ - Screen* screen = createScreen(id); - _mc.setScreen(screen); - return screen; -} +#include "ScreenChooser.hpp" +#include "StartMenuScreen.hpp" +#include "MinecraftClient.hpp" +#include "SelectWorldScreen.hpp" +#include "JoinGameScreen.hpp" +#include "PauseScreen.hpp" +#include "RenameMPLevelScreen.hpp" +#include "ConsoleScreen.hpp" +#include "IngameBlockSelectionScreen.hpp" +#include "JoinByIPScreen.hpp" +#include "touch/TouchStartMenuScreen.hpp" +#include "touch/TouchSelectWorldScreen.hpp" +#include "touch/TouchJoinGameScreen.hpp" +#include "touch/TouchIngameBlockSelectionScreen.hpp" + +#include "client/Minecraft.hpp" + +#include + +Screen* ScreenChooser::createScreen( ScreenId id ) +{ + Screen* screen = NULL; + + // :sob: + if (/* _mc->useTouchscreen() */ true) { + switch (id) { + case SCREEN_STARTMENU: screen = new Touch::StartMenuScreen(); break; + case SCREEN_SELECTWORLD: screen = new Touch::SelectWorldScreen();break; + case SCREEN_JOINGAME: screen = new Touch::JoinGameScreen(); break; + case SCREEN_PAUSE: screen = new PauseScreen(false); break; + case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break; + case SCREEN_BLOCKSELECTION: screen = new Touch::IngameBlockSelectionScreen(); break; + case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break; + case SCREEN_CONSOLE: screen = new ConsoleScreen(); break; + case SCREEN_NONE: + default: + // Do nothing + break; + } + } else { + switch (id) { + case SCREEN_STARTMENU: screen = new StartMenuScreen(); break; + case SCREEN_SELECTWORLD: screen = new SelectWorldScreen();break; + case SCREEN_JOINGAME: screen = new JoinGameScreen(); break; + case SCREEN_PAUSE: screen = new PauseScreen(false); break; + case SCREEN_PAUSEPREV: screen = new PauseScreen(true); break; + case SCREEN_BLOCKSELECTION: screen = new IngameBlockSelectionScreen(); break; + case SCREEN_JOINBYIP: screen = new JoinByIPScreen(); break; + case SCREEN_CONSOLE: screen = new ConsoleScreen(); break; + case SCREEN_NONE: + default: + // Do nothing + break; + } + } + return screen; +} + +Screen* ScreenChooser::setScreen(ScreenId id) +{ + Screen* screen = createScreen(id); + _mc.setScreen(screen); + return screen; +} diff --git a/src/client/gui/screens/ScreenChooser.h b/src/client/gui/screens/ScreenChooser.hpp similarity index 100% rename from src/client/gui/screens/ScreenChooser.h rename to src/client/gui/screens/ScreenChooser.hpp diff --git a/src/client/gui/screens/SelectWorldScreen.cpp b/src/client/gui/screens/SelectWorldScreen.cpp index 10612f0..f6df45a 100755 --- a/src/client/gui/screens/SelectWorldScreen.cpp +++ b/src/client/gui/screens/SelectWorldScreen.cpp @@ -1,469 +1,469 @@ -#include "SelectWorldScreen.h" -#include "MinecraftClient.h" -#include "StartMenuScreen.h" -#include "ProgressScreen.h" -#include "DialogDefinitions.h" -#include "../../renderer/Tesselator.h" -#include "../../../AppPlatform.h" -#include "../../../util/StringUtils.h" -#include "../../../util/Mth.h" -#include "../../../platform/input/Mouse.h" -#include "../../../Performance.h" -#include "../../../world/level/LevelSettings.h" - -#include -#include -#include "../../renderer/Textures.h" -#include "SimpleChooseLevelScreen.h" - -static float Max(float a, float b) { - return a>b? a : b; -} - -// -// World Selection List -// -WorldSelectionList::WorldSelectionList( MinecraftClient& minecraft, int width, int height ) -: _height(height), - hasPickedLevel(false), - currentTick(0), - stoppedTick(-1), - mode(0), - RolledSelectionListH(minecraft, width, height, 0, width, 26, height-32, 120) -{ -} - -int WorldSelectionList::getNumberOfItems() { - return (int)levels.size(); -} - -void WorldSelectionList::selectItem( int item, bool doubleClick ) { - //LOGI("sel: %d, item %d\n", selectedItem, item); - if (selectedItem < 0 || (selectedItem != item)) - return; - - if (!hasPickedLevel) { - hasPickedLevel = true; - pickedLevel = levels[item]; - } -} - -bool WorldSelectionList::isSelectedItem( int item ) { - return item == selectedItem; -} - -void WorldSelectionList::renderItem( int i, int x, int y, int h, Tesselator& t ) { - - int centerx = x + itemWidth/2; - - float a0 = Max(1.1f - std::abs( width / 2 - centerx ) * 0.0055f, 0.2f); - if (a0 > 1) a0 = 1; - int textColor = (int)(255.0f * a0) * 0x010101; - int textColor2 = (int)(140.0f * a0) * 0x010101; - - const int TY = y + 42; - const int TX = centerx - itemWidth / 2 + 5; - - StringVector v = _descriptions[i]; - drawString(minecraft->font, v[0].c_str(), TX, TY + 0, textColor); - drawString(minecraft->font, v[1].c_str(), TX, TY + 10, textColor2); - drawString(minecraft->font, v[2].c_str(), TX, TY + 20, textColor2); - drawString(minecraft->font, v[3].c_str(), TX, TY + 30, textColor2); - - minecraft->textures->loadAndBindTexture(_imageNames[i]); - t.color(0.3f, 1.0f, 0.2f); - - //float x0 = (float)x; - //float x1 = (float)x + (float)itemWidth; - - const float IY = (float)y - 8; - t.begin(); - t.color(textColor); - t.vertexUV((float)(centerx-32), IY, blitOffset, 0, 0); - t.vertexUV((float)(centerx-32), IY + 48, blitOffset, 0, 1); - t.vertexUV((float)(centerx+32), IY + 48, blitOffset, 1, 1); - t.vertexUV((float)(centerx+32), IY, blitOffset, 1, 0); - t.draw(); -} - -void WorldSelectionList::stepLeft() { - if (selectedItem > 0) { - td.start = xo; - td.stop = xo - itemWidth; - td.cur = 0; - td.dur = 8; - mode = 1; - tweenInited(); - } -} - -void WorldSelectionList::stepRight() { - if (selectedItem >= 0 && selectedItem < getNumberOfItems()-1) { - td.start = xo; - td.stop = xo + itemWidth; - td.cur = 0; - td.dur = 8; - mode = 1; - tweenInited(); - } -} - -void WorldSelectionList::commit() { - for (unsigned int i = 0; i < levels.size(); ++i) { - LevelSummary& level = levels[i]; - - std::stringstream ss; - ss << level.name << "/preview.png"; - TextureId id = Textures::InvalidId;//minecraft->textures->loadTexture(ss.str(), false); - - if (id != Textures::InvalidId) { - _imageNames.push_back( ss.str() ); - } else { - _imageNames.push_back("gui/default_world.png"); - } - - StringVector lines; - lines.push_back(level.name); - lines.push_back(minecraft->platform()->getDateString(level.lastPlayed)); - lines.push_back(level.id); - lines.push_back(LevelSettings::gameTypeToString(level.gameType)); - _descriptions.push_back(lines); - - selectedItem = 0; - } -} - -static float quadraticInOut(float t, float dur, float start, float stop) { - const float delta = stop - start; - const float T = (t / dur) * 2.0f; - if (T < 1) return 0.5f*delta*T*T + start; - return -0.5f*delta * ((T-1)*(T-3) - 1) + start; -} - -void WorldSelectionList::tick() -{ - RolledSelectionListH::tick(); - - ++currentTick; - - if (Mouse::isButtonDown(MouseAction::ACTION_LEFT) || dragState == 0) - return; - - // Handle the tween (when in "mode 1") - selectedItem = -1; - if (mode == 1) { - if (++td.cur == td.dur) { - mode = 0; - xInertia = 0; - xoo = xo = td.stop; - selectedItem = getItemAtPosition(width/2, height/2); - } else { - tweenInited(); - } - return; - } - - // It's still going fast, let it run - float speed = Mth::abs(xInertia); - bool slowEnoughToBeBothered = speed < 5.0f; - if (!slowEnoughToBeBothered) { - xInertia = xInertia * .9f; - return; - } - - xInertia *= 0.8f; - - if (speed < 1 && dragState < 0) { - const int offsetx = (width-itemWidth) / 2; - const float pxo = xo + offsetx; - int index = getItemAtXPositionRaw((int)(pxo - 10*xInertia)); - int indexPos = index*itemWidth; - - // Pick closest - float diff = (float)indexPos - pxo; - if (diff < -itemWidth/2) { - diff += itemWidth; - index++; - //indexPos += itemWidth; - } - if (Mth::abs(diff) < 1 && speed < 0.1f) { - selectedItem = getItemAtPosition(width/2, height/2); - return; - } - - td.start = xo; - td.stop = xo + diff; - td.cur = 0; - td.dur = (float) Mth::Min(7, 1 + (int)(Mth::abs(diff) * 0.25f)); - mode = 1; - //LOGI("inited-t %d\n", dragState); - tweenInited(); - } -} - -float WorldSelectionList::getPos( float alpha ) -{ - if (mode != 1) return RolledSelectionListH::getPos(alpha); - - float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); - float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); - return x0 + (x1-x0)*alpha; -} - -bool WorldSelectionList::capXPosition() { - bool capped = RolledSelectionListH::capXPosition(); - if (capped) mode = 0; - return capped; -} - -void WorldSelectionList::tweenInited() { - float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); - float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); - xInertia = x0-x1; // yes, it's all backwards and messed up.. -} - -// -// Select World Screen -// -SelectWorldScreen::SelectWorldScreen() -: bDelete (1, "Delete"), - bCreate (2, "Create new"), - bBack (3, "Back"), - bWorldView(4, ""), - worldsList(NULL), - _hasStartedLevel(false) -{ - bDelete.active = false; -} - -SelectWorldScreen::~SelectWorldScreen() -{ - delete worldsList; -} - -void SelectWorldScreen::buttonClicked(Button* button) -{ - if (button->id == bCreate.id) { - // open in-game world-creation screen instead of using platform dialog - if (!_hasStartedLevel) { - std::string name = getUniqueLevelName("world"); - minecraft->setScreen(new SimpleChooseLevelScreen(name)); - } - } - if (button->id == bDelete.id) { - if (isIndexValid(worldsList->selectedItem)) { - LevelSummary level = worldsList->levels[worldsList->selectedItem]; - LOGI("level: %s, %s\n", level.id.c_str(), level.name.c_str()); - minecraft->setScreen( new DeleteWorldScreen(level) ); - } - } - if (button->id == bBack.id) { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } - if (button->id == bWorldView.id) { - // Try to "click" the item in the middle - worldsList->selectItem( worldsList->getItemAtPosition(width/2, height/2), false ); - } -} - -bool SelectWorldScreen::handleBackEvent(bool isDown) -{ - if (!isDown) - { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } - return true; -} - -bool SelectWorldScreen::isIndexValid( int index ) -{ - return worldsList && index >= 0 && index < worldsList->getNumberOfItems(); -} - -static char ILLEGAL_FILE_CHARACTERS[] = { - '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' -}; - -void SelectWorldScreen::tick() -{ - worldsList->tick(); - - if (worldsList->hasPickedLevel) { - minecraft->selectLevel(worldsList->pickedLevel.id, worldsList->pickedLevel.name, LevelSettings::None()); - minecraft->hostMultiplayer(); - minecraft->setScreen(new ProgressScreen()); - _hasStartedLevel = true; - return; - } - - // copy the currently selected item - LevelSummary selectedWorld; - //bool hasSelection = false; - if (isIndexValid(worldsList->selectedItem)) - { - selectedWorld = worldsList->levels[worldsList->selectedItem]; - //hasSelection = true; - } - - bDelete.active = isIndexValid(worldsList->selectedItem); -} - -void SelectWorldScreen::init() -{ - worldsList = new WorldSelectionList(minecraft, width, height); - loadLevelSource(); - worldsList->commit(); - - buttons.push_back(&bDelete); - buttons.push_back(&bCreate); - buttons.push_back(&bBack); - - _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); - - tabButtons.push_back(&bWorldView); - tabButtons.push_back(&bDelete); - tabButtons.push_back(&bCreate); - tabButtons.push_back(&bBack); -} - -void SelectWorldScreen::setupPositions() { - int yBase = height - 28; - - //#ifdef ANDROID - bCreate.y = yBase; - bBack.y = yBase; - bDelete.y = yBase; - - bBack.width = bDelete.width = bCreate.width = 84; - //bDelete.h = bCreate.h = bBack.h = 24; - //#endif - - // Center buttons - bDelete.x = width / 2 - 4 - bDelete.width - bDelete.width / 2; - bCreate.x = width / 2 - bCreate.width / 2; - bBack.x = width / 2 + 4 + bCreate.width - bBack.width / 2; -} - -void SelectWorldScreen::render( int xm, int ym, float a ) -{ - //Performance::watches.get("sws-full").start(); - //Performance::watches.get("sws-renderbg").start(); - renderBackground(); - //Performance::watches.get("sws-renderbg").stop(); - //Performance::watches.get("sws-worlds").start(); - - worldsList->setComponentSelected(bWorldView.selected); - // #ifdef PLATFORM_DESKTOP - - // desktop: render the list normally (mouse wheel handled separately below) - if (_mouseHasBeenUp) - worldsList->render(xm, ym, a); - else { - worldsList->render(0, 0, a); - _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); - } - // #else - // if (_mouseHasBeenUp) - // worldsList->render(xm, ym, a); - // else { - // worldsList->render(0, 0, a); - // _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); - // } - // #endif - - //Performance::watches.get("sws-worlds").stop(); - //Performance::watches.get("sws-screen").start(); - Screen::render(xm, ym, a); - //Performance::watches.get("sws-screen").stop(); - - //Performance::watches.get("sws-string").start(); - drawCenteredString(minecraft->font, "Select world", width / 2, 8, 0xffffffff); - //Performance::watches.get("sws-string").stop(); - - //Performance::watches.get("sws-full").stop(); - //Performance::watches.printEvery(128); -} - -void SelectWorldScreen::loadLevelSource() -{ - LevelStorageSource* levelSource = minecraft->getLevelSource(); - levelSource->getLevelList(levels); - std::sort(levels.begin(), levels.end()); - - for (unsigned int i = 0; i < levels.size(); ++i) { - if (levels[i].id != LevelStorageSource::TempLevelId) - worldsList->levels.push_back( levels[i] ); - } -} - - -std::string SelectWorldScreen::getUniqueLevelName( const std::string& level ) -{ - std::set Set; - for (unsigned int i = 0; i < levels.size(); ++i) - Set.insert(levels[i].id); - - std::string s = level; - while ( Set.find(s) != Set.end() ) - s += "-"; - return s; -} - -bool SelectWorldScreen::isInGameScreen() { return true; } - -void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym) -{ - if (!worldsList) - return; - if (dy == 0) - return; - int num = worldsList->getNumberOfItems(); - int idx = worldsList->selectedItem; - if (dy > 0) { - if (idx > 0) { - idx--; - worldsList->stepLeft(); - } - } else { - if (idx < num - 1) { - idx++; - worldsList->stepRight(); - } - } - worldsList->selectedItem = idx; -} - -void SelectWorldScreen::keyPressed( int eventKey ) -{ - if (bWorldView.selected) { - if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_RIGHT)) - worldsList->stepLeft(); - if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_LEFT)) - worldsList->stepRight(); - } - - Screen::keyPressed(eventKey); -} - -// -// Delete World Screen -// -DeleteWorldScreen::DeleteWorldScreen(const LevelSummary& level) -: ConfirmScreen(NULL, "Are you sure you want to delete this world?", - "'" + level.name + "' will be lost forever!", - "Delete", "Cancel", 0), - _level(level) -{ - tabButtonIndex = 1; -} - -void DeleteWorldScreen::postResult( bool isOk ) -{ - if (isOk) { - LevelStorageSource* storageSource = minecraft->getLevelSource(); - storageSource->deleteLevel(_level.id); - } - minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); -} +#include "SelectWorldScreen.hpp" +#include "MinecraftClient.hpp" +#include "StartMenuScreen.hpp" +#include "ProgressScreen.hpp" +#include "DialogDefinitions.hpp" +#include "client/renderer/Tesselator.hpp" +#include "AppPlatform.hpp" +#include "util/StringUtils.hpp" +#include "util/Mth.hpp" +#include "platform/input/Mouse.hpp" +#include "Performance.hpp" +#include "world/level/LevelSettings.hpp" + +#include +#include +#include "client/renderer/Textures.hpp" +#include "SimpleChooseLevelScreen.hpp" + +static float Max(float a, float b) { + return a>b? a : b; +} + +// +// World Selection List +// +WorldSelectionList::WorldSelectionList( MinecraftClient& minecraft, int width, int height ) +: _height(height), + hasPickedLevel(false), + currentTick(0), + stoppedTick(-1), + mode(0), + RolledSelectionListH(minecraft, width, height, 0, width, 26, height-32, 120) +{ +} + +int WorldSelectionList::getNumberOfItems() { + return (int)levels.size(); +} + +void WorldSelectionList::selectItem( int item, bool doubleClick ) { + //LOGI("sel: %d, item %d\n", selectedItem, item); + if (selectedItem < 0 || (selectedItem != item)) + return; + + if (!hasPickedLevel) { + hasPickedLevel = true; + pickedLevel = levels[item]; + } +} + +bool WorldSelectionList::isSelectedItem( int item ) { + return item == selectedItem; +} + +void WorldSelectionList::renderItem( int i, int x, int y, int h, Tesselator& t ) { + + int centerx = x + itemWidth/2; + + float a0 = Max(1.1f - std::abs( width / 2 - centerx ) * 0.0055f, 0.2f); + if (a0 > 1) a0 = 1; + int textColor = (int)(255.0f * a0) * 0x010101; + int textColor2 = (int)(140.0f * a0) * 0x010101; + + const int TY = y + 42; + const int TX = centerx - itemWidth / 2 + 5; + + StringVector v = _descriptions[i]; + drawString(minecraft->font, v[0].c_str(), TX, TY + 0, textColor); + drawString(minecraft->font, v[1].c_str(), TX, TY + 10, textColor2); + drawString(minecraft->font, v[2].c_str(), TX, TY + 20, textColor2); + drawString(minecraft->font, v[3].c_str(), TX, TY + 30, textColor2); + + minecraft->textures->loadAndBindTexture(_imageNames[i]); + t.color(0.3f, 1.0f, 0.2f); + + //float x0 = (float)x; + //float x1 = (float)x + (float)itemWidth; + + const float IY = (float)y - 8; + t.begin(); + t.color(textColor); + t.vertexUV((float)(centerx-32), IY, blitOffset, 0, 0); + t.vertexUV((float)(centerx-32), IY + 48, blitOffset, 0, 1); + t.vertexUV((float)(centerx+32), IY + 48, blitOffset, 1, 1); + t.vertexUV((float)(centerx+32), IY, blitOffset, 1, 0); + t.draw(); +} + +void WorldSelectionList::stepLeft() { + if (selectedItem > 0) { + td.start = xo; + td.stop = xo - itemWidth; + td.cur = 0; + td.dur = 8; + mode = 1; + tweenInited(); + } +} + +void WorldSelectionList::stepRight() { + if (selectedItem >= 0 && selectedItem < getNumberOfItems()-1) { + td.start = xo; + td.stop = xo + itemWidth; + td.cur = 0; + td.dur = 8; + mode = 1; + tweenInited(); + } +} + +void WorldSelectionList::commit() { + for (unsigned int i = 0; i < levels.size(); ++i) { + LevelSummary& level = levels[i]; + + std::stringstream ss; + ss << level.name << "/preview.png"; + TextureId id = Textures::InvalidId;//minecraft->textures->loadTexture(ss.str(), false); + + if (id != Textures::InvalidId) { + _imageNames.push_back( ss.str() ); + } else { + _imageNames.push_back("gui/default_world.png"); + } + + StringVector lines; + lines.push_back(level.name); + lines.push_back(minecraft->platform()->getDateString(level.lastPlayed)); + lines.push_back(level.id); + lines.push_back(LevelSettings::gameTypeToString(level.gameType)); + _descriptions.push_back(lines); + + selectedItem = 0; + } +} + +static float quadraticInOut(float t, float dur, float start, float stop) { + const float delta = stop - start; + const float T = (t / dur) * 2.0f; + if (T < 1) return 0.5f*delta*T*T + start; + return -0.5f*delta * ((T-1)*(T-3) - 1) + start; +} + +void WorldSelectionList::tick() +{ + RolledSelectionListH::tick(); + + ++currentTick; + + if (Mouse::isButtonDown(MouseAction::ACTION_LEFT) || dragState == 0) + return; + + // Handle the tween (when in "mode 1") + selectedItem = -1; + if (mode == 1) { + if (++td.cur == td.dur) { + mode = 0; + xInertia = 0; + xoo = xo = td.stop; + selectedItem = getItemAtPosition(width/2, height/2); + } else { + tweenInited(); + } + return; + } + + // It's still going fast, let it run + float speed = Mth::abs(xInertia); + bool slowEnoughToBeBothered = speed < 5.0f; + if (!slowEnoughToBeBothered) { + xInertia = xInertia * .9f; + return; + } + + xInertia *= 0.8f; + + if (speed < 1 && dragState < 0) { + const int offsetx = (width-itemWidth) / 2; + const float pxo = xo + offsetx; + int index = getItemAtXPositionRaw((int)(pxo - 10*xInertia)); + int indexPos = index*itemWidth; + + // Pick closest + float diff = (float)indexPos - pxo; + if (diff < -itemWidth/2) { + diff += itemWidth; + index++; + //indexPos += itemWidth; + } + if (Mth::abs(diff) < 1 && speed < 0.1f) { + selectedItem = getItemAtPosition(width/2, height/2); + return; + } + + td.start = xo; + td.stop = xo + diff; + td.cur = 0; + td.dur = (float) Mth::Min(7, 1 + (int)(Mth::abs(diff) * 0.25f)); + mode = 1; + //LOGI("inited-t %d\n", dragState); + tweenInited(); + } +} + +float WorldSelectionList::getPos( float alpha ) +{ + if (mode != 1) return RolledSelectionListH::getPos(alpha); + + float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); + float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); + return x0 + (x1-x0)*alpha; +} + +bool WorldSelectionList::capXPosition() { + bool capped = RolledSelectionListH::capXPosition(); + if (capped) mode = 0; + return capped; +} + +void WorldSelectionList::tweenInited() { + float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); + float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); + xInertia = x0-x1; // yes, it's all backwards and messed up.. +} + +// +// Select World Screen +// +SelectWorldScreen::SelectWorldScreen() +: bDelete (1, "Delete"), + bCreate (2, "Create new"), + bBack (3, "Back"), + bWorldView(4, ""), + worldsList(NULL), + _hasStartedLevel(false) +{ + bDelete.active = false; +} + +SelectWorldScreen::~SelectWorldScreen() +{ + delete worldsList; +} + +void SelectWorldScreen::buttonClicked(Button* button) +{ + if (button->id == bCreate.id) { + // open in-game world-creation screen instead of using platform dialog + if (!_hasStartedLevel) { + std::string name = getUniqueLevelName("world"); + minecraft->setScreen(new SimpleChooseLevelScreen(name)); + } + } + if (button->id == bDelete.id) { + if (isIndexValid(worldsList->selectedItem)) { + LevelSummary level = worldsList->levels[worldsList->selectedItem]; + LOGI("level: %s, %s\n", level.id.c_str(), level.name.c_str()); + minecraft->setScreen( new DeleteWorldScreen(level) ); + } + } + if (button->id == bBack.id) { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } + if (button->id == bWorldView.id) { + // Try to "click" the item in the middle + worldsList->selectItem( worldsList->getItemAtPosition(width/2, height/2), false ); + } +} + +bool SelectWorldScreen::handleBackEvent(bool isDown) +{ + if (!isDown) + { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } + return true; +} + +bool SelectWorldScreen::isIndexValid( int index ) +{ + return worldsList && index >= 0 && index < worldsList->getNumberOfItems(); +} + +static char ILLEGAL_FILE_CHARACTERS[] = { + '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' +}; + +void SelectWorldScreen::tick() +{ + worldsList->tick(); + + if (worldsList->hasPickedLevel) { + minecraft->selectLevel(worldsList->pickedLevel.id, worldsList->pickedLevel.name, LevelSettings::None()); + minecraft->hostMultiplayer(); + minecraft->setScreen(new ProgressScreen()); + _hasStartedLevel = true; + return; + } + + // copy the currently selected item + LevelSummary selectedWorld; + //bool hasSelection = false; + if (isIndexValid(worldsList->selectedItem)) + { + selectedWorld = worldsList->levels[worldsList->selectedItem]; + //hasSelection = true; + } + + bDelete.active = isIndexValid(worldsList->selectedItem); +} + +void SelectWorldScreen::init() +{ + worldsList = new WorldSelectionList(minecraft, width, height); + loadLevelSource(); + worldsList->commit(); + + buttons.push_back(&bDelete); + buttons.push_back(&bCreate); + buttons.push_back(&bBack); + + _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); + + tabButtons.push_back(&bWorldView); + tabButtons.push_back(&bDelete); + tabButtons.push_back(&bCreate); + tabButtons.push_back(&bBack); +} + +void SelectWorldScreen::setupPositions() { + int yBase = height - 28; + + //#ifdef ANDROID + bCreate.y = yBase; + bBack.y = yBase; + bDelete.y = yBase; + + bBack.width = bDelete.width = bCreate.width = 84; + //bDelete.h = bCreate.h = bBack.h = 24; + //#endif + + // Center buttons + bDelete.x = width / 2 - 4 - bDelete.width - bDelete.width / 2; + bCreate.x = width / 2 - bCreate.width / 2; + bBack.x = width / 2 + 4 + bCreate.width - bBack.width / 2; +} + +void SelectWorldScreen::render( int xm, int ym, float a ) +{ + //Performance::watches.get("sws-full").start(); + //Performance::watches.get("sws-renderbg").start(); + renderBackground(); + //Performance::watches.get("sws-renderbg").stop(); + //Performance::watches.get("sws-worlds").start(); + + worldsList->setComponentSelected(bWorldView.selected); + // #ifdef PLATFORM_DESKTOP + + // desktop: render the list normally (mouse wheel handled separately below) + if (_mouseHasBeenUp) + worldsList->render(xm, ym, a); + else { + worldsList->render(0, 0, a); + _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); + } + // #else + // if (_mouseHasBeenUp) + // worldsList->render(xm, ym, a); + // else { + // worldsList->render(0, 0, a); + // _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); + // } + // #endif + + //Performance::watches.get("sws-worlds").stop(); + //Performance::watches.get("sws-screen").start(); + Screen::render(xm, ym, a); + //Performance::watches.get("sws-screen").stop(); + + //Performance::watches.get("sws-string").start(); + drawCenteredString(minecraft->font, "Select world", width / 2, 8, 0xffffffff); + //Performance::watches.get("sws-string").stop(); + + //Performance::watches.get("sws-full").stop(); + //Performance::watches.printEvery(128); +} + +void SelectWorldScreen::loadLevelSource() +{ + LevelStorageSource* levelSource = minecraft->getLevelSource(); + levelSource->getLevelList(levels); + std::sort(levels.begin(), levels.end()); + + for (unsigned int i = 0; i < levels.size(); ++i) { + if (levels[i].id != LevelStorageSource::TempLevelId) + worldsList->levels.push_back( levels[i] ); + } +} + + +std::string SelectWorldScreen::getUniqueLevelName( const std::string& level ) +{ + std::set Set; + for (unsigned int i = 0; i < levels.size(); ++i) + Set.insert(levels[i].id); + + std::string s = level; + while ( Set.find(s) != Set.end() ) + s += "-"; + return s; +} + +bool SelectWorldScreen::isInGameScreen() { return true; } + +void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym) +{ + if (!worldsList) + return; + if (dy == 0) + return; + int num = worldsList->getNumberOfItems(); + int idx = worldsList->selectedItem; + if (dy > 0) { + if (idx > 0) { + idx--; + worldsList->stepLeft(); + } + } else { + if (idx < num - 1) { + idx++; + worldsList->stepRight(); + } + } + worldsList->selectedItem = idx; +} + +void SelectWorldScreen::keyPressed( int eventKey ) +{ + if (bWorldView.selected) { + if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_RIGHT)) + worldsList->stepLeft(); + if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_LEFT)) + worldsList->stepRight(); + } + + Screen::keyPressed(eventKey); +} + +// +// Delete World Screen +// +DeleteWorldScreen::DeleteWorldScreen(const LevelSummary& level) +: ConfirmScreen(NULL, "Are you sure you want to delete this world?", + "'" + level.name + "' will be lost forever!", + "Delete", "Cancel", 0), + _level(level) +{ + tabButtonIndex = 1; +} + +void DeleteWorldScreen::postResult( bool isOk ) +{ + if (isOk) { + LevelStorageSource* storageSource = minecraft->getLevelSource(); + storageSource->deleteLevel(_level.id); + } + minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); +} diff --git a/src/client/gui/screens/SelectWorldScreen.h b/src/client/gui/screens/SelectWorldScreen.hpp similarity index 89% rename from src/client/gui/screens/SelectWorldScreen.h rename to src/client/gui/screens/SelectWorldScreen.hpp index 563514c..3355841 100755 --- a/src/client/gui/screens/SelectWorldScreen.h +++ b/src/client/gui/screens/SelectWorldScreen.hpp @@ -1,10 +1,10 @@ #pragma once -#include "../Screen.h" -#include "../TweenData.h" -#include "../components/Button.h" -#include "../components/RolledSelectionListH.h" -#include "../../../world/level/storage/LevelStorageSource.h" +#include "client/gui/Screen.hpp" +#include "client/gui/TweenData.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/RolledSelectionListH.hpp" +#include "world/level/storage/LevelStorageSource.hpp" class SelectWorldScreen; @@ -56,7 +56,7 @@ private: // // Delete World screen // -#include "ConfirmScreen.h" +#include "ConfirmScreen.hpp" class DeleteWorldScreen: public ConfirmScreen { public: diff --git a/src/client/gui/screens/SimpleChooseLevelScreen.cpp b/src/client/gui/screens/SimpleChooseLevelScreen.cpp index c5a1278..64c3abe 100755 --- a/src/client/gui/screens/SimpleChooseLevelScreen.cpp +++ b/src/client/gui/screens/SimpleChooseLevelScreen.cpp @@ -1,260 +1,260 @@ -#include "SimpleChooseLevelScreen.h" -#include "ProgressScreen.h" -#include "ScreenChooser.h" -#include "../components/Button.h" -#include "../components/ImageButton.h" -#include "../../Minecraft.h" -#include "../../../world/level/LevelSettings.h" -#include "../../../platform/time.h" -#include "../../../platform/input/Keyboard.h" -#include "../../../platform/log.h" - -SimpleChooseLevelScreen::SimpleChooseLevelScreen(const std::string& levelName) -: bHeader(0), - bGamemode(0), - bCheats(0), - bBack(0), - bCreate(0), - levelName(levelName), - hasChosen(false), - gamemode(GameType::Survival), - cheatsEnabled(false), - tLevelName(0, "World name"), - tSeed(1, "World seed") -{ -} - -SimpleChooseLevelScreen::~SimpleChooseLevelScreen() -{ - if (bHeader) delete bHeader; - delete bGamemode; - delete bCheats; - delete bBack; - delete bCreate; -} - -void SimpleChooseLevelScreen::init() -{ - // make sure the base class loads the existing level list; the - // derived screen uses ChooseLevelScreen::getUniqueLevelName(), which - // depends on `levels` being populated. omitting this used to result - // in duplicate IDs ("creating the second world would load the - // first") when the name already existed. - ChooseLevelScreen::init(); - - tLevelName.text = "New world"; - - // header + close button - bHeader = new Touch::THeader(0, "Create World"); - // create the back/X button as ImageButton like CreditsScreen - bBack = new ImageButton(2, ""); - { - ImageDef def; - def.name = "gui/touchgui.png"; - def.width = 34; - def.height = 26; - def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); - bBack->setImageDef(def, true); - } - if (/* minecraft->useTouchscreen() */ true) { - bGamemode = new Touch::TButton(1, "Survival mode"); - bCheats = new Touch::TButton(4, "Cheats: Off"); - bCreate = new Touch::TButton(3, "Create"); - } else { - bGamemode = new Button(1, "Survival mode"); - bCheats = new Button(4, "Cheats: Off"); - bCreate = new Button(3, "Create"); - } - - buttons.push_back(bHeader); - buttons.push_back(bBack); - buttons.push_back(bGamemode); - buttons.push_back(bCheats); - buttons.push_back(bCreate); - - tabButtons.push_back(bGamemode); - tabButtons.push_back(bCheats); - tabButtons.push_back(bBack); - tabButtons.push_back(bCreate); - - textBoxes.push_back(&tLevelName); - textBoxes.push_back(&tSeed); -} - -void SimpleChooseLevelScreen::setupPositions() -{ - int buttonHeight = bBack->height; - - // position back button in upper-right - bBack->x = width - bBack->width; - bBack->y = 0; - - // header occupies remaining top bar - if (bHeader) { - bHeader->x = 0; - bHeader->y = 0; - bHeader->width = width - bBack->width; - bHeader->height = buttonHeight; - } - - // layout the form elements below the header - int centerX = width / 2; - const int padding = 5; - - tLevelName.width = tSeed.width = 200; - tLevelName.x = centerX - tLevelName.width / 2; - tLevelName.y = buttonHeight + 20; - - tSeed.x = tLevelName.x; - tSeed.y = tLevelName.y + 30; - - const int buttonWidth = 120; - const int buttonSpacing = 10; - const int totalButtonWidth = buttonWidth * 2 + buttonSpacing; - - bGamemode->width = buttonWidth; - bCheats->width = buttonWidth; - - bGamemode->x = centerX - totalButtonWidth / 2; - bCheats->x = bGamemode->x + buttonWidth + buttonSpacing; - - // compute vertical centre for buttons in remaining space - { - int bottomPad = 20; - int availTop = buttonHeight + 20 + 30 + 10; // just below seed - int availBottom = height - bottomPad - bCreate->height - 10; // leave some gap before create - int availHeight = availBottom - availTop; - if (availHeight < 0) availHeight = 0; - int y = availTop + (availHeight - bGamemode->height) / 2; - bGamemode->y = y; - bCheats->y = y; - } - - bCreate->width = 100; - bCreate->x = centerX - bCreate->width / 2; - int bottomPadding = 20; - bCreate->y = height - bottomPadding - bCreate->height; -} - -void SimpleChooseLevelScreen::tick() -{ - // let any textboxes handle their own blinking/input - for (auto* tb : textBoxes) - tb->tick(minecraft); -} - -void SimpleChooseLevelScreen::render( int xm, int ym, float a ) -{ - renderDirtBackground(0); - glEnable2(GL_BLEND); - - const char* modeDesc = NULL; - if (gamemode == GameType::Survival) { - modeDesc = "Mobs, health and gather resources"; - } else if (gamemode == GameType::Creative) { - modeDesc = "Unlimited resources and flying"; - } - if (modeDesc) { - drawCenteredString(minecraft->font, modeDesc, width / 2, bGamemode->y + bGamemode->height + 4, 0xffcccccc); - } - - drawString(minecraft->font, "World name:", tLevelName.x, tLevelName.y - Font::DefaultLineHeight - 2, 0xffcccccc); - drawString(minecraft->font, "World seed:", tSeed.x, tSeed.y - Font::DefaultLineHeight - 2, 0xffcccccc); - - Screen::render(xm, ym, a); - glDisable2(GL_BLEND); -} - -// mouse clicks should also manage textbox focus explicitly -void SimpleChooseLevelScreen::mouseClicked(int x, int y, int buttonNum) -{ - if (buttonNum == MouseAction::ACTION_LEFT) { - // determine if the click landed on either textbox or its label above - int lvlTop = tLevelName.y - (Font::DefaultLineHeight + 4); - int lvlBottom = tLevelName.y + tLevelName.height; - int lvlLeft = tLevelName.x; - int lvlRight = tLevelName.x + tLevelName.width; - bool clickedLevel = x >= lvlLeft && x < lvlRight && y >= lvlTop && y < lvlBottom; - - int seedTop = tSeed.y - (Font::DefaultLineHeight + 4); - int seedBottom = tSeed.y + tSeed.height; - int seedLeft = tSeed.x; - int seedRight = tSeed.x + tSeed.width; - bool clickedSeed = x >= seedLeft && x < seedRight && y >= seedTop && y < seedBottom; - - if (clickedLevel) { - LOGI("SimpleChooseLevelScreen: level textbox clicked (%d,%d)\n", x, y); - tLevelName.setFocus(minecraft); - tSeed.loseFocus(minecraft); - } else if (clickedSeed) { - LOGI("SimpleChooseLevelScreen: seed textbox clicked (%d,%d)\n", x, y); - tSeed.setFocus(minecraft); - tLevelName.loseFocus(minecraft); - } else { - // click outside both fields -> blur both - tLevelName.loseFocus(minecraft); - tSeed.loseFocus(minecraft); - } - } - - // allow normal button and textbox handling too - Screen::mouseClicked(x, y, buttonNum); -} - -void SimpleChooseLevelScreen::buttonClicked( Button* button ) -{ - if (hasChosen) - return; - - if (button == bGamemode) { - gamemode ^= 1; - bGamemode->msg = (gamemode == GameType::Survival) ? "Survival mode" : "Creative mode"; - return; - } - - if (button == bCheats) { - cheatsEnabled = !cheatsEnabled; - bCheats->msg = cheatsEnabled ? "Cheats: On" : "Cheats: Off"; - return; - } - - if (button == bCreate && !tLevelName.text.empty()) { - int seed = getEpochTimeS(); - if (!tSeed.text.empty()) { - std::string seedString = Util::stringTrim(tSeed.text); - int tmpSeed; - if (sscanf(seedString.c_str(), "%d", &tmpSeed) > 0) { - seed = tmpSeed; - } else { - seed = Util::hashCode(seedString); - } - } - std::string levelId = getUniqueLevelName(tLevelName.text); - LevelSettings settings(seed, gamemode, cheatsEnabled); - minecraft->selectLevel(levelId, levelId, settings); - minecraft->hostMultiplayer(); - minecraft->setScreen(new ProgressScreen()); - hasChosen = true; - return; - } - - if (button == bBack) { - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } -} - -void SimpleChooseLevelScreen::keyPressed(int eventKey) -{ - if (eventKey == Keyboard::KEY_ESCAPE) { - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - return; - } - // let base class handle navigation and text box keys - Screen::keyPressed(eventKey); -} - -bool SimpleChooseLevelScreen::handleBackEvent(bool isDown) { - if (!isDown) - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - return true; -} +#include "SimpleChooseLevelScreen.hpp" +#include "ProgressScreen.hpp" +#include "ScreenChooser.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "client/Minecraft.hpp" +#include "world/level/LevelSettings.hpp" +#include "platform/time.hpp" +#include "platform/input/Keyboard.hpp" +#include "platform/log.hpp" + +SimpleChooseLevelScreen::SimpleChooseLevelScreen(const std::string& levelName) +: bHeader(0), + bGamemode(0), + bCheats(0), + bBack(0), + bCreate(0), + levelName(levelName), + hasChosen(false), + gamemode(GameType::Survival), + cheatsEnabled(false), + tLevelName(0, "World name"), + tSeed(1, "World seed") +{ +} + +SimpleChooseLevelScreen::~SimpleChooseLevelScreen() +{ + if (bHeader) delete bHeader; + delete bGamemode; + delete bCheats; + delete bBack; + delete bCreate; +} + +void SimpleChooseLevelScreen::init() +{ + // make sure the base class loads the existing level list; the + // derived screen uses ChooseLevelScreen::getUniqueLevelName(), which + // depends on `levels` being populated. omitting this used to result + // in duplicate IDs ("creating the second world would load the + // first") when the name already existed. + ChooseLevelScreen::init(); + + tLevelName.text = "New world"; + + // header + close button + bHeader = new Touch::THeader(0, "Create World"); + // create the back/X button as ImageButton like CreditsScreen + bBack = new ImageButton(2, ""); + { + ImageDef def; + def.name = "gui/touchgui.png"; + def.width = 34; + def.height = 26; + def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); + bBack->setImageDef(def, true); + } + if (/* minecraft->useTouchscreen() */ true) { + bGamemode = new Touch::TButton(1, "Survival mode"); + bCheats = new Touch::TButton(4, "Cheats: Off"); + bCreate = new Touch::TButton(3, "Create"); + } else { + bGamemode = new Button(1, "Survival mode"); + bCheats = new Button(4, "Cheats: Off"); + bCreate = new Button(3, "Create"); + } + + buttons.push_back(bHeader); + buttons.push_back(bBack); + buttons.push_back(bGamemode); + buttons.push_back(bCheats); + buttons.push_back(bCreate); + + tabButtons.push_back(bGamemode); + tabButtons.push_back(bCheats); + tabButtons.push_back(bBack); + tabButtons.push_back(bCreate); + + textBoxes.push_back(&tLevelName); + textBoxes.push_back(&tSeed); +} + +void SimpleChooseLevelScreen::setupPositions() +{ + int buttonHeight = bBack->height; + + // position back button in upper-right + bBack->x = width - bBack->width; + bBack->y = 0; + + // header occupies remaining top bar + if (bHeader) { + bHeader->x = 0; + bHeader->y = 0; + bHeader->width = width - bBack->width; + bHeader->height = buttonHeight; + } + + // layout the form elements below the header + int centerX = width / 2; + const int padding = 5; + + tLevelName.width = tSeed.width = 200; + tLevelName.x = centerX - tLevelName.width / 2; + tLevelName.y = buttonHeight + 20; + + tSeed.x = tLevelName.x; + tSeed.y = tLevelName.y + 30; + + const int buttonWidth = 120; + const int buttonSpacing = 10; + const int totalButtonWidth = buttonWidth * 2 + buttonSpacing; + + bGamemode->width = buttonWidth; + bCheats->width = buttonWidth; + + bGamemode->x = centerX - totalButtonWidth / 2; + bCheats->x = bGamemode->x + buttonWidth + buttonSpacing; + + // compute vertical centre for buttons in remaining space + { + int bottomPad = 20; + int availTop = buttonHeight + 20 + 30 + 10; // just below seed + int availBottom = height - bottomPad - bCreate->height - 10; // leave some gap before create + int availHeight = availBottom - availTop; + if (availHeight < 0) availHeight = 0; + int y = availTop + (availHeight - bGamemode->height) / 2; + bGamemode->y = y; + bCheats->y = y; + } + + bCreate->width = 100; + bCreate->x = centerX - bCreate->width / 2; + int bottomPadding = 20; + bCreate->y = height - bottomPadding - bCreate->height; +} + +void SimpleChooseLevelScreen::tick() +{ + // let any textboxes handle their own blinking/input + for (auto* tb : textBoxes) + tb->tick(minecraft); +} + +void SimpleChooseLevelScreen::render( int xm, int ym, float a ) +{ + renderDirtBackground(0); + glEnable2(GL_BLEND); + + const char* modeDesc = NULL; + if (gamemode == GameType::Survival) { + modeDesc = "Mobs, health and gather resources"; + } else if (gamemode == GameType::Creative) { + modeDesc = "Unlimited resources and flying"; + } + if (modeDesc) { + drawCenteredString(minecraft->font, modeDesc, width / 2, bGamemode->y + bGamemode->height + 4, 0xffcccccc); + } + + drawString(minecraft->font, "World name:", tLevelName.x, tLevelName.y - Font::DefaultLineHeight - 2, 0xffcccccc); + drawString(minecraft->font, "World seed:", tSeed.x, tSeed.y - Font::DefaultLineHeight - 2, 0xffcccccc); + + Screen::render(xm, ym, a); + glDisable2(GL_BLEND); +} + +// mouse clicks should also manage textbox focus explicitly +void SimpleChooseLevelScreen::mouseClicked(int x, int y, int buttonNum) +{ + if (buttonNum == MouseAction::ACTION_LEFT) { + // determine if the click landed on either textbox or its label above + int lvlTop = tLevelName.y - (Font::DefaultLineHeight + 4); + int lvlBottom = tLevelName.y + tLevelName.height; + int lvlLeft = tLevelName.x; + int lvlRight = tLevelName.x + tLevelName.width; + bool clickedLevel = x >= lvlLeft && x < lvlRight && y >= lvlTop && y < lvlBottom; + + int seedTop = tSeed.y - (Font::DefaultLineHeight + 4); + int seedBottom = tSeed.y + tSeed.height; + int seedLeft = tSeed.x; + int seedRight = tSeed.x + tSeed.width; + bool clickedSeed = x >= seedLeft && x < seedRight && y >= seedTop && y < seedBottom; + + if (clickedLevel) { + LOGI("SimpleChooseLevelScreen: level textbox clicked (%d,%d)\n", x, y); + tLevelName.setFocus(minecraft); + tSeed.loseFocus(minecraft); + } else if (clickedSeed) { + LOGI("SimpleChooseLevelScreen: seed textbox clicked (%d,%d)\n", x, y); + tSeed.setFocus(minecraft); + tLevelName.loseFocus(minecraft); + } else { + // click outside both fields -> blur both + tLevelName.loseFocus(minecraft); + tSeed.loseFocus(minecraft); + } + } + + // allow normal button and textbox handling too + Screen::mouseClicked(x, y, buttonNum); +} + +void SimpleChooseLevelScreen::buttonClicked( Button* button ) +{ + if (hasChosen) + return; + + if (button == bGamemode) { + gamemode ^= 1; + bGamemode->msg = (gamemode == GameType::Survival) ? "Survival mode" : "Creative mode"; + return; + } + + if (button == bCheats) { + cheatsEnabled = !cheatsEnabled; + bCheats->msg = cheatsEnabled ? "Cheats: On" : "Cheats: Off"; + return; + } + + if (button == bCreate && !tLevelName.text.empty()) { + int seed = getEpochTimeS(); + if (!tSeed.text.empty()) { + std::string seedString = Util::stringTrim(tSeed.text); + int tmpSeed; + if (sscanf(seedString.c_str(), "%d", &tmpSeed) > 0) { + seed = tmpSeed; + } else { + seed = Util::hashCode(seedString); + } + } + std::string levelId = getUniqueLevelName(tLevelName.text); + LevelSettings settings(seed, gamemode, cheatsEnabled); + minecraft->selectLevel(levelId, levelId, settings); + minecraft->hostMultiplayer(); + minecraft->setScreen(new ProgressScreen()); + hasChosen = true; + return; + } + + if (button == bBack) { + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } +} + +void SimpleChooseLevelScreen::keyPressed(int eventKey) +{ + if (eventKey == Keyboard::KEY_ESCAPE) { + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + return; + } + // let base class handle navigation and text box keys + Screen::keyPressed(eventKey); +} + +bool SimpleChooseLevelScreen::handleBackEvent(bool isDown) { + if (!isDown) + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + return true; +} diff --git a/src/client/gui/screens/SimpleChooseLevelScreen.h b/src/client/gui/screens/SimpleChooseLevelScreen.hpp similarity index 82% rename from src/client/gui/screens/SimpleChooseLevelScreen.h rename to src/client/gui/screens/SimpleChooseLevelScreen.hpp index 8200a20..7c15b3f 100755 --- a/src/client/gui/screens/SimpleChooseLevelScreen.h +++ b/src/client/gui/screens/SimpleChooseLevelScreen.hpp @@ -1,8 +1,8 @@ #pragma once -#include "ChooseLevelScreen.h" -#include "../components/TextBox.h" -#include "../components/Button.h" // for Touch::THeader +#include "ChooseLevelScreen.hpp" +#include "client/gui/components/TextBox.hpp" +#include "client/gui/components/Button.hpp" // for Touch::THeader class Button; class ImageButton; diff --git a/src/client/gui/screens/StartMenuScreen.cpp b/src/client/gui/screens/StartMenuScreen.cpp index 3fede7e..ab2d6e2 100755 --- a/src/client/gui/screens/StartMenuScreen.cpp +++ b/src/client/gui/screens/StartMenuScreen.cpp @@ -1,216 +1,216 @@ -#include "StartMenuScreen.h" -#include "UsernameScreen.h" -#include "SelectWorldScreen.h" -#include "ProgressScreen.h" -#include "JoinGameScreen.h" -#include "OptionsScreen.h" -#include "PauseScreen.h" -#include "PrerenderTilesScreen.h" // test button -#include "../components/ImageButton.h" - -#include "../../../util/Mth.h" - -#include "../Font.h" -#include "../components/ScrolledSelectionList.h" - -#include "../../Minecraft.h" -#include "../../renderer/Tesselator.h" -#include "../../../AppPlatform.h" -#include "../../../LicenseCodes.h" -#include "SimpleChooseLevelScreen.h" -#include "../../renderer/Textures.h" -#include "../../../SharedConstants.h" - -// Some kind of default settings, might be overridden in ::init -StartMenuScreen::StartMenuScreen() -: bHost( 2, 0, 0, 160, 24, "Start Game"), - bJoin( 3, 0, 0, 160, 24, "Join Game"), - bOptions( 4, 0, 0, 160, 24, "Options"), - bQuit( 5, "") -{ -} - -StartMenuScreen::~StartMenuScreen() -{ -} - -void StartMenuScreen::init() -{ - bJoin.active = bHost.active = bOptions.active = true; - - if (minecraft->options.getStringValue(OPTIONS_USERNAME).empty()) { - return; // tick() will redirect to UsernameScreen - } - - buttons.push_back(&bHost); - buttons.push_back(&bJoin); - //buttons.push_back(&bTest); - - tabButtons.push_back(&bHost); - tabButtons.push_back(&bJoin); - - #ifndef RPI - buttons.push_back(&bOptions); - tabButtons.push_back(&bOptions); - #endif - - // add quit button (top right X icon) – match OptionsScreen style - { - ImageDef def; - def.name = "gui/touchgui.png"; - def.width = 34; - def.height = 26; - def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); - bQuit.setImageDef(def, true); - bQuit.scaleWhenPressed = false; - buttons.push_back(&bQuit); - // don't include in tab navigation - } - - copyright = "\xffMojang AB";//. Do not distribute!"; - - // always show base version string, suffix was previously added for Android builds - std::string versionString = Common::getGameVersionString(); - - std::string _username = minecraft->options.getStringValue(OPTIONS_USERNAME); - if (_username.empty()) _username = "unknown"; - - username = "Username: " + _username; - - #ifdef DEMO_MODE - #ifdef __APPLE__ - version = versionString + " (Lite)"; - #else - version = versionString + " (Demo)"; - #endif - #else - #ifdef RPI - version = "v0.1.1 alpha";//(MCPE " + versionString + " compatible)"; - #else - version = versionString; - #endif - #endif -} - -void StartMenuScreen::setupPositions() { - int yBase = height / 2; - - bHost.y = yBase; - bJoin.y = bHost.y + 24 + 4; - bOptions.y = bJoin.y + 24 + 4; - - // Center buttons - bHost.x = (width - bHost.width) / 2; - bJoin.x = (width - bJoin.width) / 2; - bOptions.x = (width - bOptions.width) / 2; - - // position quit icon at top-right (use image-defined size) - bQuit.x = width - bQuit.width; - bQuit.y = 0; -} - -void StartMenuScreen::tick() { -} - -void StartMenuScreen::buttonClicked(Button* button) { - - if (button->id == bHost.id) - { - #if defined(DEMO_MODE) || defined(APPLE_DEMO_PROMOTION) - minecraft->setScreen( new SimpleChooseLevelScreen("_DemoLevel") ); - #else - minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); - #endif - } - if (button->id == bJoin.id) - { - minecraft->locateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_JOINGAME); - } - if (button->id == bOptions.id) - { - minecraft->setScreen(new OptionsScreen()); - } - if (button == &bQuit) - { - minecraft->quit(); - } -} - -bool StartMenuScreen::isInGameScreen() { return false; } - -void StartMenuScreen::render( int xm, int ym, float a ) -{ - renderBackground(); - - // Show current username in the top-left corner - drawString(font, username, 2, 2, 0xffffffff); - -#if defined(RPI) - TextureId id = minecraft->textures->loadTexture("gui/pi_title.png"); -#else - TextureId id = minecraft->textures->loadTexture("gui/title.png"); -#endif - const TextureData* data = minecraft->textures->getTemporaryTextureData(id); - - if (data) { - minecraft->textures->bind(id); - - const float x = (float)width / 2; - const float y = height/16; - //const float scale = Mth::Min( - const float wh = Mth::Min((float)width/2.0f, (float)data->w / 2); - const float scale = 2.0f * wh / (float)data->w; - const float h = scale * (float)data->h; - - // Render title text - Tesselator& t = Tesselator::instance; - glColor4f2(1, 1, 1, 1); - t.begin(); - t.vertexUV(x-wh, y+h, blitOffset, 0, 1); - t.vertexUV(x+wh, y+h, blitOffset, 1, 1); - t.vertexUV(x+wh, y+0, blitOffset, 1, 0); - t.vertexUV(x-wh, y+0, blitOffset, 0, 0); - t.draw(); - } - -#if defined(RPI) - if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/raknet_high_72.png"))) - blit(0, height - 12, 0, 0, 43, 12, 256, 72+72); -#endif - - drawString(font, version, width - font->width(version) - 2, height - 10, 0xffcccccc);//0x666666); - drawString(font, copyright, 2, height - 20, 0xffffff); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f2(1, 1, 1, 1); - if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/github.png"))) - blit(2, height - 10, 0, 0, 8, 8, 256, 256); - { - std::string txt = "Kolyah35/minecraft-pe-0.6.1"; - float wtxt = font->width(txt); - Gui::drawColoredString(font, txt, 12, height - 10, 255); - // underline link - float y0 = height - 10 + font->lineHeight - 1; - this->fill(12, (int)y0, 12 + (int)wtxt, (int)(y0 + 1), 0xffffffff); - } - - - Screen::render(xm, ym, a); -} - -void StartMenuScreen::mouseClicked(int x, int y, int buttonNum) { - const int logoX = 2; - const int logoW = 8 + 2 + font->width("Kolyah35/minecraft-pe-0.6.1"); - const int logoY = height - 10; - const int logoH = 10; - if (x >= logoX && x <= logoX + logoW && y >= logoY && y <= logoY + logoH) - minecraft->platform()->openURL("https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1"); - else - Screen::mouseClicked(x, y, buttonNum); -} - -bool StartMenuScreen::handleBackEvent( bool isDown ) { - minecraft->quit(); - return true; -} +#include "StartMenuScreen.hpp" +#include "UsernameScreen.hpp" +#include "SelectWorldScreen.hpp" +#include "ProgressScreen.hpp" +#include "JoinGameScreen.hpp" +#include "OptionsScreen.hpp" +#include "PauseScreen.hpp" +#include "PrerenderTilesScreen.hpp" // test button +#include "client/gui/components/ImageButton.hpp" + +#include "util/Mth.hpp" + +#include "client/gui/Font.hpp" +#include "client/gui/components/ScrolledSelectionList.hpp" + +#include "client/Minecraft.hpp" +#include "client/renderer/Tesselator.hpp" +#include "AppPlatform.hpp" +#include "LicenseCodes.hpp" +#include "SimpleChooseLevelScreen.hpp" +#include "client/renderer/Textures.hpp" +#include "SharedConstants.hpp" + +// Some kind of default settings, might be overridden in ::init +StartMenuScreen::StartMenuScreen() +: bHost( 2, 0, 0, 160, 24, "Start Game"), + bJoin( 3, 0, 0, 160, 24, "Join Game"), + bOptions( 4, 0, 0, 160, 24, "Options"), + bQuit( 5, "") +{ +} + +StartMenuScreen::~StartMenuScreen() +{ +} + +void StartMenuScreen::init() +{ + bJoin.active = bHost.active = bOptions.active = true; + + if (minecraft->options.getStringValue(OPTIONS_USERNAME).empty()) { + return; // tick() will redirect to UsernameScreen + } + + buttons.push_back(&bHost); + buttons.push_back(&bJoin); + //buttons.push_back(&bTest); + + tabButtons.push_back(&bHost); + tabButtons.push_back(&bJoin); + + #ifndef RPI + buttons.push_back(&bOptions); + tabButtons.push_back(&bOptions); + #endif + + // add quit button (top right X icon) – match OptionsScreen style + { + ImageDef def; + def.name = "gui/touchgui.png"; + def.width = 34; + def.height = 26; + def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); + bQuit.setImageDef(def, true); + bQuit.scaleWhenPressed = false; + buttons.push_back(&bQuit); + // don't include in tab navigation + } + + copyright = "\xffMojang AB";//. Do not distribute!"; + + // always show base version string, suffix was previously added for Android builds + std::string versionString = Common::getGameVersionString(); + + std::string _username = minecraft->options.getStringValue(OPTIONS_USERNAME); + if (_username.empty()) _username = "unknown"; + + username = "Username: " + _username; + + #ifdef DEMO_MODE + #ifdef __APPLE__ + version = versionString + " (Lite)"; + #else + version = versionString + " (Demo)"; + #endif + #else + #ifdef RPI + version = "v0.1.1 alpha";//(MCPE " + versionString + " compatible)"; + #else + version = versionString; + #endif + #endif +} + +void StartMenuScreen::setupPositions() { + int yBase = height / 2; + + bHost.y = yBase; + bJoin.y = bHost.y + 24 + 4; + bOptions.y = bJoin.y + 24 + 4; + + // Center buttons + bHost.x = (width - bHost.width) / 2; + bJoin.x = (width - bJoin.width) / 2; + bOptions.x = (width - bOptions.width) / 2; + + // position quit icon at top-right (use image-defined size) + bQuit.x = width - bQuit.width; + bQuit.y = 0; +} + +void StartMenuScreen::tick() { +} + +void StartMenuScreen::buttonClicked(Button* button) { + + if (button->id == bHost.id) + { + #if defined(DEMO_MODE) || defined(APPLE_DEMO_PROMOTION) + minecraft->setScreen( new SimpleChooseLevelScreen("_DemoLevel") ); + #else + minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); + #endif + } + if (button->id == bJoin.id) + { + minecraft->locateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_JOINGAME); + } + if (button->id == bOptions.id) + { + minecraft->setScreen(new OptionsScreen()); + } + if (button == &bQuit) + { + minecraft->quit(); + } +} + +bool StartMenuScreen::isInGameScreen() { return false; } + +void StartMenuScreen::render( int xm, int ym, float a ) +{ + renderBackground(); + + // Show current username in the top-left corner + drawString(font, username, 2, 2, 0xffffffff); + +#if defined(RPI) + TextureId id = minecraft->textures->loadTexture("gui/pi_title.png"); +#else + TextureId id = minecraft->textures->loadTexture("gui/title.png"); +#endif + const TextureData* data = minecraft->textures->getTemporaryTextureData(id); + + if (data) { + minecraft->textures->bind(id); + + const float x = (float)width / 2; + const float y = height/16; + //const float scale = Mth::Min( + const float wh = Mth::Min((float)width/2.0f, (float)data->w / 2); + const float scale = 2.0f * wh / (float)data->w; + const float h = scale * (float)data->h; + + // Render title text + Tesselator& t = Tesselator::instance; + glColor4f2(1, 1, 1, 1); + t.begin(); + t.vertexUV(x-wh, y+h, blitOffset, 0, 1); + t.vertexUV(x+wh, y+h, blitOffset, 1, 1); + t.vertexUV(x+wh, y+0, blitOffset, 1, 0); + t.vertexUV(x-wh, y+0, blitOffset, 0, 0); + t.draw(); + } + +#if defined(RPI) + if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/raknet_high_72.png"))) + blit(0, height - 12, 0, 0, 43, 12, 256, 72+72); +#endif + + drawString(font, version, width - font->width(version) - 2, height - 10, 0xffcccccc);//0x666666); + drawString(font, copyright, 2, height - 20, 0xffffff); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4f2(1, 1, 1, 1); + if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/github.png"))) + blit(2, height - 10, 0, 0, 8, 8, 256, 256); + { + std::string txt = "Kolyah35/minecraft-pe-0.6.1"; + float wtxt = font->width(txt); + Gui::drawColoredString(font, txt, 12, height - 10, 255); + // underline link + float y0 = height - 10 + font->lineHeight - 1; + this->fill(12, (int)y0, 12 + (int)wtxt, (int)(y0 + 1), 0xffffffff); + } + + + Screen::render(xm, ym, a); +} + +void StartMenuScreen::mouseClicked(int x, int y, int buttonNum) { + const int logoX = 2; + const int logoW = 8 + 2 + font->width("Kolyah35/minecraft-pe-0.6.1"); + const int logoY = height - 10; + const int logoH = 10; + if (x >= logoX && x <= logoX + logoW && y >= logoY && y <= logoY + logoH) + minecraft->platform()->openURL("https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1"); + else + Screen::mouseClicked(x, y, buttonNum); +} + +bool StartMenuScreen::handleBackEvent( bool isDown ) { + minecraft->quit(); + return true; +} diff --git a/src/client/gui/screens/StartMenuScreen.h b/src/client/gui/screens/StartMenuScreen.hpp similarity index 82% rename from src/client/gui/screens/StartMenuScreen.h rename to src/client/gui/screens/StartMenuScreen.hpp index 1c794fe..7726ef5 100755 --- a/src/client/gui/screens/StartMenuScreen.h +++ b/src/client/gui/screens/StartMenuScreen.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../Screen.h" -#include "../components/Button.h" -#include "../components/ImageButton.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/ImageButton.hpp" class StartMenuScreen: public Screen { diff --git a/src/client/gui/screens/TextEditScreen.cpp b/src/client/gui/screens/TextEditScreen.cpp index 1159e67..eeda3d6 100755 --- a/src/client/gui/screens/TextEditScreen.cpp +++ b/src/client/gui/screens/TextEditScreen.cpp @@ -1,146 +1,146 @@ -#include "TextEditScreen.h" -#include "../../../world/level/tile/entity/SignTileEntity.h" -#include "../../../AppPlatform.h" -#include "../../Minecraft.h" -#include "../../renderer/tileentity/TileEntityRenderDispatcher.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/Textures.h" -#include "../../renderer/GameRenderer.h" -#include "../components/Button.h" -#include "../../../network/Packet.h" -#include "../../../network/RakNetInstance.h" -TextEditScreen::TextEditScreen( SignTileEntity* signEntity ) - : sign(signEntity), isShowingKeyboard(false), frame(0), line(0), btnClose(1, "") { - -} -TextEditScreen::~TextEditScreen() { - -} -void TextEditScreen::init() { - super::init(); - minecraft->platform()->showKeyboard(); - isShowingKeyboard = true; - ImageDef def; - def.name = "gui/spritesheet.png"; - def.x = 0; - def.y = 1; - def.width = def.height = 18; - def.setSrc(IntRectangle(60, 0, 18, 18)); - btnClose.setImageDef(def, true); - btnClose.scaleWhenPressed = false; - buttons.push_back(&btnClose); -} - -void TextEditScreen::setupPositions() { - btnClose.width = btnClose.height = 19; - btnClose.x = width - btnClose.width; - btnClose.y = 0; -} - - -bool TextEditScreen::handleBackEvent( bool isDown ) { - sign->setChanged(); - Packet* signUpdatePacket = sign->getUpdatePacket(); - minecraft->raknetInstance->send(signUpdatePacket); - minecraft->platform()->hideKeyboard(); - minecraft->setScreen(NULL); - return true; -} - -void TextEditScreen::render( int xm, int ym, float a ) { - glDepthMask(GL_FALSE); - renderBackground(); - glPushMatrix(); - glDepthMask(GL_TRUE); - glDisable(GL_CULL_FACE); - glLoadIdentity(); - Tesselator& t = Tesselator::instance; - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrthof(0.0f, (float)minecraft->width, (float)minecraft->height, 0, -1, 1); - glMatrixMode(GL_MODELVIEW); - - minecraft->textures->loadAndBindTexture("item/sign.png"); - glColor4f2(1, 1, 1, 1); - - static float minUV[] = {0.03126f, 0.06249f}; - static float maxUV[] = {0.39063f, 0.4374f}; - float scale = ((minecraft->height / 2) / 32) * 0.9f; - - glTranslatef(minecraft->width / 2.0f, 5.0f, 0.0f); - glScalef2(scale,scale,1); - t.begin(GL_QUADS); - t.vertexUV(-32, 0, 0.0f,minUV[0],minUV[1]); - t.vertexUV(32, 0, 0.0f, maxUV[0], minUV[1]); - t.vertexUV(32, 0 + 32, 0.0f, maxUV[0], maxUV[1]); - t.vertexUV(-32, 0 + 32, 0.0f, minUV[0], maxUV[1]); - t.draw(); - - sign->selectedLine = line; - float textScale = 8.0f / 11.0f; - - glTranslatef(0, 2 ,0); - glScalef2(textScale, textScale, 1); - for(int i = 0; i < 4; ++i) { - //drawCenteredString(font, sign->messages[a], 32.0f, 10 * a, 0xFF000000); - std::string msg = sign->messages[i]; - if (i == sign->selectedLine && msg.length() < 14) { - std::string s = "> " + msg + " <"; - font->draw(s, -(float)font->width(s) / 2.0f, 10.0f * i, 0xFF000000, false); - } else { - font->draw(msg, -(float)font->width(msg) / 2.0f, 10.0f * i, 0xFF000000, false); - } - } - sign->selectedLine = -1; - //font->draw("Hej", minecraft->width / 2, 100, 0xFFFFFFFF, false); - - glPopMatrix(); - glEnable(GL_CULL_FACE); - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - - //glEnable(GL_DEPTH_TEST); - super::render(xm, ym, a); -} - -void TextEditScreen::lostFocus() { - -} - -void TextEditScreen::tick() { - frame++; -} - -void TextEditScreen::keyPressed( int eventKey ) { - LOGW("Key pressed! [%d]", eventKey); - if(eventKey == Keyboard::KEY_BACKSPACE) { - if(sign->messages[line].length() > 0) { - sign->messages[line].erase(sign->messages[line].size() - 1, 1); - } else { - line--; - if(line < 0) { - line = 3; - } - } - } else if(eventKey == Keyboard::KEY_RETURN) { - line = (line + 1) % 4; - } else { - super::keyPressed(eventKey); - } -} - -void TextEditScreen::charPressed( char inputChar ) { - std::string fullstring = sign->messages[line] + inputChar; - if(fullstring.length() < 16) { - sign->messages[line] = fullstring; - //LOGW("Line text updated: %s\n", fullstring.c_str()); - } -} - -void TextEditScreen::buttonClicked( Button* button ) { - if(button == &btnClose) - handleBackEvent(true); -} +#include "TextEditScreen.hpp" +#include "world/level/tile/entity/SignTileEntity.hpp" +#include "AppPlatform.hpp" +#include "client/Minecraft.hpp" +#include "client/renderer/tileentity/TileEntityRenderDispatcher.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "client/renderer/GameRenderer.hpp" +#include "client/gui/components/Button.hpp" +#include "network/Packet.hpp" +#include "network/RakNetInstance.hpp" +TextEditScreen::TextEditScreen( SignTileEntity* signEntity ) + : sign(signEntity), isShowingKeyboard(false), frame(0), line(0), btnClose(1, "") { + +} +TextEditScreen::~TextEditScreen() { + +} +void TextEditScreen::init() { + super::init(); + minecraft->platform()->showKeyboard(); + isShowingKeyboard = true; + ImageDef def; + def.name = "gui/spritesheet.png"; + def.x = 0; + def.y = 1; + def.width = def.height = 18; + def.setSrc(IntRectangle(60, 0, 18, 18)); + btnClose.setImageDef(def, true); + btnClose.scaleWhenPressed = false; + buttons.push_back(&btnClose); +} + +void TextEditScreen::setupPositions() { + btnClose.width = btnClose.height = 19; + btnClose.x = width - btnClose.width; + btnClose.y = 0; +} + + +bool TextEditScreen::handleBackEvent( bool isDown ) { + sign->setChanged(); + Packet* signUpdatePacket = sign->getUpdatePacket(); + minecraft->raknetInstance->send(signUpdatePacket); + minecraft->platform()->hideKeyboard(); + minecraft->setScreen(NULL); + return true; +} + +void TextEditScreen::render( int xm, int ym, float a ) { + glDepthMask(GL_FALSE); + renderBackground(); + glPushMatrix(); + glDepthMask(GL_TRUE); + glDisable(GL_CULL_FACE); + glLoadIdentity(); + Tesselator& t = Tesselator::instance; + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrthof(0.0f, (float)minecraft->width, (float)minecraft->height, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + + minecraft->textures->loadAndBindTexture("item/sign.png"); + glColor4f2(1, 1, 1, 1); + + static float minUV[] = {0.03126f, 0.06249f}; + static float maxUV[] = {0.39063f, 0.4374f}; + float scale = ((minecraft->height / 2) / 32) * 0.9f; + + glTranslatef(minecraft->width / 2.0f, 5.0f, 0.0f); + glScalef2(scale,scale,1); + t.begin(GL_QUADS); + t.vertexUV(-32, 0, 0.0f,minUV[0],minUV[1]); + t.vertexUV(32, 0, 0.0f, maxUV[0], minUV[1]); + t.vertexUV(32, 0 + 32, 0.0f, maxUV[0], maxUV[1]); + t.vertexUV(-32, 0 + 32, 0.0f, minUV[0], maxUV[1]); + t.draw(); + + sign->selectedLine = line; + float textScale = 8.0f / 11.0f; + + glTranslatef(0, 2 ,0); + glScalef2(textScale, textScale, 1); + for(int i = 0; i < 4; ++i) { + //drawCenteredString(font, sign->messages[a], 32.0f, 10 * a, 0xFF000000); + std::string msg = sign->messages[i]; + if (i == sign->selectedLine && msg.length() < 14) { + std::string s = "> " + msg + " <"; + font->draw(s, -(float)font->width(s) / 2.0f, 10.0f * i, 0xFF000000, false); + } else { + font->draw(msg, -(float)font->width(msg) / 2.0f, 10.0f * i, 0xFF000000, false); + } + } + sign->selectedLine = -1; + //font->draw("Hej", minecraft->width / 2, 100, 0xFFFFFFFF, false); + + glPopMatrix(); + glEnable(GL_CULL_FACE); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + //glEnable(GL_DEPTH_TEST); + super::render(xm, ym, a); +} + +void TextEditScreen::lostFocus() { + +} + +void TextEditScreen::tick() { + frame++; +} + +void TextEditScreen::keyPressed( int eventKey ) { + LOGW("Key pressed! [%d]", eventKey); + if(eventKey == Keyboard::KEY_BACKSPACE) { + if(sign->messages[line].length() > 0) { + sign->messages[line].erase(sign->messages[line].size() - 1, 1); + } else { + line--; + if(line < 0) { + line = 3; + } + } + } else if(eventKey == Keyboard::KEY_RETURN) { + line = (line + 1) % 4; + } else { + super::keyPressed(eventKey); + } +} + +void TextEditScreen::charPressed( char inputChar ) { + std::string fullstring = sign->messages[line] + inputChar; + if(fullstring.length() < 16) { + sign->messages[line] = fullstring; + //LOGW("Line text updated: %s\n", fullstring.c_str()); + } +} + +void TextEditScreen::buttonClicked( Button* button ) { + if(button == &btnClose) + handleBackEvent(true); +} diff --git a/src/client/gui/screens/TextEditScreen.h b/src/client/gui/screens/TextEditScreen.hpp similarity index 88% rename from src/client/gui/screens/TextEditScreen.h rename to src/client/gui/screens/TextEditScreen.hpp index 7a97d1d..c49f7aa 100755 --- a/src/client/gui/screens/TextEditScreen.h +++ b/src/client/gui/screens/TextEditScreen.hpp @@ -2,9 +2,9 @@ //package net.minecraft.client.gui; -#include "../Screen.h" +#include "client/gui/Screen.hpp" #include -#include "../components/ImageButton.h" +#include "client/gui/components/ImageButton.hpp" class SignTileEntity; class Button; class TextEditScreen: public Screen diff --git a/src/client/gui/screens/UploadPhotoScreen.cpp b/src/client/gui/screens/UploadPhotoScreen.cpp index ccf38f8..299b317 100755 --- a/src/client/gui/screens/UploadPhotoScreen.cpp +++ b/src/client/gui/screens/UploadPhotoScreen.cpp @@ -1,177 +1,177 @@ -#if 0 - -#include "UploadPhotoScreen.h" -#include "../renderer/TileRenderer.h" -#include "../player/LocalPlayer.h" -#include "../../world/entity/player/Inventory.h" - -UploadPhotoScreen::UploadPhotoScreen() - : -selectedItem(0) -{ -} - -void UploadPhotoScreen::init() -{ - int currentSelection = minecraft->player->inventory->getSelectedItemId(); - for (int i = 0; i < Inventory::INVENTORY_SIZE; i++) - { - if (currentSelection == minecraft->player->inventory->getSelectionSlotItemId(i + Inventory::SELECTION_SIZE)) - { - selectedItem = i; - break; - } - } - -} - -void UploadPhotoScreen::renderSlots() -{ - glColor4f2(1, 1, 1, 1); - - blitOffset = -90; - - minecraft->textures->loadAndBindTexture("gui/gui.png"); - for (int r = 0; r < Inventory::INVENTORY_ROWS; r++) - { - blit(width / 2 - 182 / 2, height - 22 * 3 - 22 * r, 0, 0, 182, 22); - } - if (selectedItem >= 0) - { - int x = width / 2 - 182 / 2 - 1 + (selectedItem % Inventory::SELECTION_SIZE) * 20; - int y = height - 22 * 3 - 1 - (selectedItem / Inventory::SELECTION_SIZE) * 22; - blit(x, y, 0, 22, 24, 22); - } - - for (int r = 0; r < Inventory::INVENTORY_ROWS; r++) - { - for (int i = 0; i < 9; i++) { - int x = width / 2 - 9 * 10 + i * 20 + 2; - int y = height - 16 - 3 - 22 * 2 - 22 * r; - renderSlot(r * 9 + i + Inventory::SELECTION_SIZE, x, y, 0); - } - } - -} - -void UploadPhotoScreen::renderSlot(int slot, int x, int y, float a) -{ - int itemId = minecraft->player->inventory->getSelectionSlotItemId(slot); - if (itemId < 0) return; - - const bool fancy = false; - - if (fancy && itemId < 256 && TileRenderer::canRender(Tile::tiles[itemId]->getRenderShape())) { - - } else { - if (itemId < 256) { - Tile* tile = Tile::tiles[itemId]; - if (tile == NULL) return; - - minecraft->textures->loadAndBindTexture("terrain.png"); - - int textureId = tile->getTexture(2, 0); - blit(x, y, textureId % 16 * 16, textureId / 16 * 16, 16, 16); - } - } - -} - -void UploadPhotoScreen::keyPressed(int eventKey) -{ - int selX = selectedItem % Inventory::SELECTION_SIZE; - int selY = selectedItem / Inventory::SELECTION_SIZE; - - Options& o = minecraft->options; - if (eventKey == o.keyLeft.key && selX > 0) - { - selectedItem -= 1; - } - else if (eventKey == o.keyRight.key && selX < (Inventory::SELECTION_SIZE - 1)) - { - selectedItem += 1; - } - else if (eventKey == o.keyDown.key && selY > 0) - { - selectedItem -= Inventory::SELECTION_SIZE; - } - else if (eventKey == o.keyUp.key && selY < (Inventory::INVENTORY_ROWS - 1)) - { - selectedItem += Inventory::SELECTION_SIZE; - } - - if (eventKey == o.keyMenuOk.key) - { - selectSlotAndClose(); - } -} - -int UploadPhotoScreen::getSelectedSlot(int x, int y) -{ - int left = 3 + width / 2 - Inventory::SELECTION_SIZE * 10; - int top = height - 16 - 3 - 22 * 2 - 22 * Inventory::INVENTORY_ROWS; - - if (x >= left && y >= top) - { - int xSlot = (x - left) / 20; - if (xSlot < Inventory::SELECTION_SIZE) - { - // rows are rendered upsidedown - return xSlot + Inventory::INVENTORY_SIZE - ((y - top) / 22) * Inventory::SELECTION_SIZE; - } - } - return -1; -} - -void UploadPhotoScreen::mouseClicked(int x, int y, int buttonNum) { - if (buttonNum == MouseAction::ACTION_LEFT) { - - int slot = getSelectedSlot(x, y); - if (slot >= 0 && slot < Inventory::INVENTORY_SIZE) - { - selectedItem = slot; - //minecraft->soundEngine->playUI("random.click", 1, 1); - } - } -} - -void UploadPhotoScreen::mouseReleased(int x, int y, int buttonNum) -{ - if (buttonNum == MouseAction::ACTION_LEFT) { - - int slot = getSelectedSlot(x, y); - if (slot >= 0 && slot < Inventory::INVENTORY_SIZE && slot == selectedItem) - { - selectSlotAndClose(); - } - } -} - -void UploadPhotoScreen::selectSlotAndClose() -{ - Inventory* inventory = minecraft->player->inventory; - - int itemId = inventory->getSelectionSlotItemId(selectedItem + Inventory::SELECTION_SIZE); - int i = 0; - - for (; i < Inventory::SELECTION_SIZE - 2; i++) - { - if (itemId == inventory->getSelectionSlotItemId(i)) - { - break; - } - } - - // update selection list - for (; i >= 1; i--) - { - inventory->setSelectionSlotItemId(i, inventory->getSelectionSlotItemId(i - 1)); - } - inventory->setSelectionSlotItemId(0, itemId); - inventory->selectSlot(0); - - minecraft->soundEngine->playUI("random.click", 1, 1); - minecraft->setScreen(NULL); -} - -#endif +#if 0 + +#include "UploadPhotoScreen.hpp" +#include "client/gui/renderer/TileRenderer.hpp" +#include "client/gui/player/LocalPlayer.hpp" +#include "client/world/entity/player/Inventory.hpp" + +UploadPhotoScreen::UploadPhotoScreen() + : +selectedItem(0) +{ +} + +void UploadPhotoScreen::init() +{ + int currentSelection = minecraft->player->inventory->getSelectedItemId(); + for (int i = 0; i < Inventory::INVENTORY_SIZE; i++) + { + if (currentSelection == minecraft->player->inventory->getSelectionSlotItemId(i + Inventory::SELECTION_SIZE)) + { + selectedItem = i; + break; + } + } + +} + +void UploadPhotoScreen::renderSlots() +{ + glColor4f2(1, 1, 1, 1); + + blitOffset = -90; + + minecraft->textures->loadAndBindTexture("gui/gui.png"); + for (int r = 0; r < Inventory::INVENTORY_ROWS; r++) + { + blit(width / 2 - 182 / 2, height - 22 * 3 - 22 * r, 0, 0, 182, 22); + } + if (selectedItem >= 0) + { + int x = width / 2 - 182 / 2 - 1 + (selectedItem % Inventory::SELECTION_SIZE) * 20; + int y = height - 22 * 3 - 1 - (selectedItem / Inventory::SELECTION_SIZE) * 22; + blit(x, y, 0, 22, 24, 22); + } + + for (int r = 0; r < Inventory::INVENTORY_ROWS; r++) + { + for (int i = 0; i < 9; i++) { + int x = width / 2 - 9 * 10 + i * 20 + 2; + int y = height - 16 - 3 - 22 * 2 - 22 * r; + renderSlot(r * 9 + i + Inventory::SELECTION_SIZE, x, y, 0); + } + } + +} + +void UploadPhotoScreen::renderSlot(int slot, int x, int y, float a) +{ + int itemId = minecraft->player->inventory->getSelectionSlotItemId(slot); + if (itemId < 0) return; + + const bool fancy = false; + + if (fancy && itemId < 256 && TileRenderer::canRender(Tile::tiles[itemId]->getRenderShape())) { + + } else { + if (itemId < 256) { + Tile* tile = Tile::tiles[itemId]; + if (tile == NULL) return; + + minecraft->textures->loadAndBindTexture("terrain.png"); + + int textureId = tile->getTexture(2, 0); + blit(x, y, textureId % 16 * 16, textureId / 16 * 16, 16, 16); + } + } + +} + +void UploadPhotoScreen::keyPressed(int eventKey) +{ + int selX = selectedItem % Inventory::SELECTION_SIZE; + int selY = selectedItem / Inventory::SELECTION_SIZE; + + Options& o = minecraft->options; + if (eventKey == o.keyLeft.key && selX > 0) + { + selectedItem -= 1; + } + else if (eventKey == o.keyRight.key && selX < (Inventory::SELECTION_SIZE - 1)) + { + selectedItem += 1; + } + else if (eventKey == o.keyDown.key && selY > 0) + { + selectedItem -= Inventory::SELECTION_SIZE; + } + else if (eventKey == o.keyUp.key && selY < (Inventory::INVENTORY_ROWS - 1)) + { + selectedItem += Inventory::SELECTION_SIZE; + } + + if (eventKey == o.keyMenuOk.key) + { + selectSlotAndClose(); + } +} + +int UploadPhotoScreen::getSelectedSlot(int x, int y) +{ + int left = 3 + width / 2 - Inventory::SELECTION_SIZE * 10; + int top = height - 16 - 3 - 22 * 2 - 22 * Inventory::INVENTORY_ROWS; + + if (x >= left && y >= top) + { + int xSlot = (x - left) / 20; + if (xSlot < Inventory::SELECTION_SIZE) + { + // rows are rendered upsidedown + return xSlot + Inventory::INVENTORY_SIZE - ((y - top) / 22) * Inventory::SELECTION_SIZE; + } + } + return -1; +} + +void UploadPhotoScreen::mouseClicked(int x, int y, int buttonNum) { + if (buttonNum == MouseAction::ACTION_LEFT) { + + int slot = getSelectedSlot(x, y); + if (slot >= 0 && slot < Inventory::INVENTORY_SIZE) + { + selectedItem = slot; + //minecraft->soundEngine->playUI("random.click", 1, 1); + } + } +} + +void UploadPhotoScreen::mouseReleased(int x, int y, int buttonNum) +{ + if (buttonNum == MouseAction::ACTION_LEFT) { + + int slot = getSelectedSlot(x, y); + if (slot >= 0 && slot < Inventory::INVENTORY_SIZE && slot == selectedItem) + { + selectSlotAndClose(); + } + } +} + +void UploadPhotoScreen::selectSlotAndClose() +{ + Inventory* inventory = minecraft->player->inventory; + + int itemId = inventory->getSelectionSlotItemId(selectedItem + Inventory::SELECTION_SIZE); + int i = 0; + + for (; i < Inventory::SELECTION_SIZE - 2; i++) + { + if (itemId == inventory->getSelectionSlotItemId(i)) + { + break; + } + } + + // update selection list + for (; i >= 1; i--) + { + inventory->setSelectionSlotItemId(i, inventory->getSelectionSlotItemId(i - 1)); + } + inventory->setSelectionSlotItemId(0, itemId); + inventory->selectSlot(0); + + minecraft->soundEngine->playUI("random.click", 1, 1); + minecraft->setScreen(NULL); +} + +#endif diff --git a/src/client/gui/screens/UploadPhotoScreen.h b/src/client/gui/screens/UploadPhotoScreen.hpp similarity index 96% rename from src/client/gui/screens/UploadPhotoScreen.h rename to src/client/gui/screens/UploadPhotoScreen.hpp index 266f23c..d25467b 100755 --- a/src/client/gui/screens/UploadPhotoScreen.h +++ b/src/client/gui/screens/UploadPhotoScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Screen.h" +#include "Screen.hpp" class UploadPhotoScreen : public Screen { diff --git a/src/client/gui/screens/UsernameScreen.cpp b/src/client/gui/screens/UsernameScreen.cpp index 82f4bca..78f96d3 100644 --- a/src/client/gui/screens/UsernameScreen.cpp +++ b/src/client/gui/screens/UsernameScreen.cpp @@ -1,10 +1,10 @@ -#include "UsernameScreen.h" -#include "StartMenuScreen.h" -#include "../../Minecraft.h" -#include "../Font.h" -#include "../components/Button.h" -#include "../../../platform/input/Keyboard.h" -#include "../../../AppPlatform.h" +#include "UsernameScreen.hpp" +#include "StartMenuScreen.hpp" +#include "client/Minecraft.hpp" +#include "client/gui/Font.hpp" +#include "client/gui/components/Button.hpp" +#include "platform/input/Keyboard.hpp" +#include "AppPlatform.hpp" UsernameScreen::UsernameScreen() : _btnDone(0, "Done"), diff --git a/src/client/gui/screens/UsernameScreen.h b/src/client/gui/screens/UsernameScreen.hpp similarity index 85% rename from src/client/gui/screens/UsernameScreen.h rename to src/client/gui/screens/UsernameScreen.hpp index 02f2830..6d4f29b 100644 --- a/src/client/gui/screens/UsernameScreen.h +++ b/src/client/gui/screens/UsernameScreen.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../Screen.h" -#include "../components/Button.h" -#include "client/gui/components/TextBox.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/TextBox.hpp" #include class UsernameScreen : public Screen diff --git a/src/client/gui/screens/crafting/CraftingFilters.cpp b/src/client/gui/screens/crafting/CraftingFilters.cpp index 5820b13..b7596b8 100755 --- a/src/client/gui/screens/crafting/CraftingFilters.cpp +++ b/src/client/gui/screens/crafting/CraftingFilters.cpp @@ -1,32 +1,32 @@ -#include "CraftingFilters.h" -#include "../../../../world/item/ItemInstance.h" -#include "../../../../world/item/Item.h" -#include "../../../../world/level/tile/Tile.h" -#include "../../../../world/level/material/Material.h" -#include "../../../../world/level/tile/StoneSlabTile.h" - -namespace CraftingFilters { - -bool isStonecutterItem(const ItemInstance& ins) { - Item* const item = ins.getItem(); - if (item->id < 0 || item->id >= 256) - return false; - - Tile* const tile = Tile::tiles[item->id]; - if (!tile) - return false; - - // Special stone/sand cases - if ( tile == Tile::lapisBlock - || tile == Tile::furnace - || tile == Tile::stonecutterBench) - return false; - - if (tile == Tile::stoneSlabHalf && ins.getAuxValue() == StoneSlabTile::WOOD_SLAB) - return false; - - // Return everything stone or sand - return (tile->material == Material::stone || tile->material == Material::sand); -} - +#include "CraftingFilters.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/item/Item.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/StoneSlabTile.hpp" + +namespace CraftingFilters { + +bool isStonecutterItem(const ItemInstance& ins) { + Item* const item = ins.getItem(); + if (item->id < 0 || item->id >= 256) + return false; + + Tile* const tile = Tile::tiles[item->id]; + if (!tile) + return false; + + // Special stone/sand cases + if ( tile == Tile::lapisBlock + || tile == Tile::furnace + || tile == Tile::stonecutterBench) + return false; + + if (tile == Tile::stoneSlabHalf && ins.getAuxValue() == StoneSlabTile::WOOD_SLAB) + return false; + + // Return everything stone or sand + return (tile->material == Material::stone || tile->material == Material::sand); +} + } \ No newline at end of file diff --git a/src/client/gui/screens/crafting/CraftingFilters.h b/src/client/gui/screens/crafting/CraftingFilters.hpp similarity index 100% rename from src/client/gui/screens/crafting/CraftingFilters.h rename to src/client/gui/screens/crafting/CraftingFilters.hpp diff --git a/src/client/gui/screens/crafting/PaneCraftingScreen.cpp b/src/client/gui/screens/crafting/PaneCraftingScreen.cpp index 4e3d025..9cd5672 100755 --- a/src/client/gui/screens/crafting/PaneCraftingScreen.cpp +++ b/src/client/gui/screens/crafting/PaneCraftingScreen.cpp @@ -1,556 +1,556 @@ -#include "PaneCraftingScreen.h" -#include "../touch/TouchStartMenuScreen.h" -#include "../../Screen.h" -#include "../../components/NinePatch.h" -#include "../../../Minecraft.h" -#include "../../../player/LocalPlayer.h" -#include "../../../renderer/Tesselator.h" -#include "../../../renderer/entity/ItemRenderer.h" -#include "../../../../world/item/Item.h" -#include "../../../../world/item/crafting/Recipes.h" -#include "../../../../world/item/ItemCategory.h" -#include "../../../../world/entity/player/Inventory.h" -#include "../../../../util/StringUtils.h" -#include "../../../../locale/I18n.h" -#include "../../../../world/entity/item/ItemEntity.h" -#include "../../../../world/level/Level.h" -#include "../../../../world/item/DyePowderItem.h" -#include "../../../../world/item/crafting/Recipe.h" -#include "platform/input/Keyboard.h" - -static NinePatchLayer* guiPaneFrame = NULL; - -const float BorderPixels = 6.0f; -const int descFrameWidth = 100; - -const int rgbActive = 0xfff0f0f0; -const int rgbInactive = 0xc0635558; -const int rgbInactiveShadow = 0xc0aaaaaa; - -class CategoryButton: public ImageButton { - typedef ImageButton super; -public: - CategoryButton(int id, const ImageButton* const* selectedPtr, NinePatchLayer* stateNormal, NinePatchLayer* statePressed) - : super(id, ""), - selectedPtr(selectedPtr), - stateNormal(stateNormal), - statePressed(statePressed) - {} - - void renderBg(Minecraft* minecraft, int xm, int ym) { - //fill(x+1, y+1, x+w-1, y+h-1, 0xff999999); - - bool hovered = active && (minecraft->useTouchscreen()? - (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); - - if (hovered || *selectedPtr == this) - statePressed->draw(Tesselator::instance, (float)x, (float)y); - else - stateNormal->draw(Tesselator::instance, (float)x, (float)y); - } - bool isSecondImage(bool hovered) { return false; } - -private: - const ImageButton* const* selectedPtr; - NinePatchLayer* stateNormal; - NinePatchLayer* statePressed; -}; - -PaneCraftingScreen::PaneCraftingScreen(int craftingSize) -: craftingSize(craftingSize), - currentCategory(-1), - currentItem(NULL), - pane(NULL), - btnCraft(1), - btnClose(2, ""), - selectedCategoryButton(NULL), - guiBackground(NULL), - guiSlotCategory(NULL), - guiSlotCategorySelected(NULL), - numCategories(4) -{ - for (int i = 0; i < numCategories; ++i) { - categoryBitmasks.push_back(1 << i); - categoryIcons.push_back(i); - } -} - -PaneCraftingScreen::~PaneCraftingScreen() { - for (unsigned int i = 0; i < _items.size(); ++i) - delete _items[i]; - - for (unsigned int i = 0; i < _categoryButtons.size(); ++i) - delete _categoryButtons[i]; - - clearCategoryItems(); - - delete pane; - delete guiBackground; - - // statics - delete guiSlotCategory; - delete guiSlotCategorySelected; - delete guiPaneFrame; -} - -void PaneCraftingScreen::init() { - ImageDef def; - def.name = "gui/spritesheet.png"; - def.x = 0; - def.y = 1; - def.width = def.height = 18; - def.setSrc(IntRectangle(60, 0, 18, 18)); - btnClose.setImageDef(def, true); - btnClose.scaleWhenPressed = false; - - btnCraft.init(minecraft->textures); - - buttons.push_back(&btnCraft); - buttons.push_back(&btnClose); - - // GUI patches - NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); - - guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); - guiPaneFrame = builder.createSymmetrical(IntRectangle(0, 20, 8, 8), 1, 2)->setExcluded(1 << 4); - guiSlotCategory = builder.createSymmetrical(IntRectangle(8, 32, 8, 8), 2, 2); - guiSlotCategorySelected = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 2, 2); - - initCategories(); -} - -void PaneCraftingScreen::initCategories() { - _categories.resize(numCategories); - - // Category buttons - for (int i = 0; i < numCategories; ++i) { - ImageButton* button = new CategoryButton(100 + i, &selectedCategoryButton, guiSlotCategory, guiSlotCategorySelected); - _categoryButtons.push_back( button ); - buttons.push_back( button ); - } - - const RecipeList& all = Recipes::getInstance()->getRecipes(); - RecipeList filtered; - filtered.reserve(all.size()); - - // Apply size filter - for (unsigned int i = 0; i < all.size(); ++i) { - if (craftingSize >= all[i]->getCraftingSize()) - filtered.push_back(all[i]); - } - // Filter by subclass impl - filterRecipes(filtered); - - // Add items from filtered recipes - for (unsigned int i = 0; i < filtered.size(); ++i) - addItem(filtered[i]); - - recheckRecipes(); -} - -void PaneCraftingScreen::setupPositions() { - // Left - Categories - const int buttonHeight = (height - 16) / (Mth::Max(numCategories, 4)); - for (unsigned c = 0; c < _categoryButtons.size(); ++c) { - ImageButton* button = _categoryButtons[c]; - button->x = (int)BorderPixels; - button->y = (int)BorderPixels + c * (1 + buttonHeight); - button->width = (int)buttonHeight; - button->height = (int)buttonHeight; - - int icon = categoryIcons[c]; - ImageDef def; - def.x = 0; - def.width = def.height = (float)buttonHeight; - def.name = "gui/spritesheet.png"; - def.setSrc(IntRectangle(32 * (icon/2), 64 + (icon&1) * 32, 32, 32)); - button->setImageDef(def, false); - } - // Right - Description - const int craftW = (int)(100 - 2 * BorderPixels - 0); - btnCraft.x = width - descFrameWidth + (descFrameWidth-craftW)/2 - 1;// width - descFrameWidth + (int)BorderPixels + 4; - btnCraft.y = 20; - btnCraft.setSize((float)craftW, 62); - - btnClose.width = btnClose.height = 19; - btnClose.x = width - btnClose.width; - btnClose.y = 0; - - // Middle - Scrolling pane - paneRect.x = buttonHeight + 2 * (int)BorderPixels; - paneRect.y = (int)BorderPixels + 2; - paneRect.w = width - paneRect.x - descFrameWidth; - paneRect.h = height - 2 * (int)BorderPixels - 4; - - guiPaneFrame->setSize((float)paneRect.w + 2, (float)paneRect.h + 4); - guiBackground->setSize((float)width, (float)height); - guiSlotCategory->setSize((float)buttonHeight, (float)buttonHeight); - guiSlotCategorySelected->setSize((float)buttonHeight, (float)buttonHeight); - - int oldCategory = currentCategory; - currentCategory = -1; - buttonClicked(_categoryButtons[pane?oldCategory:0]); -} - -void PaneCraftingScreen::tick() { - if (pane) pane->tick(); -} - -void PaneCraftingScreen::render(int xm, int ym, float a) { - const int N = 5; - static StopwatchNLast r(N); - //renderBackground(); - Tesselator& t = Tesselator::instance; - guiBackground->draw(t, 0, 0); - glEnable2(GL_ALPHA_TEST); - - // Buttons (Left side + crafting) - super::render(xm, ym, a); - - // Mid - r.start(); - // Blit frame - guiPaneFrame->draw(t, (float)paneRect.x - 1, (float)paneRect.y - 2); - if (pane) pane->render(xm, ym, a); - r.stop(); - //r.printEvery(N, "test"); - - const float slotWidth = (float)btnCraft.width / 2.0f; - const float slotHeight = (float)btnCraft.height / 2.0f; - const float slotBx = (float)btnCraft.x + slotWidth/2 - 8; - const float slotBy = (float)btnCraft.y + slotHeight/2 - 9; - - ItemInstance reqItem; - // Right side - if (currentItem) { - t.beginOverride(); - for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { - const float xx = slotBx + slotWidth * (float)(i % 2); - const float yy = slotBy + slotHeight * (float)(i / 2); - CItem::ReqItem& req = currentItem->neededItems[i]; - reqItem = req.item; - if (reqItem.getAuxValue() == -1) reqItem.setAuxValue(0); - ItemRenderer::renderGuiItem(NULL, minecraft->textures, &reqItem, xx, yy, 16, 16, true); - } - t.endOverrideAndDraw(); - - char buf[16]; - const float scale = 2.0f / 3.0f; - const float invScale = 1.0f / scale; - t.beginOverride(); - t.scale2d(scale, scale); - for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { - const float xx = 4 + invScale * (slotBx + slotWidth * (float)(i % 2)); - const float yy = 23 + invScale * (slotBy + slotHeight * (float)(i / 2)); - CItem::ReqItem& req = currentItem->neededItems[i]; - - int bufIndex = 0; - bufIndex += Gui::itemCountItoa(&buf[bufIndex], req.has); - strcpy(&buf[bufIndex], "/"); bufIndex += 1; - bufIndex += Gui::itemCountItoa(&buf[bufIndex], req.item.count); - - buf[bufIndex] = 0; - if (req.enough()) - minecraft->font->drawShadow(buf, xx, yy, rgbActive); - else { - minecraft->font->draw(buf, xx+1, yy+1, rgbInactiveShadow); - minecraft->font->draw(buf, xx, yy, rgbInactive); - } - } - t.resetScale(); - t.endOverrideAndDraw(); - - //minecraft->font->drawWordWrap(currentItemDesc, rightBx + 2, (float)btnCraft.y + btnCraft.h + 6, descFrameWidth-4, rgbActive); - minecraft->font->drawWordWrap(currentItemDesc, (float)btnCraft.x, (float)(btnCraft.y + btnCraft.height + 6), (float)btnCraft.width, rgbActive); - } - //glDisable2(GL_ALPHA_TEST); -} - -void PaneCraftingScreen::buttonClicked(Button* button) { - if (button == &btnCraft) - craftSelectedItem(); - - if (button == &btnClose) - minecraft->setScreen(NULL); - - // Did we click a category? - if (button->id >= 100 && button->id < 200) { - int categoryId = button->id - 100; - ItemList& cat = _categories[categoryId]; - if (!cat.empty()) { - onItemSelected(categoryId, cat[0]); - pane->setSelected(0, true); - } - currentCategory = categoryId; - selectedCategoryButton = (CategoryButton*)button; - } -} - -static void randomlyFillItemPack(ItemPack* ip, int numItems) { - int added = 0; - ItemInstance item(0, 1, 0); - while (added < numItems) { - int t = Mth::random(512); - if (!Item::items[t]) continue; - - item.id = t; - int id = ItemPack::getIdForItemInstance(&item); - int count = Mth::random(10); - for (int i = 0; i < count; ++i) - ip->add(id); - ++added; - } -} - -static bool sortCanCraftPredicate(const CItem* a, const CItem* b) { - //if (a->maxBuildCount == 0 && b->maxBuildCount > 0) return false; - //if (b->maxBuildCount == 0 && a->maxBuildCount > 0) return true; - return a->sortText < b->sortText; -} - -void PaneCraftingScreen::recheckRecipes() { - ItemPack ip; - - if (minecraft->player && minecraft->player->inventory) { - Inventory* inv = (minecraft->player)->inventory; - - for (int i = Inventory::MAX_SELECTION_SIZE; i < inv->getContainerSize(); ++i) { - if (ItemInstance* item = inv->getItem(i)) - ip.add(ItemPack::getIdForItemInstance(item), item->count); - } - } else { - randomlyFillItemPack(&ip, 50); - } - - ip.print(); - - Stopwatch w; - w.start(); - - for (unsigned int i = 0; i < _items.size(); ++i) { - CItem* item = _items[i]; - item->neededItems.clear(); - item->setCanCraft(true); - - Recipe* recipe = item->recipe; - item->inventoryCount = ip.getCount(ItemPack::getIdForItemInstance(&item->item)); - //item->maxBuildCount = recipe->getMaxCraftCount(ip); - // Override the canCraft thing, since I'm too lazy - // to fix the above (commented out) function - std::vector items = recipe->getItemPack().getItemInstances(); - for (unsigned int j = 0; j < items.size(); ++j) { - ItemInstance& jtem = items[j]; - int has = 0; - if (!Recipe::isAnyAuxValue(&jtem) && (jtem.getAuxValue() == Recipe::ANY_AUX_VALUE)) { - // If the aux value on the item matters, but the recipe says it doesn't, - // use this override (by fetching all items with aux-ids 0-15) - ItemInstance aux(jtem); - for (int i = 0; i < 16; ++i) { - aux.setAuxValue(i); - has += ip.getCount(ItemPack::getIdForItemInstance(&aux)); - } - } else { - // Else just use the normal aux-value rules - has = ip.getCount(ItemPack::getIdForItemInstance(&jtem)); - } - CItem::ReqItem req(jtem, has); - item->neededItems.push_back(req); - item->setCanCraft(item->canCraft() && req.enough()); - } - } - w.stop(); - w.printEvery(1, "> craft "); - - for (unsigned int c = 0; c < _categories.size(); ++c) - std::stable_sort(_categories[c].begin(), _categories[c].end(), sortCanCraftPredicate); -} - -void PaneCraftingScreen::addItem( Recipe* recipe ) -{ - ItemInstance instance = recipe->getResultItem(); - Item* item = instance.getItem(); - CItem* ci = new CItem(instance, recipe, instance.getName());//item->getDescriptionId()); - if (item->id == Tile::cloth->id) - ci->sortText = "Wool " + ci->text; - if (item->id == Item::dye_powder->id) - ci->sortText = "ZDye " + ci->text; - _items.push_back(ci); - - if (item->category < 0) - return; - - for (int i = 0; i < (int)categoryBitmasks.size(); ++i) { - int bitmask = categoryBitmasks[i]; - if ((bitmask & item->category) != 0) - _categories[i].push_back( ci ); - } -} - -void PaneCraftingScreen::onItemSelected(const ItemPane* forPane, int itemIndexInCurrentCategory) { - if (currentCategory >= (int)_categories.size()) return; - if (itemIndexInCurrentCategory >= (int)_categories[currentCategory].size()) return; - onItemSelected(currentCategory, _categories[currentCategory][itemIndexInCurrentCategory]); -} - -void PaneCraftingScreen::onItemSelected(int buttonIndex, CItem* item) { - currentItem = item; - currentItemDesc = I18n::getDescriptionString(currentItem->item); - - if (buttonIndex != currentCategory) { - // Clear item buttons for this category - clearCategoryItems(); - - // Setup new buttons for the items in this category - const int NumCategoryItems = _categories[buttonIndex].size(); - - if (pane) delete pane; - pane = new ItemPane(this, minecraft->textures, paneRect, NumCategoryItems, height, minecraft->height); - pane->f = minecraft->font; - - currentCategory = buttonIndex; - } -} - -void PaneCraftingScreen::clearCategoryItems() -{ - for (unsigned int i = 0; i < currentCategoryButtons.size(); ++i) { - delete currentCategoryButtons[i]; - } - currentCategoryButtons.clear(); -} - -void PaneCraftingScreen::keyPressed( int eventKey ) -{ - if (eventKey == Keyboard::KEY_ESCAPE || eventKey == Keyboard::KEY_E) { - minecraft->setScreen(NULL); - //minecraft->grabMouse(); - } else { - super::keyPressed(eventKey); - } -} - -void PaneCraftingScreen::craftSelectedItem() -{ - if (!currentItem) - return; - if (!currentItem->canCraft()) - return; - - ItemInstance resultItem = currentItem->item; - - if (minecraft->player) { - // Remove all items required for the recipe and ... - for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { - CItem::ReqItem& req = currentItem->neededItems[i]; - - // If the recipe allows any aux-value as ingredients, first deplete - // aux == 0 from inventory. Since I'm not sure if this always is - // correct, let's only do it for ingredient sandstone for now. - ItemInstance toRemove = req.item; - - if (Tile::sandStone->id == req.item.id - && Recipe::ANY_AUX_VALUE == req.item.getAuxValue()) { - toRemove.setAuxValue(0); - toRemove.count = minecraft->player->inventory->removeResource(toRemove, true); - toRemove.setAuxValue(Recipe::ANY_AUX_VALUE); - } - - if (toRemove.count > 0) { - minecraft->player->inventory->removeResource(toRemove); - } - } - // ... add the new one! (in this order, to fill empty slots better) - // if it doesn't fit, throw it on the ground! - if (!minecraft->player->inventory->add(&resultItem)) { - minecraft->player->drop(new ItemInstance(resultItem), false); - } - - recheckRecipes(); - } -} - -bool PaneCraftingScreen::renderGameBehind() -{ - return false; -} - -bool PaneCraftingScreen::closeOnPlayerHurt() { - return true; -} - -void PaneCraftingScreen::filterRecipes(RecipeList& recipes) { - for (int i = recipes.size() - 1; i >= 0; --i) { - if (!filterRecipe(*recipes[i])) - recipes.erase(recipes.begin() + i); - } -} - -const std::vector& PaneCraftingScreen::getItems(const ItemPane* forPane) -{ - return _categories[currentCategory]; -} - -void PaneCraftingScreen::setSingleCategoryAndIcon(int categoryBitmask, int categoryIcon) { - assert(!minecraft && "setSingleCategoryAndIcon needs to be called from subclass constructor!\n"); - - numCategories = 1; - - categoryIcons.clear(); - categoryIcons.push_back(categoryIcon); - - categoryBitmasks.clear(); - categoryBitmasks.push_back(categoryBitmask); -} - -// -// Craft button -// -CraftButton::CraftButton( int id) -: super(id, ""), - bg(NULL), - bgSelected(NULL), - numItems(0) -{ -} - -CraftButton::~CraftButton() -{ - delete bg; - delete bgSelected; -} - -void CraftButton::setSize(float w, float h ) { - this->width = (int)w; - this->height = (int)h; - - if (bg && bgSelected) { - bg->setSize(w, h); - bgSelected->setSize(w, h); - } -} - -void CraftButton::init( Textures* textures) -{ - NinePatchFactory builder(textures, "gui/spritesheet.png"); - bg = builder.createSymmetrical(IntRectangle(112, 0, 8, 67), 2, 2); - bgSelected = builder.createSymmetrical(IntRectangle(120, 0, 8, 67), 2, 2); -} - -IntRectangle CraftButton::getItemPos( int i ) -{ - return IntRectangle(); -} - -void CraftButton::renderBg(Minecraft* minecraft, int xm, int ym) { - if (!bg || !bgSelected) - return; - //fill(x+1, y+1, x+w-1, y+h-1, 0xff999999); - - bool hovered = active && (minecraft->useTouchscreen()? - (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); - - if (hovered || selected) - bgSelected->draw(Tesselator::instance, (float)x, (float)y); - else - bg->draw(Tesselator::instance, (float)x, (float)y); -} +#include "PaneCraftingScreen.hpp" +#include "client/gui/screens/touch/TouchStartMenuScreen.hpp" +#include "client/gui/Screen.hpp" +#include "client/gui/components/NinePatch.hpp" +#include "client/Minecraft.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "world/item/Item.hpp" +#include "world/item/crafting/Recipes.hpp" +#include "world/item/ItemCategory.hpp" +#include "world/entity/player/Inventory.hpp" +#include "util/StringUtils.hpp" +#include "locale/I18n.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/level/Level.hpp" +#include "world/item/DyePowderItem.hpp" +#include "world/item/crafting/Recipe.hpp" +#include "platform/input/Keyboard.hpp" + +static NinePatchLayer* guiPaneFrame = NULL; + +const float BorderPixels = 6.0f; +const int descFrameWidth = 100; + +const int rgbActive = 0xfff0f0f0; +const int rgbInactive = 0xc0635558; +const int rgbInactiveShadow = 0xc0aaaaaa; + +class CategoryButton: public ImageButton { + typedef ImageButton super; +public: + CategoryButton(int id, const ImageButton* const* selectedPtr, NinePatchLayer* stateNormal, NinePatchLayer* statePressed) + : super(id, ""), + selectedPtr(selectedPtr), + stateNormal(stateNormal), + statePressed(statePressed) + {} + + void renderBg(Minecraft* minecraft, int xm, int ym) { + //fill(x+1, y+1, x+w-1, y+h-1, 0xff999999); + + bool hovered = active && (minecraft->useTouchscreen()? + (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); + + if (hovered || *selectedPtr == this) + statePressed->draw(Tesselator::instance, (float)x, (float)y); + else + stateNormal->draw(Tesselator::instance, (float)x, (float)y); + } + bool isSecondImage(bool hovered) { return false; } + +private: + const ImageButton* const* selectedPtr; + NinePatchLayer* stateNormal; + NinePatchLayer* statePressed; +}; + +PaneCraftingScreen::PaneCraftingScreen(int craftingSize) +: craftingSize(craftingSize), + currentCategory(-1), + currentItem(NULL), + pane(NULL), + btnCraft(1), + btnClose(2, ""), + selectedCategoryButton(NULL), + guiBackground(NULL), + guiSlotCategory(NULL), + guiSlotCategorySelected(NULL), + numCategories(4) +{ + for (int i = 0; i < numCategories; ++i) { + categoryBitmasks.push_back(1 << i); + categoryIcons.push_back(i); + } +} + +PaneCraftingScreen::~PaneCraftingScreen() { + for (unsigned int i = 0; i < _items.size(); ++i) + delete _items[i]; + + for (unsigned int i = 0; i < _categoryButtons.size(); ++i) + delete _categoryButtons[i]; + + clearCategoryItems(); + + delete pane; + delete guiBackground; + + // statics + delete guiSlotCategory; + delete guiSlotCategorySelected; + delete guiPaneFrame; +} + +void PaneCraftingScreen::init() { + ImageDef def; + def.name = "gui/spritesheet.png"; + def.x = 0; + def.y = 1; + def.width = def.height = 18; + def.setSrc(IntRectangle(60, 0, 18, 18)); + btnClose.setImageDef(def, true); + btnClose.scaleWhenPressed = false; + + btnCraft.init(minecraft->textures); + + buttons.push_back(&btnCraft); + buttons.push_back(&btnClose); + + // GUI patches + NinePatchFactory builder(minecraft->textures, "gui/spritesheet.png"); + + guiBackground = builder.createSymmetrical(IntRectangle(0, 0, 16, 16), 4, 4); + guiPaneFrame = builder.createSymmetrical(IntRectangle(0, 20, 8, 8), 1, 2)->setExcluded(1 << 4); + guiSlotCategory = builder.createSymmetrical(IntRectangle(8, 32, 8, 8), 2, 2); + guiSlotCategorySelected = builder.createSymmetrical(IntRectangle(0, 32, 8, 8), 2, 2); + + initCategories(); +} + +void PaneCraftingScreen::initCategories() { + _categories.resize(numCategories); + + // Category buttons + for (int i = 0; i < numCategories; ++i) { + ImageButton* button = new CategoryButton(100 + i, &selectedCategoryButton, guiSlotCategory, guiSlotCategorySelected); + _categoryButtons.push_back( button ); + buttons.push_back( button ); + } + + const RecipeList& all = Recipes::getInstance()->getRecipes(); + RecipeList filtered; + filtered.reserve(all.size()); + + // Apply size filter + for (unsigned int i = 0; i < all.size(); ++i) { + if (craftingSize >= all[i]->getCraftingSize()) + filtered.push_back(all[i]); + } + // Filter by subclass impl + filterRecipes(filtered); + + // Add items from filtered recipes + for (unsigned int i = 0; i < filtered.size(); ++i) + addItem(filtered[i]); + + recheckRecipes(); +} + +void PaneCraftingScreen::setupPositions() { + // Left - Categories + const int buttonHeight = (height - 16) / (Mth::Max(numCategories, 4)); + for (unsigned c = 0; c < _categoryButtons.size(); ++c) { + ImageButton* button = _categoryButtons[c]; + button->x = (int)BorderPixels; + button->y = (int)BorderPixels + c * (1 + buttonHeight); + button->width = (int)buttonHeight; + button->height = (int)buttonHeight; + + int icon = categoryIcons[c]; + ImageDef def; + def.x = 0; + def.width = def.height = (float)buttonHeight; + def.name = "gui/spritesheet.png"; + def.setSrc(IntRectangle(32 * (icon/2), 64 + (icon&1) * 32, 32, 32)); + button->setImageDef(def, false); + } + // Right - Description + const int craftW = (int)(100 - 2 * BorderPixels - 0); + btnCraft.x = width - descFrameWidth + (descFrameWidth-craftW)/2 - 1;// width - descFrameWidth + (int)BorderPixels + 4; + btnCraft.y = 20; + btnCraft.setSize((float)craftW, 62); + + btnClose.width = btnClose.height = 19; + btnClose.x = width - btnClose.width; + btnClose.y = 0; + + // Middle - Scrolling pane + paneRect.x = buttonHeight + 2 * (int)BorderPixels; + paneRect.y = (int)BorderPixels + 2; + paneRect.w = width - paneRect.x - descFrameWidth; + paneRect.h = height - 2 * (int)BorderPixels - 4; + + guiPaneFrame->setSize((float)paneRect.w + 2, (float)paneRect.h + 4); + guiBackground->setSize((float)width, (float)height); + guiSlotCategory->setSize((float)buttonHeight, (float)buttonHeight); + guiSlotCategorySelected->setSize((float)buttonHeight, (float)buttonHeight); + + int oldCategory = currentCategory; + currentCategory = -1; + buttonClicked(_categoryButtons[pane?oldCategory:0]); +} + +void PaneCraftingScreen::tick() { + if (pane) pane->tick(); +} + +void PaneCraftingScreen::render(int xm, int ym, float a) { + const int N = 5; + static StopwatchNLast r(N); + //renderBackground(); + Tesselator& t = Tesselator::instance; + guiBackground->draw(t, 0, 0); + glEnable2(GL_ALPHA_TEST); + + // Buttons (Left side + crafting) + super::render(xm, ym, a); + + // Mid + r.start(); + // Blit frame + guiPaneFrame->draw(t, (float)paneRect.x - 1, (float)paneRect.y - 2); + if (pane) pane->render(xm, ym, a); + r.stop(); + //r.printEvery(N, "test"); + + const float slotWidth = (float)btnCraft.width / 2.0f; + const float slotHeight = (float)btnCraft.height / 2.0f; + const float slotBx = (float)btnCraft.x + slotWidth/2 - 8; + const float slotBy = (float)btnCraft.y + slotHeight/2 - 9; + + ItemInstance reqItem; + // Right side + if (currentItem) { + t.beginOverride(); + for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { + const float xx = slotBx + slotWidth * (float)(i % 2); + const float yy = slotBy + slotHeight * (float)(i / 2); + CItem::ReqItem& req = currentItem->neededItems[i]; + reqItem = req.item; + if (reqItem.getAuxValue() == -1) reqItem.setAuxValue(0); + ItemRenderer::renderGuiItem(NULL, minecraft->textures, &reqItem, xx, yy, 16, 16, true); + } + t.endOverrideAndDraw(); + + char buf[16]; + const float scale = 2.0f / 3.0f; + const float invScale = 1.0f / scale; + t.beginOverride(); + t.scale2d(scale, scale); + for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { + const float xx = 4 + invScale * (slotBx + slotWidth * (float)(i % 2)); + const float yy = 23 + invScale * (slotBy + slotHeight * (float)(i / 2)); + CItem::ReqItem& req = currentItem->neededItems[i]; + + int bufIndex = 0; + bufIndex += Gui::itemCountItoa(&buf[bufIndex], req.has); + strcpy(&buf[bufIndex], "/"); bufIndex += 1; + bufIndex += Gui::itemCountItoa(&buf[bufIndex], req.item.count); + + buf[bufIndex] = 0; + if (req.enough()) + minecraft->font->drawShadow(buf, xx, yy, rgbActive); + else { + minecraft->font->draw(buf, xx+1, yy+1, rgbInactiveShadow); + minecraft->font->draw(buf, xx, yy, rgbInactive); + } + } + t.resetScale(); + t.endOverrideAndDraw(); + + //minecraft->font->drawWordWrap(currentItemDesc, rightBx + 2, (float)btnCraft.y + btnCraft.h + 6, descFrameWidth-4, rgbActive); + minecraft->font->drawWordWrap(currentItemDesc, (float)btnCraft.x, (float)(btnCraft.y + btnCraft.height + 6), (float)btnCraft.width, rgbActive); + } + //glDisable2(GL_ALPHA_TEST); +} + +void PaneCraftingScreen::buttonClicked(Button* button) { + if (button == &btnCraft) + craftSelectedItem(); + + if (button == &btnClose) + minecraft->setScreen(NULL); + + // Did we click a category? + if (button->id >= 100 && button->id < 200) { + int categoryId = button->id - 100; + ItemList& cat = _categories[categoryId]; + if (!cat.empty()) { + onItemSelected(categoryId, cat[0]); + pane->setSelected(0, true); + } + currentCategory = categoryId; + selectedCategoryButton = (CategoryButton*)button; + } +} + +static void randomlyFillItemPack(ItemPack* ip, int numItems) { + int added = 0; + ItemInstance item(0, 1, 0); + while (added < numItems) { + int t = Mth::random(512); + if (!Item::items[t]) continue; + + item.id = t; + int id = ItemPack::getIdForItemInstance(&item); + int count = Mth::random(10); + for (int i = 0; i < count; ++i) + ip->add(id); + ++added; + } +} + +static bool sortCanCraftPredicate(const CItem* a, const CItem* b) { + //if (a->maxBuildCount == 0 && b->maxBuildCount > 0) return false; + //if (b->maxBuildCount == 0 && a->maxBuildCount > 0) return true; + return a->sortText < b->sortText; +} + +void PaneCraftingScreen::recheckRecipes() { + ItemPack ip; + + if (minecraft->player && minecraft->player->inventory) { + Inventory* inv = (minecraft->player)->inventory; + + for (int i = Inventory::MAX_SELECTION_SIZE; i < inv->getContainerSize(); ++i) { + if (ItemInstance* item = inv->getItem(i)) + ip.add(ItemPack::getIdForItemInstance(item), item->count); + } + } else { + randomlyFillItemPack(&ip, 50); + } + + ip.print(); + + Stopwatch w; + w.start(); + + for (unsigned int i = 0; i < _items.size(); ++i) { + CItem* item = _items[i]; + item->neededItems.clear(); + item->setCanCraft(true); + + Recipe* recipe = item->recipe; + item->inventoryCount = ip.getCount(ItemPack::getIdForItemInstance(&item->item)); + //item->maxBuildCount = recipe->getMaxCraftCount(ip); + // Override the canCraft thing, since I'm too lazy + // to fix the above (commented out) function + std::vector items = recipe->getItemPack().getItemInstances(); + for (unsigned int j = 0; j < items.size(); ++j) { + ItemInstance& jtem = items[j]; + int has = 0; + if (!Recipe::isAnyAuxValue(&jtem) && (jtem.getAuxValue() == Recipe::ANY_AUX_VALUE)) { + // If the aux value on the item matters, but the recipe says it doesn't, + // use this override (by fetching all items with aux-ids 0-15) + ItemInstance aux(jtem); + for (int i = 0; i < 16; ++i) { + aux.setAuxValue(i); + has += ip.getCount(ItemPack::getIdForItemInstance(&aux)); + } + } else { + // Else just use the normal aux-value rules + has = ip.getCount(ItemPack::getIdForItemInstance(&jtem)); + } + CItem::ReqItem req(jtem, has); + item->neededItems.push_back(req); + item->setCanCraft(item->canCraft() && req.enough()); + } + } + w.stop(); + w.printEvery(1, "> craft "); + + for (unsigned int c = 0; c < _categories.size(); ++c) + std::stable_sort(_categories[c].begin(), _categories[c].end(), sortCanCraftPredicate); +} + +void PaneCraftingScreen::addItem( Recipe* recipe ) +{ + ItemInstance instance = recipe->getResultItem(); + Item* item = instance.getItem(); + CItem* ci = new CItem(instance, recipe, instance.getName());//item->getDescriptionId()); + if (item->id == Tile::cloth->id) + ci->sortText = "Wool " + ci->text; + if (item->id == Item::dye_powder->id) + ci->sortText = "ZDye " + ci->text; + _items.push_back(ci); + + if (item->category < 0) + return; + + for (int i = 0; i < (int)categoryBitmasks.size(); ++i) { + int bitmask = categoryBitmasks[i]; + if ((bitmask & item->category) != 0) + _categories[i].push_back( ci ); + } +} + +void PaneCraftingScreen::onItemSelected(const ItemPane* forPane, int itemIndexInCurrentCategory) { + if (currentCategory >= (int)_categories.size()) return; + if (itemIndexInCurrentCategory >= (int)_categories[currentCategory].size()) return; + onItemSelected(currentCategory, _categories[currentCategory][itemIndexInCurrentCategory]); +} + +void PaneCraftingScreen::onItemSelected(int buttonIndex, CItem* item) { + currentItem = item; + currentItemDesc = I18n::getDescriptionString(currentItem->item); + + if (buttonIndex != currentCategory) { + // Clear item buttons for this category + clearCategoryItems(); + + // Setup new buttons for the items in this category + const int NumCategoryItems = _categories[buttonIndex].size(); + + if (pane) delete pane; + pane = new ItemPane(this, minecraft->textures, paneRect, NumCategoryItems, height, minecraft->height); + pane->f = minecraft->font; + + currentCategory = buttonIndex; + } +} + +void PaneCraftingScreen::clearCategoryItems() +{ + for (unsigned int i = 0; i < currentCategoryButtons.size(); ++i) { + delete currentCategoryButtons[i]; + } + currentCategoryButtons.clear(); +} + +void PaneCraftingScreen::keyPressed( int eventKey ) +{ + if (eventKey == Keyboard::KEY_ESCAPE || eventKey == Keyboard::KEY_E) { + minecraft->setScreen(NULL); + //minecraft->grabMouse(); + } else { + super::keyPressed(eventKey); + } +} + +void PaneCraftingScreen::craftSelectedItem() +{ + if (!currentItem) + return; + if (!currentItem->canCraft()) + return; + + ItemInstance resultItem = currentItem->item; + + if (minecraft->player) { + // Remove all items required for the recipe and ... + for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { + CItem::ReqItem& req = currentItem->neededItems[i]; + + // If the recipe allows any aux-value as ingredients, first deplete + // aux == 0 from inventory. Since I'm not sure if this always is + // correct, let's only do it for ingredient sandstone for now. + ItemInstance toRemove = req.item; + + if (Tile::sandStone->id == req.item.id + && Recipe::ANY_AUX_VALUE == req.item.getAuxValue()) { + toRemove.setAuxValue(0); + toRemove.count = minecraft->player->inventory->removeResource(toRemove, true); + toRemove.setAuxValue(Recipe::ANY_AUX_VALUE); + } + + if (toRemove.count > 0) { + minecraft->player->inventory->removeResource(toRemove); + } + } + // ... add the new one! (in this order, to fill empty slots better) + // if it doesn't fit, throw it on the ground! + if (!minecraft->player->inventory->add(&resultItem)) { + minecraft->player->drop(new ItemInstance(resultItem), false); + } + + recheckRecipes(); + } +} + +bool PaneCraftingScreen::renderGameBehind() +{ + return false; +} + +bool PaneCraftingScreen::closeOnPlayerHurt() { + return true; +} + +void PaneCraftingScreen::filterRecipes(RecipeList& recipes) { + for (int i = recipes.size() - 1; i >= 0; --i) { + if (!filterRecipe(*recipes[i])) + recipes.erase(recipes.begin() + i); + } +} + +const std::vector& PaneCraftingScreen::getItems(const ItemPane* forPane) +{ + return _categories[currentCategory]; +} + +void PaneCraftingScreen::setSingleCategoryAndIcon(int categoryBitmask, int categoryIcon) { + assert(!minecraft && "setSingleCategoryAndIcon needs to be called from subclass constructor!\n"); + + numCategories = 1; + + categoryIcons.clear(); + categoryIcons.push_back(categoryIcon); + + categoryBitmasks.clear(); + categoryBitmasks.push_back(categoryBitmask); +} + +// +// Craft button +// +CraftButton::CraftButton( int id) +: super(id, ""), + bg(NULL), + bgSelected(NULL), + numItems(0) +{ +} + +CraftButton::~CraftButton() +{ + delete bg; + delete bgSelected; +} + +void CraftButton::setSize(float w, float h ) { + this->width = (int)w; + this->height = (int)h; + + if (bg && bgSelected) { + bg->setSize(w, h); + bgSelected->setSize(w, h); + } +} + +void CraftButton::init( Textures* textures) +{ + NinePatchFactory builder(textures, "gui/spritesheet.png"); + bg = builder.createSymmetrical(IntRectangle(112, 0, 8, 67), 2, 2); + bgSelected = builder.createSymmetrical(IntRectangle(120, 0, 8, 67), 2, 2); +} + +IntRectangle CraftButton::getItemPos( int i ) +{ + return IntRectangle(); +} + +void CraftButton::renderBg(Minecraft* minecraft, int xm, int ym) { + if (!bg || !bgSelected) + return; + //fill(x+1, y+1, x+w-1, y+h-1, 0xff999999); + + bool hovered = active && (minecraft->useTouchscreen()? + (_currentlyDown && xm >= x && ym >= y && xm < x + width && ym < y + height) : isInside(xm, ym)); + + if (hovered || selected) + bgSelected->draw(Tesselator::instance, (float)x, (float)y); + else + bg->draw(Tesselator::instance, (float)x, (float)y); +} diff --git a/src/client/gui/screens/crafting/PaneCraftingScreen.h b/src/client/gui/screens/crafting/PaneCraftingScreen.hpp similarity index 89% rename from src/client/gui/screens/crafting/PaneCraftingScreen.h rename to src/client/gui/screens/crafting/PaneCraftingScreen.hpp index 9639181..5bcb7aa 100755 --- a/src/client/gui/screens/crafting/PaneCraftingScreen.h +++ b/src/client/gui/screens/crafting/PaneCraftingScreen.hpp @@ -1,12 +1,12 @@ #pragma once -#include "../../Screen.h" -#include "../../../../world/item/crafting/Recipes.h" -#include "../../../../world/item/ItemInstance.h" +#include "client/gui/Screen.hpp" +#include "world/item/crafting/Recipes.hpp" +#include "world/item/ItemInstance.hpp" -#include "../../components/ScrollingPane.h" -#include "../../components/ImageButton.h" -#include "../../components/ItemPane.h" +#include "client/gui/components/ScrollingPane.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "client/gui/components/ItemPane.hpp" class Font; class CItem; diff --git a/src/client/gui/screens/crafting/StonecutterScreen.cpp b/src/client/gui/screens/crafting/StonecutterScreen.cpp index 08a0fdd..c0e7d7e 100755 --- a/src/client/gui/screens/crafting/StonecutterScreen.cpp +++ b/src/client/gui/screens/crafting/StonecutterScreen.cpp @@ -1,17 +1,17 @@ -#include "StonecutterScreen.h" -#include "CraftingFilters.h" -#include "../../../../world/level/material/Material.h" -#include "../../../../world/item/ItemCategory.h" - -StonecutterScreen::StonecutterScreen() -: super(Recipe::SIZE_3X3) -{ - setSingleCategoryAndIcon(ItemCategory::Structures, 5); -} - -StonecutterScreen::~StonecutterScreen() { -} - -bool StonecutterScreen::filterRecipe(const Recipe& r) { - return CraftingFilters::isStonecutterItem(r.getResultItem()); -} +#include "StonecutterScreen.hpp" +#include "CraftingFilters.hpp" +#include "world/level/material/Material.hpp" +#include "world/item/ItemCategory.hpp" + +StonecutterScreen::StonecutterScreen() +: super(Recipe::SIZE_3X3) +{ + setSingleCategoryAndIcon(ItemCategory::Structures, 5); +} + +StonecutterScreen::~StonecutterScreen() { +} + +bool StonecutterScreen::filterRecipe(const Recipe& r) { + return CraftingFilters::isStonecutterItem(r.getResultItem()); +} diff --git a/src/client/gui/screens/crafting/StonecutterScreen.h b/src/client/gui/screens/crafting/StonecutterScreen.hpp similarity index 86% rename from src/client/gui/screens/crafting/StonecutterScreen.h rename to src/client/gui/screens/crafting/StonecutterScreen.hpp index 978a2c6..b65af2f 100755 --- a/src/client/gui/screens/crafting/StonecutterScreen.h +++ b/src/client/gui/screens/crafting/StonecutterScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "PaneCraftingScreen.h" +#include "PaneCraftingScreen.hpp" class StonecutterScreen: public PaneCraftingScreen { diff --git a/src/client/gui/screens/crafting/WorkbenchScreen.cpp b/src/client/gui/screens/crafting/WorkbenchScreen.cpp index 3c29dfc..6d8469d 100755 --- a/src/client/gui/screens/crafting/WorkbenchScreen.cpp +++ b/src/client/gui/screens/crafting/WorkbenchScreen.cpp @@ -1,15 +1,15 @@ -#include "WorkbenchScreen.h" -#include "CraftingFilters.h" -#include "../../../../world/level/material/Material.h" - -WorkbenchScreen::WorkbenchScreen(int craftingSize) -: super(craftingSize) -{ -} - -WorkbenchScreen::~WorkbenchScreen() { -} - -bool WorkbenchScreen::filterRecipe(const Recipe& r) { - return !CraftingFilters::isStonecutterItem(r.getResultItem()); -} +#include "WorkbenchScreen.hpp" +#include "CraftingFilters.hpp" +#include "world/level/material/Material.hpp" + +WorkbenchScreen::WorkbenchScreen(int craftingSize) +: super(craftingSize) +{ +} + +WorkbenchScreen::~WorkbenchScreen() { +} + +bool WorkbenchScreen::filterRecipe(const Recipe& r) { + return !CraftingFilters::isStonecutterItem(r.getResultItem()); +} diff --git a/src/client/gui/screens/crafting/WorkbenchScreen.h b/src/client/gui/screens/crafting/WorkbenchScreen.hpp similarity index 86% rename from src/client/gui/screens/crafting/WorkbenchScreen.h rename to src/client/gui/screens/crafting/WorkbenchScreen.hpp index 260f960..31d52da 100755 --- a/src/client/gui/screens/crafting/WorkbenchScreen.h +++ b/src/client/gui/screens/crafting/WorkbenchScreen.hpp @@ -1,6 +1,6 @@ #pragma once -#include "PaneCraftingScreen.h" +#include "PaneCraftingScreen.hpp" class WorkbenchScreen: public PaneCraftingScreen { diff --git a/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp b/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp index d2a71a7..d3e05a3 100755 --- a/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp +++ b/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.cpp @@ -1,25 +1,25 @@ -#include "TouchIngameBlockSelectionScreen.h" -#include "../crafting/WorkbenchScreen.h" -#include "../../Screen.h" -#include "../../components/ImageButton.h" -#include "../../components/InventoryPane.h" -#include -#include "../../../renderer/TileRenderer.h" -#include "../../../player/LocalPlayer.h" -#include "../../../renderer/gles.h" -#include "../../../renderer/entity/ItemRenderer.h" -#include "../../../renderer/Tesselator.h" -#include "../../../renderer/Textures.h" -#include "../../../Minecraft.h" -#include "../../../sound/SoundEngine.h" -#include "../../../../world/entity/player/Inventory.h" -#include "../../../../platform/input/Mouse.h" -#include "../../../../util/Mth.h" -#include "../../../../world/item/ItemInstance.h" -#include "../../../../world/entity/player/Player.h" -#include "../../../../world/item/crafting/Recipe.h" -#include "../../../player/input/touchscreen/TouchAreaModel.h" -#include "../ArmorScreen.h" +#include "TouchIngameBlockSelectionScreen.hpp" +#include "client/gui/screens/crafting/WorkbenchScreen.hpp" +#include "client/gui/Screen.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "client/gui/components/InventoryPane.hpp" +#include +#include "client/renderer/TileRenderer.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/renderer/gles.hpp" +#include "client/renderer/entity/ItemRenderer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "client/Minecraft.hpp" +#include "client/sound/SoundEngine.hpp" +#include "world/entity/player/Inventory.hpp" +#include "platform/input/Mouse.hpp" +#include "util/Mth.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/crafting/Recipe.hpp" +#include "client/player/input/touchscreen/TouchAreaModel.hpp" +#include "client/gui/screens/ArmorScreen.hpp" namespace Touch { diff --git a/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.h b/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.hpp similarity index 79% rename from src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.h rename to src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.hpp index 542ec93..fd8eccc 100755 --- a/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.h +++ b/src/client/gui/screens/touch/TouchIngameBlockSelectionScreen.hpp @@ -1,13 +1,13 @@ #pragma once -#include "../../Screen.h" -#include "../../components/InventoryPane.h" -#include "../../components/Button.h" -#include "../../components/ScrollingPane.h" -#include "../../components/ItemPane.h" -#include "../../TweenData.h" -#include "../../../player/input/touchscreen/TouchAreaModel.h" -#include "../../../../AppPlatform.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/InventoryPane.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/ScrollingPane.hpp" +#include "client/gui/components/ItemPane.hpp" +#include "client/gui/TweenData.hpp" +#include "client/player/input/touchscreen/TouchAreaModel.hpp" +#include "AppPlatform.hpp" namespace Touch { diff --git a/src/client/gui/screens/touch/TouchJoinGameScreen.cpp b/src/client/gui/screens/touch/TouchJoinGameScreen.cpp index f8ad00a..608a8bf 100755 --- a/src/client/gui/screens/touch/TouchJoinGameScreen.cpp +++ b/src/client/gui/screens/touch/TouchJoinGameScreen.cpp @@ -1,243 +1,243 @@ -#include "TouchJoinGameScreen.h" -#include "../StartMenuScreen.h" -#include "../ProgressScreen.h" -#include "../../Font.h" -#include "../../../Minecraft.h" -#include "../../../renderer/Textures.h" - -namespace Touch { - -// -// Games list -// - -void AvailableGamesList::selectStart( int item) { - startSelected = item; -} - -void AvailableGamesList::selectCancel() { - startSelected = -1; -} - -void AvailableGamesList::selectItem( int item, bool doubleClick ) { - LOGI("selected an item! %d\n", item); - selectedItem = item; -} - -void AvailableGamesList::renderItem( int i, int x, int y, int h, Tesselator& t ) -{ - if (startSelected == i && Multitouch::getFirstActivePointerIdEx() >= 0) { - fill((int)x0, y, (int)x1, y+h, 0x809E684F); - } - - //static int colors[2] = {0xffffb0, 0xcccc90}; - const PingedCompatibleServer& s = copiedServerList[i]; - unsigned int color = s.isSpecial? 0x6090a0 : 0xffffb0; - unsigned int color2 = 0xffffa0;//colors[i&1]; - - int xx1 = (int)x0 + 24; - int xx2 = xx1; - - if (s.isSpecial) { - xx1 += 50; - - glEnable2(GL_TEXTURE_2D); - glColor4f2(1,1,1,1); - glEnable2(GL_BLEND); - minecraft->textures->loadAndBindTexture("gui/badge/minecon140.png"); - blit(xx2, y + 6, 0, 0, 37, 8, 140, 240); - } - - drawString(minecraft->font, s.name.C_String(), xx1, y + 4 + 2, color); - drawString(minecraft->font, s.address.ToString(false), xx2, y + 18, color2); - - /* - drawString(minecraft->font, copiedServerList[i].name.C_String(), (int)x0 + 24, y + 4, color); - drawString(minecraft->font, copiedServerList[i].address.ToString(false), (int)x0 + 24, y + 18, color); - */ -} - - -// -// Join Game screen -// -JoinGameScreen::JoinGameScreen() -: bJoin( 2, "Join Game"), - bBack( 3, "Back"), - bJoinByIp(4, "Join By IP"), - bHeader(0, ""), - gamesList(NULL) -{ - bJoin.active = false; - //gamesList->yInertia = 0.5f; -} - -JoinGameScreen::~JoinGameScreen() -{ - delete gamesList; -} - -void JoinGameScreen::init() -{ - //buttons.push_back(&bJoin); - buttons.push_back(&bBack); - buttons.push_back(&bJoinByIp); - buttons.push_back(&bHeader); - - minecraft->raknetInstance->clearServerList(); - gamesList = new AvailableGamesList(minecraft, width, height); - -#ifdef ANDROID - //tabButtons.push_back(&bJoin); - tabButtons.push_back(&bBack); - tabButtons.push_back(&bJoinByIp); -#endif -} - -void JoinGameScreen::setupPositions() { - //int yBase = height - 26; - - //#ifdef ANDROID - bJoin.y = 0; - bBack.y = 0; - bJoinByIp.y = 0; - bHeader.y = 0; - //#endif - - // Center buttons - //bJoin.x = width / 2 - 4 - bJoin.w; - bBack.x = 0;//width / 2 + 4; - bJoinByIp.x = width - bJoinByIp.width;; - bHeader.x = bJoinByIp.width; - bHeader.width = width - (bBack.width + bJoinByIp.width); -} - -void JoinGameScreen::buttonClicked(Button* button) -{ - if (button->id == bJoin.id) - { - if (isIndexValid(gamesList->selectedItem)) - { - PingedCompatibleServer selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; - minecraft->joinMultiplayer(selectedServer); - { - bJoin.active = false; - bBack.active = false; - minecraft->setScreen(new ProgressScreen()); - } - } - //minecraft->locateMultiplayer(); - //minecraft->setScreen(new JoinGameScreen()); - } - if(button->id == bJoinByIp.id) { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_JOINBYIP); - } - - if (button->id == bBack.id) - { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } -} - -bool JoinGameScreen::handleBackEvent(bool isDown) -{ - if (!isDown) - { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } - return true; -} - - -bool JoinGameScreen::isIndexValid( int index ) -{ - return gamesList && index >= 0 && index < gamesList->getNumberOfItems(); -} - -void JoinGameScreen::tick() -{ - if (isIndexValid(gamesList->selectedItem)) { - buttonClicked(&bJoin); - return; - } - - //gamesList->tick(); - - const ServerList& orgServerList = minecraft->raknetInstance->getServerList(); - ServerList serverList; - for (unsigned int i = 0; i < orgServerList.size(); ++i) - if (orgServerList[i].name.GetLength() > 0) - serverList.push_back(orgServerList[i]); - - if (serverList.size() != gamesList->copiedServerList.size()) - { - // copy the currently selected item - PingedCompatibleServer selectedServer; - bool hasSelection = false; - if (isIndexValid(gamesList->selectedItem)) - { - selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; - hasSelection = true; - } - - gamesList->copiedServerList = serverList; - gamesList->selectItem(-1, false); - - // re-select previous item if it still exists - if (hasSelection) - { - for (unsigned int i = 0; i < gamesList->copiedServerList.size(); i++) - { - if (gamesList->copiedServerList[i].address == selectedServer.address) - { - gamesList->selectItem(i, false); - break; - } - } - } - } else { - for (int i = (int)gamesList->copiedServerList.size()-1; i >= 0 ; --i) { - for (int j = 0; j < (int) serverList.size(); ++j) - if (serverList[j].address == gamesList->copiedServerList[i].address) - gamesList->copiedServerList[i].name = serverList[j].name; - } - } - - bJoin.active = isIndexValid(gamesList->selectedItem); -} - -void JoinGameScreen::render( int xm, int ym, float a ) -{ - bool hasNetwork = minecraft->platform()->isNetworkEnabled(true); -#ifdef WIN32 - hasNetwork = hasNetwork && !GetAsyncKeyState(VK_TAB); -#endif - - renderBackground(); - if (hasNetwork) gamesList->render(xm, ym, a); - else gamesList->renderDirtBackground(); - Screen::render(xm, ym, a); - - const int baseX = bHeader.x + bHeader.width / 2; - - if (hasNetwork) { - std::string s = "Scanning for WiFi Games..."; - drawCenteredString(minecraft->font, s, baseX, 8, 0xffffffff); - - const int textWidth = minecraft->font->width(s); - const int spinnerX = baseX + textWidth / 2 + 6; - - static const char* spinnerTexts[] = {"-", "\\", "|", "/"}; - int n = ((int)(5.5f * getTimeS()) % 4); - drawCenteredString(minecraft->font, spinnerTexts[n], spinnerX, 8, 0xffffffff); - } else { - drawCenteredString(minecraft->font, "WiFi is disabled", baseX, 8, 0xffffffff); - } -} - -bool JoinGameScreen::isInGameScreen() { return false; } - -}; +#include "TouchJoinGameScreen.hpp" +#include "client/gui/screens/StartMenuScreen.hpp" +#include "client/gui/screens/ProgressScreen.hpp" +#include "client/gui/Font.hpp" +#include "client/Minecraft.hpp" +#include "client/renderer/Textures.hpp" + +namespace Touch { + +// +// Games list +// + +void AvailableGamesList::selectStart( int item) { + startSelected = item; +} + +void AvailableGamesList::selectCancel() { + startSelected = -1; +} + +void AvailableGamesList::selectItem( int item, bool doubleClick ) { + LOGI("selected an item! %d\n", item); + selectedItem = item; +} + +void AvailableGamesList::renderItem( int i, int x, int y, int h, Tesselator& t ) +{ + if (startSelected == i && Multitouch::getFirstActivePointerIdEx() >= 0) { + fill((int)x0, y, (int)x1, y+h, 0x809E684F); + } + + //static int colors[2] = {0xffffb0, 0xcccc90}; + const PingedCompatibleServer& s = copiedServerList[i]; + unsigned int color = s.isSpecial? 0x6090a0 : 0xffffb0; + unsigned int color2 = 0xffffa0;//colors[i&1]; + + int xx1 = (int)x0 + 24; + int xx2 = xx1; + + if (s.isSpecial) { + xx1 += 50; + + glEnable2(GL_TEXTURE_2D); + glColor4f2(1,1,1,1); + glEnable2(GL_BLEND); + minecraft->textures->loadAndBindTexture("gui/badge/minecon140.png"); + blit(xx2, y + 6, 0, 0, 37, 8, 140, 240); + } + + drawString(minecraft->font, s.name.C_String(), xx1, y + 4 + 2, color); + drawString(minecraft->font, s.address.ToString(false), xx2, y + 18, color2); + + /* + drawString(minecraft->font, copiedServerList[i].name.C_String(), (int)x0 + 24, y + 4, color); + drawString(minecraft->font, copiedServerList[i].address.ToString(false), (int)x0 + 24, y + 18, color); + */ +} + + +// +// Join Game screen +// +JoinGameScreen::JoinGameScreen() +: bJoin( 2, "Join Game"), + bBack( 3, "Back"), + bJoinByIp(4, "Join By IP"), + bHeader(0, ""), + gamesList(NULL) +{ + bJoin.active = false; + //gamesList->yInertia = 0.5f; +} + +JoinGameScreen::~JoinGameScreen() +{ + delete gamesList; +} + +void JoinGameScreen::init() +{ + //buttons.push_back(&bJoin); + buttons.push_back(&bBack); + buttons.push_back(&bJoinByIp); + buttons.push_back(&bHeader); + + minecraft->raknetInstance->clearServerList(); + gamesList = new AvailableGamesList(minecraft, width, height); + +#ifdef ANDROID + //tabButtons.push_back(&bJoin); + tabButtons.push_back(&bBack); + tabButtons.push_back(&bJoinByIp); +#endif +} + +void JoinGameScreen::setupPositions() { + //int yBase = height - 26; + + //#ifdef ANDROID + bJoin.y = 0; + bBack.y = 0; + bJoinByIp.y = 0; + bHeader.y = 0; + //#endif + + // Center buttons + //bJoin.x = width / 2 - 4 - bJoin.w; + bBack.x = 0;//width / 2 + 4; + bJoinByIp.x = width - bJoinByIp.width;; + bHeader.x = bJoinByIp.width; + bHeader.width = width - (bBack.width + bJoinByIp.width); +} + +void JoinGameScreen::buttonClicked(Button* button) +{ + if (button->id == bJoin.id) + { + if (isIndexValid(gamesList->selectedItem)) + { + PingedCompatibleServer selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; + minecraft->joinMultiplayer(selectedServer); + { + bJoin.active = false; + bBack.active = false; + minecraft->setScreen(new ProgressScreen()); + } + } + //minecraft->locateMultiplayer(); + //minecraft->setScreen(new JoinGameScreen()); + } + if(button->id == bJoinByIp.id) { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_JOINBYIP); + } + + if (button->id == bBack.id) + { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } +} + +bool JoinGameScreen::handleBackEvent(bool isDown) +{ + if (!isDown) + { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } + return true; +} + + +bool JoinGameScreen::isIndexValid( int index ) +{ + return gamesList && index >= 0 && index < gamesList->getNumberOfItems(); +} + +void JoinGameScreen::tick() +{ + if (isIndexValid(gamesList->selectedItem)) { + buttonClicked(&bJoin); + return; + } + + //gamesList->tick(); + + const ServerList& orgServerList = minecraft->raknetInstance->getServerList(); + ServerList serverList; + for (unsigned int i = 0; i < orgServerList.size(); ++i) + if (orgServerList[i].name.GetLength() > 0) + serverList.push_back(orgServerList[i]); + + if (serverList.size() != gamesList->copiedServerList.size()) + { + // copy the currently selected item + PingedCompatibleServer selectedServer; + bool hasSelection = false; + if (isIndexValid(gamesList->selectedItem)) + { + selectedServer = gamesList->copiedServerList[gamesList->selectedItem]; + hasSelection = true; + } + + gamesList->copiedServerList = serverList; + gamesList->selectItem(-1, false); + + // re-select previous item if it still exists + if (hasSelection) + { + for (unsigned int i = 0; i < gamesList->copiedServerList.size(); i++) + { + if (gamesList->copiedServerList[i].address == selectedServer.address) + { + gamesList->selectItem(i, false); + break; + } + } + } + } else { + for (int i = (int)gamesList->copiedServerList.size()-1; i >= 0 ; --i) { + for (int j = 0; j < (int) serverList.size(); ++j) + if (serverList[j].address == gamesList->copiedServerList[i].address) + gamesList->copiedServerList[i].name = serverList[j].name; + } + } + + bJoin.active = isIndexValid(gamesList->selectedItem); +} + +void JoinGameScreen::render( int xm, int ym, float a ) +{ + bool hasNetwork = minecraft->platform()->isNetworkEnabled(true); +#ifdef WIN32 + hasNetwork = hasNetwork && !GetAsyncKeyState(VK_TAB); +#endif + + renderBackground(); + if (hasNetwork) gamesList->render(xm, ym, a); + else gamesList->renderDirtBackground(); + Screen::render(xm, ym, a); + + const int baseX = bHeader.x + bHeader.width / 2; + + if (hasNetwork) { + std::string s = "Scanning for WiFi Games..."; + drawCenteredString(minecraft->font, s, baseX, 8, 0xffffffff); + + const int textWidth = minecraft->font->width(s); + const int spinnerX = baseX + textWidth / 2 + 6; + + static const char* spinnerTexts[] = {"-", "\\", "|", "/"}; + int n = ((int)(5.5f * getTimeS()) % 4); + drawCenteredString(minecraft->font, spinnerTexts[n], spinnerX, 8, 0xffffffff); + } else { + drawCenteredString(minecraft->font, "WiFi is disabled", baseX, 8, 0xffffffff); + } +} + +bool JoinGameScreen::isInGameScreen() { return false; } + +}; diff --git a/src/client/gui/screens/touch/TouchJoinGameScreen.h b/src/client/gui/screens/touch/TouchJoinGameScreen.hpp similarity index 83% rename from src/client/gui/screens/touch/TouchJoinGameScreen.h rename to src/client/gui/screens/touch/TouchJoinGameScreen.hpp index 6e45a2c..3496fc3 100755 --- a/src/client/gui/screens/touch/TouchJoinGameScreen.h +++ b/src/client/gui/screens/touch/TouchJoinGameScreen.hpp @@ -1,11 +1,11 @@ #pragma once -#include "../../Screen.h" -#include "../../components/Button.h" -#include "../../components/RolledSelectionListV.h" -#include "../../../Minecraft.h" -#include "../../../../platform/input/Multitouch.h" -#include "../../../../network/RakNetInstance.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/RolledSelectionListV.hpp" +#include "client/Minecraft.hpp" +#include "platform/input/Multitouch.hpp" +#include "network/RakNetInstance.hpp" namespace Touch { diff --git a/src/client/gui/screens/touch/TouchSelectWorldScreen.cpp b/src/client/gui/screens/touch/TouchSelectWorldScreen.cpp index 0ed793d..1518974 100755 --- a/src/client/gui/screens/touch/TouchSelectWorldScreen.cpp +++ b/src/client/gui/screens/touch/TouchSelectWorldScreen.cpp @@ -1,605 +1,605 @@ -#include "TouchSelectWorldScreen.h" -#include "../StartMenuScreen.h" -#include "../ProgressScreen.h" -#include "../DialogDefinitions.h" -#include "../../components/ImageButton.h" //weird! -#include "../../../renderer/Textures.h" -#include "../../../renderer/Tesselator.h" -#include "../../../../world/level/LevelSettings.h" -#include "../../../../AppPlatform.h" -#include "../../../../util/StringUtils.h" -#include "../../../../util/Mth.h" -#include "../../../../platform/input/Mouse.h" -#include "../../../../Performance.h" - -#include -#include -#include "../SimpleChooseLevelScreen.h" - -namespace Touch { - -// -// World Selection List -// -TouchWorldSelectionList::TouchWorldSelectionList( Minecraft* minecraft, int width, int height ) -: _height(height), - hasPickedLevel(false), - pickedIndex(-1), - currentTick(0), - stoppedTick(-1), - mode(0), - _newWorldSelected(false), - RolledSelectionListH(minecraft, width, height, 0, width, 24, height-32, 120) -{ - _renderBottomBorder = false; - //setRenderSelection(false); -} - -int TouchWorldSelectionList::getNumberOfItems() { - return (int)levels.size() + 1; -} - -void TouchWorldSelectionList::selectItem( int item, bool doubleClick ) { - if (selectedItem < 0) - return; - - const int delta = item - selectedItem; - - if (delta == -1) - stepLeft(); - if (delta == +1) - stepRight(); - if (delta == 0 ) { - if (!hasPickedLevel) { - hasPickedLevel = true; - pickedIndex = item; - if (item < (int)levels.size()) - pickedLevel = levels[item]; - } - } -} - -bool TouchWorldSelectionList::isSelectedItem( int item ) { - return item == selectedItem; -} - -void TouchWorldSelectionList::selectStart(int item, int localX, int localY) { - if (selectedItem != (int) levels.size() || item != selectedItem) - return; - _newWorldSelected = true; -} - -void TouchWorldSelectionList::selectCancel() { - _newWorldSelected = false; -} - -void TouchWorldSelectionList::renderItem( int i, int x, int y, int h, Tesselator& t ) { - int centerx = x + itemWidth/2; - float a0 = Mth::Max(1.1f - std::abs( width / 2 - centerx ) * 0.0055f, 0.2f); - if (a0 > 1) a0 = 1; - int textColor = (int)(255.0f * a0) * 0x010101; - int textColor2 = (int)(140.0f * a0) * 0x010101; - const int TX = centerx - itemWidth / 2 + 5; - const int TY = y + 44; //@kindle-res:42 - - if (i < (int)levels.size()) { - // Draw the worlds - StringVector v = _descriptions[i]; - drawString(minecraft->font, v[0].c_str(), TX, TY + 0, textColor); - drawString(minecraft->font, v[1].c_str(), TX, TY + 10, textColor2); - drawString(minecraft->font, v[2].c_str(), TX, TY + 20, textColor2); - drawString(minecraft->font, v[3].c_str(), TX, TY + 30, textColor2); - - minecraft->textures->loadAndBindTexture(_imageNames[i]); - t.color(0.3f, 1.0f, 0.2f); - - //float x0 = (float)x; - //float x1 = (float)x + (float)itemWidth; - - const float IY = (float)y - 8; // @kindle-res: -3 - t.begin(); - t.color(textColor); - t.vertexUV((float)(centerx-32), IY, blitOffset, 0, 0.125f); - t.vertexUV((float)(centerx-32), IY + 48, blitOffset, 0, 0.875f); //@kindle-res: +44 - t.vertexUV((float)(centerx+32), IY + 48, blitOffset, 1, 0.875f); //@kindle-res: +44 - t.vertexUV((float)(centerx+32), IY, blitOffset, 1, 0.125f); - t.draw(); - } else { - // Draw the "Create new world" icon - drawCenteredString(minecraft->font, "Create new", centerx, TY + 12, textColor); - - minecraft->textures->loadAndBindTexture("gui/touchgui.png"); - - const bool selected = _newWorldSelected; - - const float W = 54.0f; - const float H = 54.0f; - const float IY = (float)y; - const float u0 = (168.0f ) / 256.0f; - const float u1 = (168.0f + W) / 256.0f; - float v0 = (32.0f ) / 256.0f; - float v1 = (32.0f + H) / 256.0f; - if (selected) { - v0 += H / 256.0f; - v1 += H / 256.0f; - } - - t.begin(); - t.color(textColor); - t.vertexUV((float)centerx - W*0.5f, IY, blitOffset, u0, v0); - t.vertexUV((float)centerx - W*0.5f, IY + H, blitOffset, u0, v1); - t.vertexUV((float)centerx + W*0.5f, IY + H, blitOffset, u1, v1); - t.vertexUV((float)centerx + W*0.5f, IY, blitOffset, u1, v0); - t.draw(); - } -} - -void TouchWorldSelectionList::stepLeft() { - if (selectedItem > 0) { - int xoffset = (int)(xo - ((float)(selectedItem * itemWidth) + ((float)(itemWidth-width)) * 0.5f)); - td.start = xo; - td.stop = xo - itemWidth - xoffset; - td.cur = 0; - td.dur = 8; - mode = 1; - tweenInited(); - } -} - -void TouchWorldSelectionList::stepRight() { - if (selectedItem >= 0 && selectedItem < getNumberOfItems()-1) { - int xoffset = (int)(xo - ((float)(selectedItem * itemWidth) + ((float)(itemWidth-width)) * 0.5f)); - td.start = xo; - td.stop = xo + itemWidth - xoffset; - td.cur = 0; - td.dur = 8; - mode = 1; - tweenInited(); - } -} - -void TouchWorldSelectionList::commit() { - for (unsigned int i = 0; i < levels.size(); ++i) { - LevelSummary& level = levels[i]; - - std::stringstream ss; - ss << level.name << "/preview.png"; - TextureId id = Textures::InvalidId;//minecraft->textures->loadTexture(ss.str(), false); - - if (id != Textures::InvalidId) { - _imageNames.push_back( ss.str() ); - } else { - _imageNames.push_back("gui/default_world.png"); - } - - StringVector lines; - lines.push_back(levels[i].name); - lines.push_back(minecraft->platform()->getDateString(levels[i].lastPlayed)); - lines.push_back(levels[i].id); - lines.push_back(LevelSettings::gameTypeToString(level.gameType)); - _descriptions.push_back(lines); - - selectedItem = 0; - } -} - -static float quadraticInOut(float t, float dur, float start, float stop) { - const float delta = stop - start; - const float T = (t / dur) * 2.0f; - if (T < 1) return 0.5f*delta*T*T + start; - return -0.5f*delta * ((T-1)*(T-3) - 1) + start; -} - -void TouchWorldSelectionList::tick() -{ - RolledSelectionListH::tick(); - - ++currentTick; - - if (Mouse::isButtonDown(MouseAction::ACTION_LEFT) || dragState == 0) - return; - - // Handle the tween (when in "mode 1") - selectedItem = -1; - if (mode == 1) { - if (++td.cur == td.dur) { - mode = 0; - xInertia = 0; - xoo = xo = td.stop; - selectedItem = getItemAtPosition(width/2, height/2); - } else { - tweenInited(); - } - return; - } - - // It's still going fast, let it run - float speed = Mth::abs(xInertia); - bool slowEnoughToBeBothered = speed < 5.0f; - if (!slowEnoughToBeBothered) { - xInertia = xInertia * .9f; - return; - } - - xInertia *= 0.8f; - - if (speed < 1 && dragState < 0) { - const int offsetx = (width-itemWidth) / 2; - const float pxo = xo + offsetx; - int index = getItemAtXPositionRaw((int)(pxo - 10*xInertia)); - int indexPos = index*itemWidth; - - // Pick closest - float diff = (float)indexPos - pxo; - if (diff < -itemWidth/2) { - diff += itemWidth; - index++; - //indexPos += itemWidth; - } - if (Mth::abs(diff) < 1 && speed < 0.1f) { - selectedItem = getItemAtPosition(width/2, height/2); - return; - } - - td.start = xo; - td.stop = xo + diff; - td.cur = 0; - td.dur = (float) Mth::Min(7, 1 + (int)(Mth::abs(diff) * 0.25f)); - mode = 1; - //LOGI("inited-t %d\n", dragState); - tweenInited(); - } -} - -float TouchWorldSelectionList::getPos( float alpha ) -{ - if (mode != 1) return RolledSelectionListH::getPos(alpha); - - float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); - float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); - return x0 + (x1-x0)*alpha; -} - -bool TouchWorldSelectionList::capXPosition() { - bool capped = RolledSelectionListH::capXPosition(); - if (capped) mode = 0; - return capped; -} - -void TouchWorldSelectionList::tweenInited() { - float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); - float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); - _xinertia = 0; - xInertia = x0-x1; // yes, it's all backwards and messed up.. -} - -// -// Select World Screen -// -SelectWorldScreen::SelectWorldScreen() -: bDelete (1, ""), - bCreate (2, "Create new"), - bBack (3, "Back"), - bHeader (0, "Select world"), - bWorldView(4, ""), - worldsList(NULL), - _hasStartedLevel(false) -{ - bDelete.active = false; - - // Delete button - ImageDef def; - def.name = "gui/touchgui.png"; - def.width = 34; - def.height = 26; - - def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); - bDelete.setImageDef(def, true); - - // Create new, and Back button -/* - def.src.y = 26; // @ 0, 26 - def.src.w = def.w = 66; // 66, 26 size - bBack.setImageDef(def, true); - bCreate.setImageDef(def, true); -*/ -} - -SelectWorldScreen::~SelectWorldScreen() -{ - delete worldsList; -} - -void SelectWorldScreen::init() -{ - worldsList = new TouchWorldSelectionList(minecraft, width, height); - loadLevelSource(); - worldsList->commit(); - - buttons.push_back(&bDelete); - buttons.push_back(&bCreate); - buttons.push_back(&bBack); - buttons.push_back(&bHeader); - - _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); - - tabButtons.push_back(&bWorldView); - tabButtons.push_back(&bDelete); - tabButtons.push_back(&bCreate); - tabButtons.push_back(&bBack); -} - -void SelectWorldScreen::setupPositions() { - //#ifdef ANDROID - bCreate.y = 0; - bBack.y = 0; - bHeader.y = 0; - bDelete.y = height - 30; - - // Center buttons - bDelete.x = (width - bDelete.width) / 2; - bCreate.x = width - bCreate.width;//width / 2 - bCreate.w / 2; - bBack.x = 0;//width / 2 + 4 + bCreate.w - bBack.w / 2; - bHeader.x = bBack.width; - bHeader.width = width - (bBack.width + bCreate.width); - bHeader.height = bCreate.height; -} - -void SelectWorldScreen::buttonClicked(Button* button) -{ - if (button->id == bCreate.id) { - if (!_hasStartedLevel) { - std::string name = getUniqueLevelName("World"); - minecraft->setScreen(new SimpleChooseLevelScreen(name)); - } - } - if (button->id == bDelete.id) { - if (isIndexValid(worldsList->selectedItem)) { - LevelSummary level = worldsList->levels[worldsList->selectedItem]; - LOGI("level: %s, %s\n", level.id.c_str(), level.name.c_str()); - minecraft->setScreen( new TouchDeleteWorldScreen(level) ); - } - } - if (button->id == bBack.id) { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } - if (button->id == bWorldView.id) { - // Try to "click" the item in the middle - worldsList->selectItem( worldsList->getItemAtPosition(width/2, height/2), false ); - } -} - -bool SelectWorldScreen::handleBackEvent(bool isDown) -{ - if (!isDown) - { - minecraft->cancelLocateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_STARTMENU); - } - return true; -} - -bool SelectWorldScreen::isIndexValid( int index ) -{ - return worldsList && index >= 0 && index < worldsList->getNumberOfItems() - 1; -} - -static char ILLEGAL_FILE_CHARACTERS[] = { - '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' -}; - -void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym) -{ - if (!worldsList) return; - if (dy == 0) return; - int num = worldsList->getNumberOfItems(); - int idx = worldsList->selectedItem; - if (dy > 0) { - if (idx > 0) { - idx--; - worldsList->stepLeft(); - } - } else { - if (idx < num - 1) { - idx++; - worldsList->stepRight(); - } - } - worldsList->selectedItem = idx; -} - -void SelectWorldScreen::tick() -{ -#if 0 - if (_state == _STATE_CREATEWORLD) { - #if defined(RPI) - std::string levelId = getUniqueLevelName("World"); - //int seed = Util::hashCode("/r/Minecraft"); - LevelSettings settings(getEpochTimeS(), GameType::Creative); - minecraft->selectLevel(levelId, levelId, settings); - minecraft->hostMultiplayer(); - minecraft->setScreen(new ProgressScreen()); - _hasStartedLevel = true; - #elif defined(PLATFORM_DESKTOP) - std::string name = getUniqueLevelName("World"); - minecraft->setScreen(new SimpleChooseLevelScreen(name)); - #else - int status = minecraft->platform()->getUserInputStatus(); - //LOGI("Status is: %d\n", status); - if (status > -1) { - if (status == 1) { - StringVector sv = minecraft->platform()->getUserInput(); - - // Read the level name. - // 1) Trim name 2) Remove all bad chars 3) Append '-' chars 'til the name is unique - std::string levelName = Util::stringTrim(sv[0]); - std::string levelId = levelName; - - for (int i = 0; i < sizeof(ILLEGAL_FILE_CHARACTERS) / sizeof(char); ++i) - levelId = Util::stringReplace(levelId, std::string(1, ILLEGAL_FILE_CHARACTERS[i]), ""); - if ((int)levelId.length() == 0) { - levelId = "no_name"; - } - levelId = getUniqueLevelName(levelId); - - // Read the seed - int seed = getEpochTimeS(); - if (sv.size() >= 2) { - std::string seedString = Util::stringTrim(sv[1]); - if (seedString.length() > 0) { - int tmpSeed; - // Try to read it as an integer - if (sscanf(seedString.c_str(), "%d", &tmpSeed) > 0) { - seed = tmpSeed; - } // Hash the "seed" - else { - seed = Util::hashCode(seedString); - } - } - } - // Read the game mode - bool isCreative = true; - if (sv.size() >= 3 && sv[2] == "survival") - isCreative = false; - - // Start a new level with the given name and seed - LOGI("Creating a level with id '%s', name '%s' and seed '%d'\n", levelId.c_str(), levelName.c_str(), seed); - LevelSettings settings(seed, isCreative? GameType::Creative : GameType::Survival); - minecraft->selectLevel(levelId, levelName, settings); - minecraft->hostMultiplayer(); - minecraft->setScreen(new ProgressScreen()); - _hasStartedLevel = true; - } - _state = _STATE_DEFAULT; - // Reset the world list - worldsList->hasPickedLevel = false; - worldsList->pickedIndex = -1; - } - #endif - - worldsList->hasPickedLevel = false; - return; - } -#endif - - worldsList->tick(); - - if (worldsList->hasPickedLevel) { - if (worldsList->pickedIndex == worldsList->levels.size()) { - worldsList->hasPickedLevel = false; - std::string name = getUniqueLevelName("World"); - minecraft->setScreen(new SimpleChooseLevelScreen(name)); - } else { - minecraft->selectLevel(worldsList->pickedLevel.id, worldsList->pickedLevel.name, LevelSettings::None()); - minecraft->hostMultiplayer(); - minecraft->setScreen(new ProgressScreen()); - _hasStartedLevel = true; - return; - } - } - - // copy the currently selected item - LevelSummary selectedWorld; - //bool hasSelection = false; - if (isIndexValid(worldsList->selectedItem)) - { - selectedWorld = worldsList->levels[worldsList->selectedItem]; - //hasSelection = true; - } - - bDelete.active = isIndexValid(worldsList->selectedItem); -} - -void SelectWorldScreen::render( int xm, int ym, float a ) -{ - //Performance::watches.get("sws-full").start(); - //Performance::watches.get("sws-renderbg").start(); - renderBackground(); - //Performance::watches.get("sws-renderbg").stop(); - //Performance::watches.get("sws-worlds").start(); - - worldsList->setComponentSelected(bWorldView.selected); - - if (_mouseHasBeenUp) - worldsList->render(xm, ym, a); - else { - worldsList->render(0, 0, a); - _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); - } - - //Performance::watches.get("sws-worlds").stop(); - //Performance::watches.get("sws-screen").start(); - Screen::render(xm, ym, a); - //Performance::watches.get("sws-screen").stop(); - - //minecraft->textures->loadAndBindTexture("gui/selectworld/trash.png"); - - //Performance::watches.get("sws-string").start(); - //Performance::watches.get("sws-string").stop(); - - //Performance::watches.get("sws-full").stop(); - //Performance::watches.printEvery(128); -} - -void SelectWorldScreen::loadLevelSource() -{ - LevelStorageSource* levelSource = minecraft->getLevelSource(); - levelSource->getLevelList(levels); - std::sort(levels.begin(), levels.end()); - - for (unsigned int i = 0; i < levels.size(); ++i) { - if (levels[i].id != LevelStorageSource::TempLevelId) - worldsList->levels.push_back( levels[i] ); - } -} - - -std::string SelectWorldScreen::getUniqueLevelName( const std::string& level ) -{ - std::set Set; - for (unsigned int i = 0; i < levels.size(); ++i) - Set.insert(levels[i].id); - - std::string s = level; - while ( Set.find(s) != Set.end() ) - s += "-"; - return s; -} - -bool SelectWorldScreen::isInGameScreen() { return true; } - -void SelectWorldScreen::keyPressed( int eventKey ) -{ - if (bWorldView.selected) { - if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_LEFT)) - worldsList->stepLeft(); - if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_RIGHT)) - worldsList->stepRight(); - } - - Screen::keyPressed(eventKey); -} - -// -// Delete World Screen -// -TouchDeleteWorldScreen::TouchDeleteWorldScreen(const LevelSummary& level) -: ConfirmScreen(NULL, "Are you sure you want to delete this world?", - "'" + level.name + "' will be lost forever!", - "Delete", "Cancel", 0), - _level(level) -{ - tabButtonIndex = 1; -} - -void TouchDeleteWorldScreen::postResult( bool isOk ) -{ - if (isOk) { - LevelStorageSource* storageSource = minecraft->getLevelSource(); - storageSource->deleteLevel(_level.id); - } - minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); -} - -}; +#include "TouchSelectWorldScreen.hpp" +#include "client/gui/screens/StartMenuScreen.hpp" +#include "client/gui/screens/ProgressScreen.hpp" +#include "client/gui/screens/DialogDefinitions.hpp" +#include "client/gui/components/ImageButton.hpp" //weird! +#include "client/renderer/Textures.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/level/LevelSettings.hpp" +#include "AppPlatform.hpp" +#include "util/StringUtils.hpp" +#include "util/Mth.hpp" +#include "platform/input/Mouse.hpp" +#include "Performance.hpp" + +#include +#include +#include "client/gui/screens/SimpleChooseLevelScreen.hpp" + +namespace Touch { + +// +// World Selection List +// +TouchWorldSelectionList::TouchWorldSelectionList( Minecraft* minecraft, int width, int height ) +: _height(height), + hasPickedLevel(false), + pickedIndex(-1), + currentTick(0), + stoppedTick(-1), + mode(0), + _newWorldSelected(false), + RolledSelectionListH(minecraft, width, height, 0, width, 24, height-32, 120) +{ + _renderBottomBorder = false; + //setRenderSelection(false); +} + +int TouchWorldSelectionList::getNumberOfItems() { + return (int)levels.size() + 1; +} + +void TouchWorldSelectionList::selectItem( int item, bool doubleClick ) { + if (selectedItem < 0) + return; + + const int delta = item - selectedItem; + + if (delta == -1) + stepLeft(); + if (delta == +1) + stepRight(); + if (delta == 0 ) { + if (!hasPickedLevel) { + hasPickedLevel = true; + pickedIndex = item; + if (item < (int)levels.size()) + pickedLevel = levels[item]; + } + } +} + +bool TouchWorldSelectionList::isSelectedItem( int item ) { + return item == selectedItem; +} + +void TouchWorldSelectionList::selectStart(int item, int localX, int localY) { + if (selectedItem != (int) levels.size() || item != selectedItem) + return; + _newWorldSelected = true; +} + +void TouchWorldSelectionList::selectCancel() { + _newWorldSelected = false; +} + +void TouchWorldSelectionList::renderItem( int i, int x, int y, int h, Tesselator& t ) { + int centerx = x + itemWidth/2; + float a0 = Mth::Max(1.1f - std::abs( width / 2 - centerx ) * 0.0055f, 0.2f); + if (a0 > 1) a0 = 1; + int textColor = (int)(255.0f * a0) * 0x010101; + int textColor2 = (int)(140.0f * a0) * 0x010101; + const int TX = centerx - itemWidth / 2 + 5; + const int TY = y + 44; //@kindle-res:42 + + if (i < (int)levels.size()) { + // Draw the worlds + StringVector v = _descriptions[i]; + drawString(minecraft->font, v[0].c_str(), TX, TY + 0, textColor); + drawString(minecraft->font, v[1].c_str(), TX, TY + 10, textColor2); + drawString(minecraft->font, v[2].c_str(), TX, TY + 20, textColor2); + drawString(minecraft->font, v[3].c_str(), TX, TY + 30, textColor2); + + minecraft->textures->loadAndBindTexture(_imageNames[i]); + t.color(0.3f, 1.0f, 0.2f); + + //float x0 = (float)x; + //float x1 = (float)x + (float)itemWidth; + + const float IY = (float)y - 8; // @kindle-res: -3 + t.begin(); + t.color(textColor); + t.vertexUV((float)(centerx-32), IY, blitOffset, 0, 0.125f); + t.vertexUV((float)(centerx-32), IY + 48, blitOffset, 0, 0.875f); //@kindle-res: +44 + t.vertexUV((float)(centerx+32), IY + 48, blitOffset, 1, 0.875f); //@kindle-res: +44 + t.vertexUV((float)(centerx+32), IY, blitOffset, 1, 0.125f); + t.draw(); + } else { + // Draw the "Create new world" icon + drawCenteredString(minecraft->font, "Create new", centerx, TY + 12, textColor); + + minecraft->textures->loadAndBindTexture("gui/touchgui.png"); + + const bool selected = _newWorldSelected; + + const float W = 54.0f; + const float H = 54.0f; + const float IY = (float)y; + const float u0 = (168.0f ) / 256.0f; + const float u1 = (168.0f + W) / 256.0f; + float v0 = (32.0f ) / 256.0f; + float v1 = (32.0f + H) / 256.0f; + if (selected) { + v0 += H / 256.0f; + v1 += H / 256.0f; + } + + t.begin(); + t.color(textColor); + t.vertexUV((float)centerx - W*0.5f, IY, blitOffset, u0, v0); + t.vertexUV((float)centerx - W*0.5f, IY + H, blitOffset, u0, v1); + t.vertexUV((float)centerx + W*0.5f, IY + H, blitOffset, u1, v1); + t.vertexUV((float)centerx + W*0.5f, IY, blitOffset, u1, v0); + t.draw(); + } +} + +void TouchWorldSelectionList::stepLeft() { + if (selectedItem > 0) { + int xoffset = (int)(xo - ((float)(selectedItem * itemWidth) + ((float)(itemWidth-width)) * 0.5f)); + td.start = xo; + td.stop = xo - itemWidth - xoffset; + td.cur = 0; + td.dur = 8; + mode = 1; + tweenInited(); + } +} + +void TouchWorldSelectionList::stepRight() { + if (selectedItem >= 0 && selectedItem < getNumberOfItems()-1) { + int xoffset = (int)(xo - ((float)(selectedItem * itemWidth) + ((float)(itemWidth-width)) * 0.5f)); + td.start = xo; + td.stop = xo + itemWidth - xoffset; + td.cur = 0; + td.dur = 8; + mode = 1; + tweenInited(); + } +} + +void TouchWorldSelectionList::commit() { + for (unsigned int i = 0; i < levels.size(); ++i) { + LevelSummary& level = levels[i]; + + std::stringstream ss; + ss << level.name << "/preview.png"; + TextureId id = Textures::InvalidId;//minecraft->textures->loadTexture(ss.str(), false); + + if (id != Textures::InvalidId) { + _imageNames.push_back( ss.str() ); + } else { + _imageNames.push_back("gui/default_world.png"); + } + + StringVector lines; + lines.push_back(levels[i].name); + lines.push_back(minecraft->platform()->getDateString(levels[i].lastPlayed)); + lines.push_back(levels[i].id); + lines.push_back(LevelSettings::gameTypeToString(level.gameType)); + _descriptions.push_back(lines); + + selectedItem = 0; + } +} + +static float quadraticInOut(float t, float dur, float start, float stop) { + const float delta = stop - start; + const float T = (t / dur) * 2.0f; + if (T < 1) return 0.5f*delta*T*T + start; + return -0.5f*delta * ((T-1)*(T-3) - 1) + start; +} + +void TouchWorldSelectionList::tick() +{ + RolledSelectionListH::tick(); + + ++currentTick; + + if (Mouse::isButtonDown(MouseAction::ACTION_LEFT) || dragState == 0) + return; + + // Handle the tween (when in "mode 1") + selectedItem = -1; + if (mode == 1) { + if (++td.cur == td.dur) { + mode = 0; + xInertia = 0; + xoo = xo = td.stop; + selectedItem = getItemAtPosition(width/2, height/2); + } else { + tweenInited(); + } + return; + } + + // It's still going fast, let it run + float speed = Mth::abs(xInertia); + bool slowEnoughToBeBothered = speed < 5.0f; + if (!slowEnoughToBeBothered) { + xInertia = xInertia * .9f; + return; + } + + xInertia *= 0.8f; + + if (speed < 1 && dragState < 0) { + const int offsetx = (width-itemWidth) / 2; + const float pxo = xo + offsetx; + int index = getItemAtXPositionRaw((int)(pxo - 10*xInertia)); + int indexPos = index*itemWidth; + + // Pick closest + float diff = (float)indexPos - pxo; + if (diff < -itemWidth/2) { + diff += itemWidth; + index++; + //indexPos += itemWidth; + } + if (Mth::abs(diff) < 1 && speed < 0.1f) { + selectedItem = getItemAtPosition(width/2, height/2); + return; + } + + td.start = xo; + td.stop = xo + diff; + td.cur = 0; + td.dur = (float) Mth::Min(7, 1 + (int)(Mth::abs(diff) * 0.25f)); + mode = 1; + //LOGI("inited-t %d\n", dragState); + tweenInited(); + } +} + +float TouchWorldSelectionList::getPos( float alpha ) +{ + if (mode != 1) return RolledSelectionListH::getPos(alpha); + + float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); + float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); + return x0 + (x1-x0)*alpha; +} + +bool TouchWorldSelectionList::capXPosition() { + bool capped = RolledSelectionListH::capXPosition(); + if (capped) mode = 0; + return capped; +} + +void TouchWorldSelectionList::tweenInited() { + float x0 = quadraticInOut(td.cur, td.dur, td.start, td.stop); + float x1 = quadraticInOut(td.cur+1, td.dur, td.start, td.stop); + _xinertia = 0; + xInertia = x0-x1; // yes, it's all backwards and messed up.. +} + +// +// Select World Screen +// +SelectWorldScreen::SelectWorldScreen() +: bDelete (1, ""), + bCreate (2, "Create new"), + bBack (3, "Back"), + bHeader (0, "Select world"), + bWorldView(4, ""), + worldsList(NULL), + _hasStartedLevel(false) +{ + bDelete.active = false; + + // Delete button + ImageDef def; + def.name = "gui/touchgui.png"; + def.width = 34; + def.height = 26; + + def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); + bDelete.setImageDef(def, true); + + // Create new, and Back button +/* + def.src.y = 26; // @ 0, 26 + def.src.w = def.w = 66; // 66, 26 size + bBack.setImageDef(def, true); + bCreate.setImageDef(def, true); +*/ +} + +SelectWorldScreen::~SelectWorldScreen() +{ + delete worldsList; +} + +void SelectWorldScreen::init() +{ + worldsList = new TouchWorldSelectionList(minecraft, width, height); + loadLevelSource(); + worldsList->commit(); + + buttons.push_back(&bDelete); + buttons.push_back(&bCreate); + buttons.push_back(&bBack); + buttons.push_back(&bHeader); + + _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); + + tabButtons.push_back(&bWorldView); + tabButtons.push_back(&bDelete); + tabButtons.push_back(&bCreate); + tabButtons.push_back(&bBack); +} + +void SelectWorldScreen::setupPositions() { + //#ifdef ANDROID + bCreate.y = 0; + bBack.y = 0; + bHeader.y = 0; + bDelete.y = height - 30; + + // Center buttons + bDelete.x = (width - bDelete.width) / 2; + bCreate.x = width - bCreate.width;//width / 2 - bCreate.w / 2; + bBack.x = 0;//width / 2 + 4 + bCreate.w - bBack.w / 2; + bHeader.x = bBack.width; + bHeader.width = width - (bBack.width + bCreate.width); + bHeader.height = bCreate.height; +} + +void SelectWorldScreen::buttonClicked(Button* button) +{ + if (button->id == bCreate.id) { + if (!_hasStartedLevel) { + std::string name = getUniqueLevelName("World"); + minecraft->setScreen(new SimpleChooseLevelScreen(name)); + } + } + if (button->id == bDelete.id) { + if (isIndexValid(worldsList->selectedItem)) { + LevelSummary level = worldsList->levels[worldsList->selectedItem]; + LOGI("level: %s, %s\n", level.id.c_str(), level.name.c_str()); + minecraft->setScreen( new TouchDeleteWorldScreen(level) ); + } + } + if (button->id == bBack.id) { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } + if (button->id == bWorldView.id) { + // Try to "click" the item in the middle + worldsList->selectItem( worldsList->getItemAtPosition(width/2, height/2), false ); + } +} + +bool SelectWorldScreen::handleBackEvent(bool isDown) +{ + if (!isDown) + { + minecraft->cancelLocateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_STARTMENU); + } + return true; +} + +bool SelectWorldScreen::isIndexValid( int index ) +{ + return worldsList && index >= 0 && index < worldsList->getNumberOfItems() - 1; +} + +static char ILLEGAL_FILE_CHARACTERS[] = { + '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' +}; + +void SelectWorldScreen::mouseWheel(int dx, int dy, int xm, int ym) +{ + if (!worldsList) return; + if (dy == 0) return; + int num = worldsList->getNumberOfItems(); + int idx = worldsList->selectedItem; + if (dy > 0) { + if (idx > 0) { + idx--; + worldsList->stepLeft(); + } + } else { + if (idx < num - 1) { + idx++; + worldsList->stepRight(); + } + } + worldsList->selectedItem = idx; +} + +void SelectWorldScreen::tick() +{ +#if 0 + if (_state == _STATE_CREATEWORLD) { + #if defined(RPI) + std::string levelId = getUniqueLevelName("World"); + //int seed = Util::hashCode("/r/Minecraft"); + LevelSettings settings(getEpochTimeS(), GameType::Creative); + minecraft->selectLevel(levelId, levelId, settings); + minecraft->hostMultiplayer(); + minecraft->setScreen(new ProgressScreen()); + _hasStartedLevel = true; + #elif defined(PLATFORM_DESKTOP) + std::string name = getUniqueLevelName("World"); + minecraft->setScreen(new SimpleChooseLevelScreen(name)); + #else + int status = minecraft->platform()->getUserInputStatus(); + //LOGI("Status is: %d\n", status); + if (status > -1) { + if (status == 1) { + StringVector sv = minecraft->platform()->getUserInput(); + + // Read the level name. + // 1) Trim name 2) Remove all bad chars 3) Append '-' chars 'til the name is unique + std::string levelName = Util::stringTrim(sv[0]); + std::string levelId = levelName; + + for (int i = 0; i < sizeof(ILLEGAL_FILE_CHARACTERS) / sizeof(char); ++i) + levelId = Util::stringReplace(levelId, std::string(1, ILLEGAL_FILE_CHARACTERS[i]), ""); + if ((int)levelId.length() == 0) { + levelId = "no_name"; + } + levelId = getUniqueLevelName(levelId); + + // Read the seed + int seed = getEpochTimeS(); + if (sv.size() >= 2) { + std::string seedString = Util::stringTrim(sv[1]); + if (seedString.length() > 0) { + int tmpSeed; + // Try to read it as an integer + if (sscanf(seedString.c_str(), "%d", &tmpSeed) > 0) { + seed = tmpSeed; + } // Hash the "seed" + else { + seed = Util::hashCode(seedString); + } + } + } + // Read the game mode + bool isCreative = true; + if (sv.size() >= 3 && sv[2] == "survival") + isCreative = false; + + // Start a new level with the given name and seed + LOGI("Creating a level with id '%s', name '%s' and seed '%d'\n", levelId.c_str(), levelName.c_str(), seed); + LevelSettings settings(seed, isCreative? GameType::Creative : GameType::Survival); + minecraft->selectLevel(levelId, levelName, settings); + minecraft->hostMultiplayer(); + minecraft->setScreen(new ProgressScreen()); + _hasStartedLevel = true; + } + _state = _STATE_DEFAULT; + // Reset the world list + worldsList->hasPickedLevel = false; + worldsList->pickedIndex = -1; + } + #endif + + worldsList->hasPickedLevel = false; + return; + } +#endif + + worldsList->tick(); + + if (worldsList->hasPickedLevel) { + if (worldsList->pickedIndex == worldsList->levels.size()) { + worldsList->hasPickedLevel = false; + std::string name = getUniqueLevelName("World"); + minecraft->setScreen(new SimpleChooseLevelScreen(name)); + } else { + minecraft->selectLevel(worldsList->pickedLevel.id, worldsList->pickedLevel.name, LevelSettings::None()); + minecraft->hostMultiplayer(); + minecraft->setScreen(new ProgressScreen()); + _hasStartedLevel = true; + return; + } + } + + // copy the currently selected item + LevelSummary selectedWorld; + //bool hasSelection = false; + if (isIndexValid(worldsList->selectedItem)) + { + selectedWorld = worldsList->levels[worldsList->selectedItem]; + //hasSelection = true; + } + + bDelete.active = isIndexValid(worldsList->selectedItem); +} + +void SelectWorldScreen::render( int xm, int ym, float a ) +{ + //Performance::watches.get("sws-full").start(); + //Performance::watches.get("sws-renderbg").start(); + renderBackground(); + //Performance::watches.get("sws-renderbg").stop(); + //Performance::watches.get("sws-worlds").start(); + + worldsList->setComponentSelected(bWorldView.selected); + + if (_mouseHasBeenUp) + worldsList->render(xm, ym, a); + else { + worldsList->render(0, 0, a); + _mouseHasBeenUp = !Mouse::getButtonState(MouseAction::ACTION_LEFT); + } + + //Performance::watches.get("sws-worlds").stop(); + //Performance::watches.get("sws-screen").start(); + Screen::render(xm, ym, a); + //Performance::watches.get("sws-screen").stop(); + + //minecraft->textures->loadAndBindTexture("gui/selectworld/trash.png"); + + //Performance::watches.get("sws-string").start(); + //Performance::watches.get("sws-string").stop(); + + //Performance::watches.get("sws-full").stop(); + //Performance::watches.printEvery(128); +} + +void SelectWorldScreen::loadLevelSource() +{ + LevelStorageSource* levelSource = minecraft->getLevelSource(); + levelSource->getLevelList(levels); + std::sort(levels.begin(), levels.end()); + + for (unsigned int i = 0; i < levels.size(); ++i) { + if (levels[i].id != LevelStorageSource::TempLevelId) + worldsList->levels.push_back( levels[i] ); + } +} + + +std::string SelectWorldScreen::getUniqueLevelName( const std::string& level ) +{ + std::set Set; + for (unsigned int i = 0; i < levels.size(); ++i) + Set.insert(levels[i].id); + + std::string s = level; + while ( Set.find(s) != Set.end() ) + s += "-"; + return s; +} + +bool SelectWorldScreen::isInGameScreen() { return true; } + +void SelectWorldScreen::keyPressed( int eventKey ) +{ + if (bWorldView.selected) { + if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_LEFT)) + worldsList->stepLeft(); + if (eventKey == minecraft->options.getIntValue(OPTIONS_KEY_RIGHT)) + worldsList->stepRight(); + } + + Screen::keyPressed(eventKey); +} + +// +// Delete World Screen +// +TouchDeleteWorldScreen::TouchDeleteWorldScreen(const LevelSummary& level) +: ConfirmScreen(NULL, "Are you sure you want to delete this world?", + "'" + level.name + "' will be lost forever!", + "Delete", "Cancel", 0), + _level(level) +{ + tabButtonIndex = 1; +} + +void TouchDeleteWorldScreen::postResult( bool isOk ) +{ + if (isOk) { + LevelStorageSource* storageSource = minecraft->getLevelSource(); + storageSource->deleteLevel(_level.id); + } + minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); +} + +}; diff --git a/src/client/gui/screens/touch/TouchSelectWorldScreen.h b/src/client/gui/screens/touch/TouchSelectWorldScreen.hpp similarity index 87% rename from src/client/gui/screens/touch/TouchSelectWorldScreen.h rename to src/client/gui/screens/touch/TouchSelectWorldScreen.hpp index 6d922d8..1d4d16d 100755 --- a/src/client/gui/screens/touch/TouchSelectWorldScreen.h +++ b/src/client/gui/screens/touch/TouchSelectWorldScreen.hpp @@ -1,13 +1,13 @@ #pragma once -#include "../ConfirmScreen.h" -#include "../../Screen.h" -#include "../../TweenData.h" -#include "../../components/ImageButton.h" -#include "../../components/Button.h" -#include "../../components/RolledSelectionListH.h" -#include "../../../Minecraft.h" -#include "../../../../world/level/storage/LevelStorageSource.h" +#include "client/gui/screens/ConfirmScreen.hpp" +#include "client/gui/Screen.hpp" +#include "client/gui/TweenData.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "client/gui/components/Button.hpp" +#include "client/gui/components/RolledSelectionListH.hpp" +#include "client/Minecraft.hpp" +#include "world/level/storage/LevelStorageSource.hpp" namespace Touch { diff --git a/src/client/gui/screens/touch/TouchStartMenuScreen.cpp b/src/client/gui/screens/touch/TouchStartMenuScreen.cpp index c80300e..3dcc832 100755 --- a/src/client/gui/screens/touch/TouchStartMenuScreen.cpp +++ b/src/client/gui/screens/touch/TouchStartMenuScreen.cpp @@ -1,230 +1,230 @@ -#include "TouchStartMenuScreen.h" -#include "../ProgressScreen.h" -#include "../OptionsScreen.h" -#include "../PauseScreen.h" - -#include "../../Font.h" -#include "../../components/ScrolledSelectionList.h" -#include "../../components/GuiElement.h" - -#include "../../../Minecraft.h" -#include "../../../renderer/Tesselator.h" -#include "../../../renderer/Textures.h" -#include "../../../renderer/TextureData.h" -#include "../../../../SharedConstants.h" -#include "../../../../AppPlatform.h" -#include "../../../../LicenseCodes.h" -#include "../../../../util/Mth.h" - -#include "../DialogDefinitions.h" -#include "../SimpleChooseLevelScreen.h" - -namespace Touch { - -// -// Start menu screen implementation -// - -// Some kind of default settings, might be overridden in ::init -StartMenuScreen::StartMenuScreen() -: bHost( 2, "Start Game"), - bJoin( 3, "Join Game"), - bOptions( 4, "Options"), - bQuit( 5, "") -{ - ImageDef def; - bJoin.width = 75; - def.width = def.height = (float) bJoin.width; - - def.setSrc(IntRectangle(0, 26, (int)def.width, (int)def.width)); - def.name = "gui/touchgui.png"; - IntRectangle& defSrc = *def.getSrc(); - - bOptions.setImageDef(def, true); - - defSrc.y += defSrc.h; - bHost.setImageDef(def, true); - - defSrc.y += defSrc.h; - bJoin.setImageDef(def, true); -} - -StartMenuScreen::~StartMenuScreen() -{ -} - -void StartMenuScreen::init() -{ - buttons.push_back(&bHost); - buttons.push_back(&bJoin); - buttons.push_back(&bOptions); - - // add quit icon (same look as options header) - { - ImageDef def; - def.name = "gui/touchgui.png"; - def.width = 34; - def.height = 26; - def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); - bQuit.setImageDef(def, true); - bQuit.scaleWhenPressed = false; - buttons.push_back(&bQuit); - } - - tabButtons.push_back(&bHost); - tabButtons.push_back(&bJoin); - tabButtons.push_back(&bOptions); - - #ifdef DEMO_MODE - buttons.push_back(&bBuy); - tabButtons.push_back(&bBuy); - #endif - - copyright = "\xffMojang AB";//. Do not distribute!"; - - // always show base version string - std::string versionString = Common::getGameVersionString(); - - std::string _username = minecraft->options.getStringValue(OPTIONS_USERNAME); - if (_username.empty()) _username = "unknown"; - - username = "Username: " + _username; - - #ifdef DEMO_MODE - #ifdef __APPLE__ - version = versionString + " (Lite)"; - #else - version = versionString + " (Demo)"; - #endif - #else - version = versionString; - #endif - - #ifdef APPLE_DEMO_PROMOTION - version = versionString + " (Demo)"; - #endif - - bJoin.active = bHost.active = bOptions.active = true; -} - -void StartMenuScreen::setupPositions() { - int yBase = 2 + height / 3; - int buttonWidth = bHost.width; - float spacing = (width - (3.0f * buttonWidth)) / 4; - - //#ifdef ANDROID - bHost.y = yBase; - bJoin.y = yBase; - bOptions.y = yBase; - //#endif - - // Center buttons - bJoin.x = 0*buttonWidth + (int)(1*spacing); - bHost.x = 1*buttonWidth + (int)(2*spacing); - bOptions.x = 2*buttonWidth + (int)(3*spacing); - - // quit icon top-right (use size assigned in init) - bQuit.x = width - bQuit.width; - bQuit.y = 0; - - copyrightPosX = width - minecraft->font->width(copyright) - 1; - versionPosX = (width - minecraft->font->width(version)) / 2;// - minecraft->font->width(version) - 2; -} - -void StartMenuScreen::buttonClicked(::Button* button) { - - if (button->id == bHost.id) - { - #if defined(DEMO_MODE) || defined(APPLE_DEMO_PROMOTION) - minecraft->setScreen( new SimpleChooseLevelScreen("_DemoLevel") ); - #else - minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); - #endif - } - if (button->id == bJoin.id) - { - #ifdef APPLE_DEMO_PROMOTION - minecraft->platform()->createUserInput(DialogDefinitions::DIALOG_DEMO_FEATURE_DISABLED); - #else - minecraft->locateMultiplayer(); - minecraft->screenChooser.setScreen(SCREEN_JOINGAME); - #endif - } - if (button->id == bOptions.id) - { - minecraft->setScreen(new OptionsScreen()); - } - if (button == &bQuit) - { - minecraft->quit(); - } -} - -bool StartMenuScreen::isInGameScreen() { return false; } - -void StartMenuScreen::render( int xm, int ym, float a ) -{ - renderBackground(); - - // Show current username in the top-left corner - drawString(font, username, 2, 2, 0xffffffff); - - glEnable2(GL_BLEND); - -#if defined(RPI) - TextureId id = minecraft->textures->loadTexture("gui/pi_title.png"); -#else - TextureId id = minecraft->textures->loadTexture("gui/title.png"); -#endif - const TextureData* data = minecraft->textures->getTemporaryTextureData(id); - - if (data) { - minecraft->textures->bind(id); - - const float x = (float)width / 2; - const float y = 4; - const float wh = 0.5f * Mth::Min((float)width/2.0f, (float)data->w / 2); - const float scale = 2.0f * wh / (float)data->w; - const float h = scale * (float)data->h; - - // Render title text - Tesselator& t = Tesselator::instance; - glColor4f2(1, 1, 1, 1); - t.begin(); - t.vertexUV(x-wh, y+h, blitOffset, 0, 1); - t.vertexUV(x+wh, y+h, blitOffset, 1, 1); - t.vertexUV(x+wh, y+0, blitOffset, 1, 0); - t.vertexUV(x-wh, y+0, blitOffset, 0, 0); - t.draw(); - - drawString(font, version, versionPosX, (int)(y+h)+2, /*50,*/ 0xffcccccc);//0x666666); - drawString(font, copyright, copyrightPosX, height - 10, 0xffffff); - glColor4f2(1, 1, 1, 1); - if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/github.png"))) - blit(2, height - 10, 0, 0, 8, 8, 256, 256); - drawString(font, "Kolyah35/minecraft-pe-0.6.1", 12, height - 10, 0xffcccccc); - //patch->draw(t, 0, 20); - } - Screen::render(xm, ym, a); - glDisable2(GL_BLEND); -} - - -void StartMenuScreen::mouseClicked(int x, int y, int buttonNum) { - const int logoX = 2; - const int logoW = 8 + 2 + font->width("Kolyah35/minecraft-pe-0.6.1"); - const int logoY = height - 10; - const int logoH = 10; - if (x >= logoX && x <= logoX + logoW && y >= logoY && y <= logoY + logoH) - minecraft->platform()->openURL("https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1"); - else - Screen::mouseClicked(x, y, buttonNum); -} - -bool StartMenuScreen::handleBackEvent( bool isDown ) { - minecraft->quit(); - return true; -} - -} // namespace Touch - +#include "TouchStartMenuScreen.hpp" +#include "client/gui/screens/ProgressScreen.hpp" +#include "client/gui/screens/OptionsScreen.hpp" +#include "client/gui/screens/PauseScreen.hpp" + +#include "client/gui/Font.hpp" +#include "client/gui/components/ScrolledSelectionList.hpp" +#include "client/gui/components/GuiElement.hpp" + +#include "client/Minecraft.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "client/renderer/TextureData.hpp" +#include "SharedConstants.hpp" +#include "AppPlatform.hpp" +#include "LicenseCodes.hpp" +#include "util/Mth.hpp" + +#include "client/gui/screens/DialogDefinitions.hpp" +#include "client/gui/screens/SimpleChooseLevelScreen.hpp" + +namespace Touch { + +// +// Start menu screen implementation +// + +// Some kind of default settings, might be overridden in ::init +StartMenuScreen::StartMenuScreen() +: bHost( 2, "Start Game"), + bJoin( 3, "Join Game"), + bOptions( 4, "Options"), + bQuit( 5, "") +{ + ImageDef def; + bJoin.width = 75; + def.width = def.height = (float) bJoin.width; + + def.setSrc(IntRectangle(0, 26, (int)def.width, (int)def.width)); + def.name = "gui/touchgui.png"; + IntRectangle& defSrc = *def.getSrc(); + + bOptions.setImageDef(def, true); + + defSrc.y += defSrc.h; + bHost.setImageDef(def, true); + + defSrc.y += defSrc.h; + bJoin.setImageDef(def, true); +} + +StartMenuScreen::~StartMenuScreen() +{ +} + +void StartMenuScreen::init() +{ + buttons.push_back(&bHost); + buttons.push_back(&bJoin); + buttons.push_back(&bOptions); + + // add quit icon (same look as options header) + { + ImageDef def; + def.name = "gui/touchgui.png"; + def.width = 34; + def.height = 26; + def.setSrc(IntRectangle(150, 0, (int)def.width, (int)def.height)); + bQuit.setImageDef(def, true); + bQuit.scaleWhenPressed = false; + buttons.push_back(&bQuit); + } + + tabButtons.push_back(&bHost); + tabButtons.push_back(&bJoin); + tabButtons.push_back(&bOptions); + + #ifdef DEMO_MODE + buttons.push_back(&bBuy); + tabButtons.push_back(&bBuy); + #endif + + copyright = "\xffMojang AB";//. Do not distribute!"; + + // always show base version string + std::string versionString = Common::getGameVersionString(); + + std::string _username = minecraft->options.getStringValue(OPTIONS_USERNAME); + if (_username.empty()) _username = "unknown"; + + username = "Username: " + _username; + + #ifdef DEMO_MODE + #ifdef __APPLE__ + version = versionString + " (Lite)"; + #else + version = versionString + " (Demo)"; + #endif + #else + version = versionString; + #endif + + #ifdef APPLE_DEMO_PROMOTION + version = versionString + " (Demo)"; + #endif + + bJoin.active = bHost.active = bOptions.active = true; +} + +void StartMenuScreen::setupPositions() { + int yBase = 2 + height / 3; + int buttonWidth = bHost.width; + float spacing = (width - (3.0f * buttonWidth)) / 4; + + //#ifdef ANDROID + bHost.y = yBase; + bJoin.y = yBase; + bOptions.y = yBase; + //#endif + + // Center buttons + bJoin.x = 0*buttonWidth + (int)(1*spacing); + bHost.x = 1*buttonWidth + (int)(2*spacing); + bOptions.x = 2*buttonWidth + (int)(3*spacing); + + // quit icon top-right (use size assigned in init) + bQuit.x = width - bQuit.width; + bQuit.y = 0; + + copyrightPosX = width - minecraft->font->width(copyright) - 1; + versionPosX = (width - minecraft->font->width(version)) / 2;// - minecraft->font->width(version) - 2; +} + +void StartMenuScreen::buttonClicked(::Button* button) { + + if (button->id == bHost.id) + { + #if defined(DEMO_MODE) || defined(APPLE_DEMO_PROMOTION) + minecraft->setScreen( new SimpleChooseLevelScreen("_DemoLevel") ); + #else + minecraft->screenChooser.setScreen(SCREEN_SELECTWORLD); + #endif + } + if (button->id == bJoin.id) + { + #ifdef APPLE_DEMO_PROMOTION + minecraft->platform()->createUserInput(DialogDefinitions::DIALOG_DEMO_FEATURE_DISABLED); + #else + minecraft->locateMultiplayer(); + minecraft->screenChooser.setScreen(SCREEN_JOINGAME); + #endif + } + if (button->id == bOptions.id) + { + minecraft->setScreen(new OptionsScreen()); + } + if (button == &bQuit) + { + minecraft->quit(); + } +} + +bool StartMenuScreen::isInGameScreen() { return false; } + +void StartMenuScreen::render( int xm, int ym, float a ) +{ + renderBackground(); + + // Show current username in the top-left corner + drawString(font, username, 2, 2, 0xffffffff); + + glEnable2(GL_BLEND); + +#if defined(RPI) + TextureId id = minecraft->textures->loadTexture("gui/pi_title.png"); +#else + TextureId id = minecraft->textures->loadTexture("gui/title.png"); +#endif + const TextureData* data = minecraft->textures->getTemporaryTextureData(id); + + if (data) { + minecraft->textures->bind(id); + + const float x = (float)width / 2; + const float y = 4; + const float wh = 0.5f * Mth::Min((float)width/2.0f, (float)data->w / 2); + const float scale = 2.0f * wh / (float)data->w; + const float h = scale * (float)data->h; + + // Render title text + Tesselator& t = Tesselator::instance; + glColor4f2(1, 1, 1, 1); + t.begin(); + t.vertexUV(x-wh, y+h, blitOffset, 0, 1); + t.vertexUV(x+wh, y+h, blitOffset, 1, 1); + t.vertexUV(x+wh, y+0, blitOffset, 1, 0); + t.vertexUV(x-wh, y+0, blitOffset, 0, 0); + t.draw(); + + drawString(font, version, versionPosX, (int)(y+h)+2, /*50,*/ 0xffcccccc);//0x666666); + drawString(font, copyright, copyrightPosX, height - 10, 0xffffff); + glColor4f2(1, 1, 1, 1); + if (Textures::isTextureIdValid(minecraft->textures->loadAndBindTexture("gui/logo/github.png"))) + blit(2, height - 10, 0, 0, 8, 8, 256, 256); + drawString(font, "Kolyah35/minecraft-pe-0.6.1", 12, height - 10, 0xffcccccc); + //patch->draw(t, 0, 20); + } + Screen::render(xm, ym, a); + glDisable2(GL_BLEND); +} + + +void StartMenuScreen::mouseClicked(int x, int y, int buttonNum) { + const int logoX = 2; + const int logoW = 8 + 2 + font->width("Kolyah35/minecraft-pe-0.6.1"); + const int logoY = height - 10; + const int logoH = 10; + if (x >= logoX && x <= logoX + logoW && y >= logoY && y <= logoY + logoH) + minecraft->platform()->openURL("https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1"); + else + Screen::mouseClicked(x, y, buttonNum); +} + +bool StartMenuScreen::handleBackEvent( bool isDown ) { + minecraft->quit(); + return true; +} + +} // namespace Touch + diff --git a/src/client/gui/screens/touch/TouchStartMenuScreen.h b/src/client/gui/screens/touch/TouchStartMenuScreen.hpp similarity index 77% rename from src/client/gui/screens/touch/TouchStartMenuScreen.h rename to src/client/gui/screens/touch/TouchStartMenuScreen.hpp index 954e06e..71c331d 100755 --- a/src/client/gui/screens/touch/TouchStartMenuScreen.h +++ b/src/client/gui/screens/touch/TouchStartMenuScreen.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../../Screen.h" -#include "../../components/LargeImageButton.h" -#include "../../components/ImageButton.h" -#include "../../components/TextBox.h" +#include "client/gui/Screen.hpp" +#include "client/gui/components/LargeImageButton.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "client/gui/components/TextBox.hpp" namespace Touch { diff --git a/src/client/model/ChestModel.h b/src/client/model/ChestModel.hpp similarity index 94% rename from src/client/model/ChestModel.h rename to src/client/model/ChestModel.hpp index 2f48a94..4caa298 100755 --- a/src/client/model/ChestModel.h +++ b/src/client/model/ChestModel.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.model; -#include "Model.h" -#include "geom/ModelPart.h" +#include "Model.hpp" +#include "geom/ModelPart.hpp" class ChestModel: public Model { diff --git a/src/client/model/ChickenModel.cpp b/src/client/model/ChickenModel.cpp index 4c23498..e05a131 100755 --- a/src/client/model/ChickenModel.cpp +++ b/src/client/model/ChickenModel.cpp @@ -1,101 +1,101 @@ -#include "ChickenModel.h" -#include "../../world/entity/Entity.h" - -ChickenModel::ChickenModel() -: head(0, 0), - beak(14, 0), - redThing(14, 4), - body(0, 9), - leg0(26, 0), - leg1(26, 0), - wing0(24, 13), - wing1(24, 13) -{ - head.setModel(this); - beak.setModel(this); - redThing.setModel(this); - body.setModel(this); - leg0.setModel(this); - leg1.setModel(this); - wing0.setModel(this); - wing1.setModel(this); - - int yo = 16; - head.addBox(-2, -6, -2, 4, 6, 3, 0); // Head - head.setPos(0, -1 + (float)yo, -4); - - beak.addBox(-2, -4, -4, 4, 2, 2, 0); // Beak - beak.setPos(0, -1 + (float)yo, -4); - - redThing.addBox(-1, -2, -3, 2, 2, 2, 0); // Beak - redThing.setPos(0, -1 + (float)yo, -4); - - body.addBox(-3, -4, -3, 6, 8, 6, 0); // Body - body.setPos(0, 0 + (float)yo, 0); - - leg0.addBox(-1, 0, -3, 3, 5, 3); // Leg0 - leg0.setPos(-2, 3 + (float)yo, 1); - - leg1.addBox(-1, 0, -3, 3, 5, 3); // Leg1 - leg1.setPos(1, 3 + (float)yo, 1); - - wing0.addBox(0, 0, -3, 1, 4, 6); // Wing0 - wing0.setPos(-4, -3 + (float)yo, 0); - - wing1.addBox(-1, 0, -3, 1, 4, 6); // Wing1 - wing1.setPos(4, -3 + (float)yo, 0); -} - -void ChickenModel::render( Entity* entity, float time, float r, float bob, float yRot, float xRot, float scale ) -{ - setupAnim(time, r, bob, yRot, xRot, scale); - - if (young) { - float ss = 2; - glPushMatrix(); - glTranslatef(0, 5 * scale, 2 * scale); - head.render(scale); - beak.render(scale); - redThing.render(scale); - glPopMatrix(); - glPushMatrix(); - glScalef(1 / ss, 1 / ss, 1 / ss); - glTranslatef(0, 24 * scale, 0); - body.render(scale); - leg0.render(scale); - leg1.render(scale); - wing0.render(scale); - wing1.render(scale); - glPopMatrix(); - } else { - head.render(scale); - beak.render(scale); - redThing.render(scale); - body.render(scale); - leg0.render(scale); - leg1.render(scale); - wing0.render(scale); - wing1.render(scale); - } -} - -void ChickenModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) -{ - head.xRot = -((xRot / (float) (180 / Mth::PI))); - head.yRot = yRot / (float) (180 / Mth::PI); - - beak.xRot = head.xRot; - beak.yRot = head.yRot; - - redThing.xRot = head.xRot; - redThing.yRot = head.yRot; - - body.xRot = 90 / (float) (180 / Mth::PI); - - const float pend = Mth::cos(time * 0.6662f) * 1.4f * r; - leg0.xRot = pend; - leg1.xRot = -pend; - wing0.zRot = bob; - wing1.zRot = -bob; -} - +#include "ChickenModel.hpp" +#include "world/entity/Entity.hpp" + +ChickenModel::ChickenModel() +: head(0, 0), + beak(14, 0), + redThing(14, 4), + body(0, 9), + leg0(26, 0), + leg1(26, 0), + wing0(24, 13), + wing1(24, 13) +{ + head.setModel(this); + beak.setModel(this); + redThing.setModel(this); + body.setModel(this); + leg0.setModel(this); + leg1.setModel(this); + wing0.setModel(this); + wing1.setModel(this); + + int yo = 16; + head.addBox(-2, -6, -2, 4, 6, 3, 0); // Head + head.setPos(0, -1 + (float)yo, -4); + + beak.addBox(-2, -4, -4, 4, 2, 2, 0); // Beak + beak.setPos(0, -1 + (float)yo, -4); + + redThing.addBox(-1, -2, -3, 2, 2, 2, 0); // Beak + redThing.setPos(0, -1 + (float)yo, -4); + + body.addBox(-3, -4, -3, 6, 8, 6, 0); // Body + body.setPos(0, 0 + (float)yo, 0); + + leg0.addBox(-1, 0, -3, 3, 5, 3); // Leg0 + leg0.setPos(-2, 3 + (float)yo, 1); + + leg1.addBox(-1, 0, -3, 3, 5, 3); // Leg1 + leg1.setPos(1, 3 + (float)yo, 1); + + wing0.addBox(0, 0, -3, 1, 4, 6); // Wing0 + wing0.setPos(-4, -3 + (float)yo, 0); + + wing1.addBox(-1, 0, -3, 1, 4, 6); // Wing1 + wing1.setPos(4, -3 + (float)yo, 0); +} + +void ChickenModel::render( Entity* entity, float time, float r, float bob, float yRot, float xRot, float scale ) +{ + setupAnim(time, r, bob, yRot, xRot, scale); + + if (young) { + float ss = 2; + glPushMatrix(); + glTranslatef(0, 5 * scale, 2 * scale); + head.render(scale); + beak.render(scale); + redThing.render(scale); + glPopMatrix(); + glPushMatrix(); + glScalef(1 / ss, 1 / ss, 1 / ss); + glTranslatef(0, 24 * scale, 0); + body.render(scale); + leg0.render(scale); + leg1.render(scale); + wing0.render(scale); + wing1.render(scale); + glPopMatrix(); + } else { + head.render(scale); + beak.render(scale); + redThing.render(scale); + body.render(scale); + leg0.render(scale); + leg1.render(scale); + wing0.render(scale); + wing1.render(scale); + } +} + +void ChickenModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) +{ + head.xRot = -((xRot / (float) (180 / Mth::PI))); + head.yRot = yRot / (float) (180 / Mth::PI); + + beak.xRot = head.xRot; + beak.yRot = head.yRot; + + redThing.xRot = head.xRot; + redThing.yRot = head.yRot; + + body.xRot = 90 / (float) (180 / Mth::PI); + + const float pend = Mth::cos(time * 0.6662f) * 1.4f * r; + leg0.xRot = pend; + leg1.xRot = -pend; + wing0.zRot = bob; + wing1.zRot = -bob; +} + diff --git a/src/client/model/ChickenModel.h b/src/client/model/ChickenModel.hpp similarity index 88% rename from src/client/model/ChickenModel.h rename to src/client/model/ChickenModel.hpp index ca0438b..a2034cd 100755 --- a/src/client/model/ChickenModel.h +++ b/src/client/model/ChickenModel.hpp @@ -1,7 +1,7 @@ #pragma once -#include "Model.h" -#include "geom/ModelPart.h" +#include "Model.hpp" +#include "geom/ModelPart.hpp" class Entity; diff --git a/src/client/model/CowModel.cpp b/src/client/model/CowModel.cpp index 78154ca..41f3a64 100755 --- a/src/client/model/CowModel.cpp +++ b/src/client/model/CowModel.cpp @@ -1,30 +1,30 @@ -#include "CowModel.h" - -CowModel::CowModel() -: super(12, 0) -{ - head = ModelPart(0, 0); - head.setModel(this); - head.addBox(-4, -4, -6, 8, 8, 6, 0); // Head - head.setPos(0, 12 - 6 - 2, -8); - - head.texOffs(22, 0).addBox(-5, -5, -4, 1, 3, 1, 0); // Horn1 - head.texOffs(22, 0).addBox(+4, -5, -4, 1, 3, 1, 0); // Horn1 - - body = ModelPart(18, 4); - body.setModel(this); - body.addBox(-6, -10, -7, 12, 18, 10, 0); // Body - body.setPos(0, 11 + 6 - 12, 2); - body.texOffs(52, 0).addBox(-2, 2, -8, 4, 6, 1); - - leg0.x -= 1; - leg1.x += 1; - leg0.z += 0; - leg1.z += 0; - leg2.x -= 1; - leg3.x += 1; - leg2.z -= 1; - leg3.z -= 1; - - this->zHeadOffs += 2; -} +#include "CowModel.hpp" + +CowModel::CowModel() +: super(12, 0) +{ + head = ModelPart(0, 0); + head.setModel(this); + head.addBox(-4, -4, -6, 8, 8, 6, 0); // Head + head.setPos(0, 12 - 6 - 2, -8); + + head.texOffs(22, 0).addBox(-5, -5, -4, 1, 3, 1, 0); // Horn1 + head.texOffs(22, 0).addBox(+4, -5, -4, 1, 3, 1, 0); // Horn1 + + body = ModelPart(18, 4); + body.setModel(this); + body.addBox(-6, -10, -7, 12, 18, 10, 0); // Body + body.setPos(0, 11 + 6 - 12, 2); + body.texOffs(52, 0).addBox(-2, 2, -8, 4, 6, 1); + + leg0.x -= 1; + leg1.x += 1; + leg0.z += 0; + leg1.z += 0; + leg2.x -= 1; + leg3.x += 1; + leg2.z -= 1; + leg3.z -= 1; + + this->zHeadOffs += 2; +} diff --git a/src/client/model/CowModel.h b/src/client/model/CowModel.hpp similarity index 83% rename from src/client/model/CowModel.h rename to src/client/model/CowModel.hpp index b3b260a..1f8c2f8 100755 --- a/src/client/model/CowModel.h +++ b/src/client/model/CowModel.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.model; -#include "QuadrupedModel.h" +#include "QuadrupedModel.hpp" class CowModel: public QuadrupedModel { diff --git a/src/client/model/CreeperModel.h b/src/client/model/CreeperModel.hpp similarity index 95% rename from src/client/model/CreeperModel.h rename to src/client/model/CreeperModel.hpp index 35c3392..9fccfe1 100755 --- a/src/client/model/CreeperModel.h +++ b/src/client/model/CreeperModel.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.model; -#include "Model.h" +#include "Model.hpp" -#include "geom/ModelPart.h" -#include "../../world/entity/Entity.h" +#include "geom/ModelPart.hpp" +#include "world/entity/Entity.hpp" class CreeperModel: public Model { diff --git a/src/client/model/HumanoidModel.cpp b/src/client/model/HumanoidModel.cpp index ba414b2..b6a3845 100755 --- a/src/client/model/HumanoidModel.cpp +++ b/src/client/model/HumanoidModel.cpp @@ -1,292 +1,292 @@ -#include "HumanoidModel.h" -#include -#include "../../util/Mth.h" -#include "../../world/entity/player/Player.h" -#include "../../world/entity/player/Inventory.h" - -HumanoidModel::HumanoidModel( float g /*= 0*/, float yOffset /*= 0*/, int texW /*= 64*/, int texH /*= 32*/ ) -: holdingLeftHand(false), - holdingRightHand(false), - sneaking(false), - bowAndArrow(false), - head(0, 0), - hair(32, 0), - //ear (24, 0), - body(16, 16), - arm0(24 + 16, 16), - arm1(24 + 16, 16), - leg0(0, 16), - leg1(0, 16) -{ - texWidth = texW; - texHeight = texH; - - head.setModel(this); - hair.setModel(this); - body.setModel(this); - arm0.setModel(this); - arm1.setModel(this); - leg0.setModel(this); - leg1.setModel(this); - - // If the texture is 64x64, use the modern skin layout for arms/legs and add overlay layers. - bool modernSkin = (texWidth == 64 && texHeight == 64); - if (modernSkin) { - // Left arm and left leg are located in the bottom half of a 64x64 skin. - arm1.texOffs(32, 48); - leg1.texOffs(16, 48); - } - - head.addBox(-4, -8, -4, 8, 8, 8, g); // Head - head.setPos(0, 0 + yOffset, 0); - - if (modernSkin) { - hair.addBox(-4, -8, -4, 8, 8, 8, g + 0.5f); // Outer head layer (hat) - hair.setPos(0, 0 + yOffset, 0); - } - - body.addBox(-4, 0, -2, 8, 12, 4, g); // Body - body.setPos(0, 0 + yOffset, 0); - - arm0.addBox(-3, -2, -2, 4, 12, 4, g); // Arm0 - arm0.setPos(-5, 2 + yOffset, 0); - - arm1.mirror = true; - arm1.addBox(-1, -2, -2, 4, 12, 4, g); // Arm1 - arm1.setPos(5, 2 + yOffset, 0); - - leg0.addBox(-2, 0, -2, 4, 12, 4, g); // Leg0 - leg0.setPos(-2, 12 + yOffset, 0); - - leg1.mirror = true; - leg1.addBox(-2, 0, -2, 4, 12, 4, g); // Leg1 - leg1.setPos(2, 12 + yOffset, 0); - - if (modernSkin) { - // Overlay layers for 64x64 skins (same geometry, different texture regions) - body.texOffs(16, 32); - body.addBox(-4, 0, -2, 8, 12, 4, g + 0.5f); - - arm0.texOffs(40, 32); - arm0.addBox(-3, -2, -2, 4, 12, 4, g + 0.5f); - - arm1.texOffs(48, 48); - arm1.addBox(-1, -2, -2, 4, 12, 4, g + 0.5f); - - leg0.texOffs(0, 32); - leg0.addBox(-2, 0, -2, 4, 12, 4, g + 0.5f); - - leg1.texOffs(0, 48); - leg1.addBox(-2, 0, -2, 4, 12, 4, g + 0.5f); - } -} - -void HumanoidModel::render(Entity* e, float time, float r, float bob, float yRot, float xRot, float scale ) -{ - if(e != NULL && e->isMob()) { - Mob* mob = (Mob*)(e); - ItemInstance* item = mob->getCarriedItem(); - if(item != NULL) { - if(mob->getUseItemDuration() > 0) { - UseAnim::UseAnimation anim = item->getUseAnimation(); - if(anim == UseAnim::bow) { - bowAndArrow = true; - } - } - } - } - - setupAnim(time, r, bob, yRot, xRot, scale); - - // Sync overlay with head rotation/position - if (texWidth == 64 && texHeight == 64) { - hair.xRot = head.xRot; - hair.yRot = head.yRot; - hair.zRot = head.zRot; - hair.y = head.y; - } - - head.render(scale); - if (texWidth == 64 && texHeight == 64) { - hair.render(scale); - } - body.render(scale); - arm0.render(scale); - arm1.render(scale); - leg0.render(scale); - leg1.render(scale); - bowAndArrow = false; -} - -void HumanoidModel::render( HumanoidModel* model, float scale ) -{ - head.yRot = model->head.yRot; - head.y = model->head.y; - head.xRot = model->head.xRot; - if (texWidth == 64 && texHeight == 64) { - hair.yRot = head.yRot; - hair.xRot = head.xRot; - hair.zRot = head.zRot; - hair.y = head.y; - } - - arm0.xRot = model->arm0.xRot; - arm0.zRot = model->arm0.zRot; - - arm1.xRot = model->arm1.xRot; - arm1.zRot = model->arm1.zRot; - - leg0.xRot = model->leg0.xRot; - leg1.xRot = model->leg1.xRot; - - head.render(scale); - if (texWidth == 64 && texHeight == 64) { - hair.render(scale); - } - body.render(scale); - arm0.render(scale); - arm1.render(scale); - leg0.render(scale); - leg1.render(scale); -} - -void HumanoidModel::renderHorrible( float time, float r, float bob, float yRot, float xRot, float scale ) -{ - setupAnim(time, r, bob, yRot, xRot, scale); - head.renderHorrible(scale); - body.renderHorrible(scale); - arm0.renderHorrible(scale); - arm1.renderHorrible(scale); - leg0.renderHorrible(scale); - leg1.renderHorrible(scale); - //hair.renderHorrible(scale); -} -// Updated to match Minecraft Java, all except hair. -void HumanoidModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) -{ - head.yRot = yRot / (180 / Mth::PI); - head.xRot = xRot / (180 / Mth::PI); - const float tcos0 = Mth::cos(time * 0.6662f) * r; - const float tcos1 = Mth::cos(time * 0.6662f + Mth::PI) * r; - - arm0.xRot = tcos1; - arm1.xRot = tcos0; - arm0.zRot = 0; - arm1.zRot = 0; - - leg0.xRot = tcos0 * 1.4f; - leg1.xRot = tcos1 * 1.4f; - leg0.yRot = 0; - leg1.yRot = 0; - - if (riding) { - arm0.xRot += -Mth::PI / 2 * 0.4f; - arm1.xRot += -Mth::PI / 2 * 0.4f; - leg0.xRot = -Mth::PI / 2 * 0.8f; - leg1.xRot = -Mth::PI / 2 * 0.8f; - leg0.yRot = Mth::PI / 2 * 0.2f; - leg1.yRot = -Mth::PI / 2 * 0.2f; - } - - if (holdingLeftHand != 0) { - arm1.xRot = arm1.xRot * 0.5f - Mth::PI / 2.0f * 0.2f * holdingLeftHand; - } - if (holdingRightHand != 0) { - arm0.xRot = arm0.xRot * 0.5f - Mth::PI / 2.0f * 0.2f * holdingRightHand; - } - arm0.yRot = 0; - arm1.yRot = 0; - - if (attackTime > -9990) { - float swing = attackTime; - body.yRot = Mth::sin(Mth::sqrt(swing) * Mth::PI * 2) * 0.2f; - arm0.z = Mth::sin(body.yRot) * 5; - arm0.x = -Mth::cos(body.yRot) * 5; - arm1.z = -Mth::sin(body.yRot) * 5; - arm1.x = Mth::cos(body.yRot) * 5; - arm0.yRot += body.yRot; - arm1.yRot += body.yRot; - arm1.xRot += body.yRot; - - swing = 1 - attackTime; - swing *= swing; - swing *= swing; - swing = 1 - swing; - float aa = Mth::sin(swing * Mth::PI); - float bb = Mth::sin(attackTime * Mth::PI) * -(head.xRot - 0.7f) * 0.75f; - arm0.xRot -= aa * 1.2f + bb; - arm0.yRot += body.yRot * 2; - arm0.zRot = Mth::sin(attackTime * Mth::PI) * -0.4f; - } - - if (sneaking) { - body.xRot = 0.5f; - arm0.xRot += 0.4f; - arm1.xRot += 0.4f; - leg0.z = +4.0f; - leg1.z = +4.0f; - leg0.y = +9.0f; - leg1.y = +9.0f; - head.y = +1; - } else { - body.xRot = 0.0f; - leg0.z = +0.0f; - leg1.z = +0.0f; - leg0.y = +12.0f; - leg1.y = +12.0f; - head.y = 0; - } - - const float bcos = Mth::cos(bob * 0.09f) * 0.05f + 0.05f; - const float bsin = Mth::sin(bob * 0.067f) * 0.05f; - - arm0.zRot += bcos; - arm1.zRot -= bcos; - arm0.xRot += bsin; - arm1.xRot -= bsin; - - if (bowAndArrow) { - float attack2 = 0; - float attack = 0; - - arm0.zRot = 0; - arm1.zRot = 0; - arm0.yRot = -(0.1f - attack2 * 0.6f) + head.yRot; - arm1.yRot = +(0.1f - attack2 * 0.6f) + head.yRot + 0.4f; - arm0.xRot = -Mth::PI / 2.0f + head.xRot; - arm1.xRot = -Mth::PI / 2.0f + head.xRot; - arm0.xRot -= attack2 * 1.2f - attack * 0.4f; - arm1.xRot -= attack2 * 1.2f - attack * 0.4f; - - arm0.zRot += bcos; - arm1.zRot -= bcos; - arm0.xRot += bsin; - arm1.xRot -= bsin; - } -} - -void HumanoidModel::onGraphicsReset() -{ - head.onGraphicsReset(); - body.onGraphicsReset(); - arm0.onGraphicsReset(); - arm1.onGraphicsReset(); - leg0.onGraphicsReset(); - leg1.onGraphicsReset(); - //hair.onGraphicsReset(); -} - -//void renderHair(float scale) { -// hair.yRot = head.yRot; -// hair.xRot = head.xRot; -// hair.render(scale); -//} -// -//void renderEars(float scale) { -// ear.yRot = head.yRot; -// ear.xRot = head.xRot; -// ear.x=0; -// ear.y=0; -// ear.render(scale); -//} -// +#include "HumanoidModel.hpp" +#include +#include "util/Mth.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/player/Inventory.hpp" + +HumanoidModel::HumanoidModel( float g /*= 0*/, float yOffset /*= 0*/, int texW /*= 64*/, int texH /*= 32*/ ) +: holdingLeftHand(false), + holdingRightHand(false), + sneaking(false), + bowAndArrow(false), + head(0, 0), + hair(32, 0), + //ear (24, 0), + body(16, 16), + arm0(24 + 16, 16), + arm1(24 + 16, 16), + leg0(0, 16), + leg1(0, 16) +{ + texWidth = texW; + texHeight = texH; + + head.setModel(this); + hair.setModel(this); + body.setModel(this); + arm0.setModel(this); + arm1.setModel(this); + leg0.setModel(this); + leg1.setModel(this); + + // If the texture is 64x64, use the modern skin layout for arms/legs and add overlay layers. + bool modernSkin = (texWidth == 64 && texHeight == 64); + if (modernSkin) { + // Left arm and left leg are located in the bottom half of a 64x64 skin. + arm1.texOffs(32, 48); + leg1.texOffs(16, 48); + } + + head.addBox(-4, -8, -4, 8, 8, 8, g); // Head + head.setPos(0, 0 + yOffset, 0); + + if (modernSkin) { + hair.addBox(-4, -8, -4, 8, 8, 8, g + 0.5f); // Outer head layer (hat) + hair.setPos(0, 0 + yOffset, 0); + } + + body.addBox(-4, 0, -2, 8, 12, 4, g); // Body + body.setPos(0, 0 + yOffset, 0); + + arm0.addBox(-3, -2, -2, 4, 12, 4, g); // Arm0 + arm0.setPos(-5, 2 + yOffset, 0); + + arm1.mirror = true; + arm1.addBox(-1, -2, -2, 4, 12, 4, g); // Arm1 + arm1.setPos(5, 2 + yOffset, 0); + + leg0.addBox(-2, 0, -2, 4, 12, 4, g); // Leg0 + leg0.setPos(-2, 12 + yOffset, 0); + + leg1.mirror = true; + leg1.addBox(-2, 0, -2, 4, 12, 4, g); // Leg1 + leg1.setPos(2, 12 + yOffset, 0); + + if (modernSkin) { + // Overlay layers for 64x64 skins (same geometry, different texture regions) + body.texOffs(16, 32); + body.addBox(-4, 0, -2, 8, 12, 4, g + 0.5f); + + arm0.texOffs(40, 32); + arm0.addBox(-3, -2, -2, 4, 12, 4, g + 0.5f); + + arm1.texOffs(48, 48); + arm1.addBox(-1, -2, -2, 4, 12, 4, g + 0.5f); + + leg0.texOffs(0, 32); + leg0.addBox(-2, 0, -2, 4, 12, 4, g + 0.5f); + + leg1.texOffs(0, 48); + leg1.addBox(-2, 0, -2, 4, 12, 4, g + 0.5f); + } +} + +void HumanoidModel::render(Entity* e, float time, float r, float bob, float yRot, float xRot, float scale ) +{ + if(e != NULL && e->isMob()) { + Mob* mob = (Mob*)(e); + ItemInstance* item = mob->getCarriedItem(); + if(item != NULL) { + if(mob->getUseItemDuration() > 0) { + UseAnim::UseAnimation anim = item->getUseAnimation(); + if(anim == UseAnim::bow) { + bowAndArrow = true; + } + } + } + } + + setupAnim(time, r, bob, yRot, xRot, scale); + + // Sync overlay with head rotation/position + if (texWidth == 64 && texHeight == 64) { + hair.xRot = head.xRot; + hair.yRot = head.yRot; + hair.zRot = head.zRot; + hair.y = head.y; + } + + head.render(scale); + if (texWidth == 64 && texHeight == 64) { + hair.render(scale); + } + body.render(scale); + arm0.render(scale); + arm1.render(scale); + leg0.render(scale); + leg1.render(scale); + bowAndArrow = false; +} + +void HumanoidModel::render( HumanoidModel* model, float scale ) +{ + head.yRot = model->head.yRot; + head.y = model->head.y; + head.xRot = model->head.xRot; + if (texWidth == 64 && texHeight == 64) { + hair.yRot = head.yRot; + hair.xRot = head.xRot; + hair.zRot = head.zRot; + hair.y = head.y; + } + + arm0.xRot = model->arm0.xRot; + arm0.zRot = model->arm0.zRot; + + arm1.xRot = model->arm1.xRot; + arm1.zRot = model->arm1.zRot; + + leg0.xRot = model->leg0.xRot; + leg1.xRot = model->leg1.xRot; + + head.render(scale); + if (texWidth == 64 && texHeight == 64) { + hair.render(scale); + } + body.render(scale); + arm0.render(scale); + arm1.render(scale); + leg0.render(scale); + leg1.render(scale); +} + +void HumanoidModel::renderHorrible( float time, float r, float bob, float yRot, float xRot, float scale ) +{ + setupAnim(time, r, bob, yRot, xRot, scale); + head.renderHorrible(scale); + body.renderHorrible(scale); + arm0.renderHorrible(scale); + arm1.renderHorrible(scale); + leg0.renderHorrible(scale); + leg1.renderHorrible(scale); + //hair.renderHorrible(scale); +} +// Updated to match Minecraft Java, all except hair. +void HumanoidModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) +{ + head.yRot = yRot / (180 / Mth::PI); + head.xRot = xRot / (180 / Mth::PI); + const float tcos0 = Mth::cos(time * 0.6662f) * r; + const float tcos1 = Mth::cos(time * 0.6662f + Mth::PI) * r; + + arm0.xRot = tcos1; + arm1.xRot = tcos0; + arm0.zRot = 0; + arm1.zRot = 0; + + leg0.xRot = tcos0 * 1.4f; + leg1.xRot = tcos1 * 1.4f; + leg0.yRot = 0; + leg1.yRot = 0; + + if (riding) { + arm0.xRot += -Mth::PI / 2 * 0.4f; + arm1.xRot += -Mth::PI / 2 * 0.4f; + leg0.xRot = -Mth::PI / 2 * 0.8f; + leg1.xRot = -Mth::PI / 2 * 0.8f; + leg0.yRot = Mth::PI / 2 * 0.2f; + leg1.yRot = -Mth::PI / 2 * 0.2f; + } + + if (holdingLeftHand != 0) { + arm1.xRot = arm1.xRot * 0.5f - Mth::PI / 2.0f * 0.2f * holdingLeftHand; + } + if (holdingRightHand != 0) { + arm0.xRot = arm0.xRot * 0.5f - Mth::PI / 2.0f * 0.2f * holdingRightHand; + } + arm0.yRot = 0; + arm1.yRot = 0; + + if (attackTime > -9990) { + float swing = attackTime; + body.yRot = Mth::sin(Mth::sqrt(swing) * Mth::PI * 2) * 0.2f; + arm0.z = Mth::sin(body.yRot) * 5; + arm0.x = -Mth::cos(body.yRot) * 5; + arm1.z = -Mth::sin(body.yRot) * 5; + arm1.x = Mth::cos(body.yRot) * 5; + arm0.yRot += body.yRot; + arm1.yRot += body.yRot; + arm1.xRot += body.yRot; + + swing = 1 - attackTime; + swing *= swing; + swing *= swing; + swing = 1 - swing; + float aa = Mth::sin(swing * Mth::PI); + float bb = Mth::sin(attackTime * Mth::PI) * -(head.xRot - 0.7f) * 0.75f; + arm0.xRot -= aa * 1.2f + bb; + arm0.yRot += body.yRot * 2; + arm0.zRot = Mth::sin(attackTime * Mth::PI) * -0.4f; + } + + if (sneaking) { + body.xRot = 0.5f; + arm0.xRot += 0.4f; + arm1.xRot += 0.4f; + leg0.z = +4.0f; + leg1.z = +4.0f; + leg0.y = +9.0f; + leg1.y = +9.0f; + head.y = +1; + } else { + body.xRot = 0.0f; + leg0.z = +0.0f; + leg1.z = +0.0f; + leg0.y = +12.0f; + leg1.y = +12.0f; + head.y = 0; + } + + const float bcos = Mth::cos(bob * 0.09f) * 0.05f + 0.05f; + const float bsin = Mth::sin(bob * 0.067f) * 0.05f; + + arm0.zRot += bcos; + arm1.zRot -= bcos; + arm0.xRot += bsin; + arm1.xRot -= bsin; + + if (bowAndArrow) { + float attack2 = 0; + float attack = 0; + + arm0.zRot = 0; + arm1.zRot = 0; + arm0.yRot = -(0.1f - attack2 * 0.6f) + head.yRot; + arm1.yRot = +(0.1f - attack2 * 0.6f) + head.yRot + 0.4f; + arm0.xRot = -Mth::PI / 2.0f + head.xRot; + arm1.xRot = -Mth::PI / 2.0f + head.xRot; + arm0.xRot -= attack2 * 1.2f - attack * 0.4f; + arm1.xRot -= attack2 * 1.2f - attack * 0.4f; + + arm0.zRot += bcos; + arm1.zRot -= bcos; + arm0.xRot += bsin; + arm1.xRot -= bsin; + } +} + +void HumanoidModel::onGraphicsReset() +{ + head.onGraphicsReset(); + body.onGraphicsReset(); + arm0.onGraphicsReset(); + arm1.onGraphicsReset(); + leg0.onGraphicsReset(); + leg1.onGraphicsReset(); + //hair.onGraphicsReset(); +} + +//void renderHair(float scale) { +// hair.yRot = head.yRot; +// hair.xRot = head.xRot; +// hair.render(scale); +//} +// +//void renderEars(float scale) { +// ear.yRot = head.yRot; +// ear.xRot = head.xRot; +// ear.x=0; +// ear.y=0; +// ear.render(scale); +//} +// diff --git a/src/client/model/HumanoidModel.h b/src/client/model/HumanoidModel.hpp similarity index 93% rename from src/client/model/HumanoidModel.h rename to src/client/model/HumanoidModel.hpp index f70a41c..9531ecf 100755 --- a/src/client/model/HumanoidModel.h +++ b/src/client/model/HumanoidModel.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.model; -#include "Model.h" -#include "geom/ModelPart.h" +#include "Model.hpp" +#include "geom/ModelPart.hpp" class ItemInstance; class HumanoidModel: public Model { diff --git a/src/client/model/Model.h b/src/client/model/Model.hpp similarity index 96% rename from src/client/model/Model.h rename to src/client/model/Model.hpp index e8e0455..677f34d 100755 --- a/src/client/model/Model.h +++ b/src/client/model/Model.hpp @@ -3,7 +3,7 @@ //package net.minecraft.client.model; #include -#include "geom/ModelPart.h" +#include "geom/ModelPart.hpp" class Mob; class Entity; diff --git a/src/client/model/ModelInclude.h b/src/client/model/ModelInclude.h deleted file mode 100755 index 1f3a157..0000000 --- a/src/client/model/ModelInclude.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "HumanoidModel.h" - -#include "ChickenModel.h" -#include "CowModel.h" -#include "PigModel.h" -#include "SheepModel.h" -#include "SheepFurModel.h" - -#include "ZombieModel.h" -#include "SkeletonModel.h" - -#include "SignModel.h" - diff --git a/src/client/model/ModelInclude.hpp b/src/client/model/ModelInclude.hpp new file mode 100755 index 0000000..4642389 --- /dev/null +++ b/src/client/model/ModelInclude.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "HumanoidModel.hpp" + +#include "ChickenModel.hpp" +#include "CowModel.hpp" +#include "PigModel.hpp" +#include "SheepModel.hpp" +#include "SheepFurModel.hpp" + +#include "ZombieModel.hpp" +#include "SkeletonModel.hpp" + +#include "SignModel.hpp" + diff --git a/src/client/model/PigModel.cpp b/src/client/model/PigModel.cpp index 9adc8eb..77286e4 100755 --- a/src/client/model/PigModel.cpp +++ b/src/client/model/PigModel.cpp @@ -1,8 +1,8 @@ -#include "PigModel.h" - -PigModel::PigModel( float g /*= 0*/ ) -: super(6, g) -{ - head.texOffs(16, 16).addBox(-2, 0, -9, 4, 3, 1, g); - yHeadOffs = 4; -} +#include "PigModel.hpp" + +PigModel::PigModel( float g /*= 0*/ ) +: super(6, g) +{ + head.texOffs(16, 16).addBox(-2, 0, -9, 4, 3, 1, g); + yHeadOffs = 4; +} diff --git a/src/client/model/PigModel.h b/src/client/model/PigModel.hpp similarity index 84% rename from src/client/model/PigModel.h rename to src/client/model/PigModel.hpp index 1afbe63..0876b29 100755 --- a/src/client/model/PigModel.h +++ b/src/client/model/PigModel.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.model; -#include "QuadrupedModel.h" +#include "QuadrupedModel.hpp" class PigModel: public QuadrupedModel { diff --git a/src/client/model/QuadrupedModel.cpp b/src/client/model/QuadrupedModel.cpp index 7f83c6e..58d0351 100755 --- a/src/client/model/QuadrupedModel.cpp +++ b/src/client/model/QuadrupedModel.cpp @@ -1,122 +1,122 @@ -#include "QuadrupedModel.h" -#include "geom/ModelPart.h" -#include "../../util/Mth.h" - -QuadrupedModel::QuadrupedModel( int legSize, float g ) -: yHeadOffs(8), - zHeadOffs(4), - head(0, 0), - body(28, 8), - leg0(0, 16), - leg1(0, 16), - leg2(0, 16), - leg3(0, 16) -{ - head.setModel(this); - body.setModel(this); - leg0.setModel(this); - leg1.setModel(this); - leg2.setModel(this); - leg3.setModel(this); - - head.addBox(-4, -4, -8, 8, 8, 8, g); // Head - head.setPos(0, 12 + 6 - (float)legSize, -6); - - body.addBox(-5, -10, -7, 10, 16, 8, g); // Body - body.setPos(0, 11 + 6 - (float)legSize, 2); - - leg0.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg0 - leg0.setPos(-3, 18 + 6 - (float)legSize, 7); - - leg1.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg1 - leg1.setPos(3, 18 + 6 - (float)legSize, 7); - - leg2.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg2 - leg2.setPos(-3, 18 + 6 - (float)legSize, -5); - - leg3.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg3 - leg3.setPos(3, 18 + 6 - (float)legSize, -5); -} - -void QuadrupedModel::render( Entity* entity, float time, float r, float bob, float yRot, float xRot, float scale ) -{ - setupAnim(time, r, bob, yRot, xRot, scale); - - if (young) { - float ss = 2.0f; - glPushMatrix(); - glTranslatef(0, yHeadOffs * scale, zHeadOffs * scale); - head.render(scale); - glPopMatrix(); - glPushMatrix(); - glScalef(1 / ss, 1 / ss, 1 / ss); - glTranslatef(0, 24 * scale, 0); - body.render(scale); - leg0.render(scale); - leg1.render(scale); - leg2.render(scale); - leg3.render(scale); - glPopMatrix(); - } else { - head.render(scale); - body.render(scale); - leg0.render(scale); - leg1.render(scale); - leg2.render(scale); - leg3.render(scale); - } -} - -void QuadrupedModel::render( QuadrupedModel* model, float scale ) -{ - head.yRot = model->head.yRot; - head.xRot = model->head.xRot; - - head.y = model->head.y; - head.x = model->head.x; - - body.yRot = model->body.yRot; - body.xRot = model->body.xRot; - - leg0.xRot = model->leg0.xRot; - leg1.xRot = model->leg1.xRot; - leg2.xRot = model->leg2.xRot; - leg3.xRot = model->leg3.xRot; - - if (young) { - float ss = 2.0f; - glPushMatrix(); - glTranslatef(0, 8 * scale, 4 * scale); - head.render(scale); - glPopMatrix(); - glPushMatrix(); - glScalef(1 / ss, 1 / ss, 1 / ss); - glTranslatef(0, 24 * scale, 0); - body.render(scale); - leg0.render(scale); - leg1.render(scale); - leg2.render(scale); - leg3.render(scale); - glPopMatrix(); - } else { - head.render(scale); - body.render(scale); - leg0.render(scale); - leg1.render(scale); - leg2.render(scale); - leg3.render(scale); - } -} - -void QuadrupedModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) -{ - head.xRot = xRot / (180.f / Mth::PI); - head.yRot = yRot / (180.f / Mth::PI); - body.xRot = 90 / (180.f / Mth::PI); - - const float pend = Mth::cos(time * 0.6662f) * 1.4f * r; - leg0.xRot = pend; - leg1.xRot = -pend; - leg2.xRot = -pend; - leg3.xRot = pend; -} +#include "QuadrupedModel.hpp" +#include "geom/ModelPart.hpp" +#include "util/Mth.hpp" + +QuadrupedModel::QuadrupedModel( int legSize, float g ) +: yHeadOffs(8), + zHeadOffs(4), + head(0, 0), + body(28, 8), + leg0(0, 16), + leg1(0, 16), + leg2(0, 16), + leg3(0, 16) +{ + head.setModel(this); + body.setModel(this); + leg0.setModel(this); + leg1.setModel(this); + leg2.setModel(this); + leg3.setModel(this); + + head.addBox(-4, -4, -8, 8, 8, 8, g); // Head + head.setPos(0, 12 + 6 - (float)legSize, -6); + + body.addBox(-5, -10, -7, 10, 16, 8, g); // Body + body.setPos(0, 11 + 6 - (float)legSize, 2); + + leg0.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg0 + leg0.setPos(-3, 18 + 6 - (float)legSize, 7); + + leg1.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg1 + leg1.setPos(3, 18 + 6 - (float)legSize, 7); + + leg2.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg2 + leg2.setPos(-3, 18 + 6 - (float)legSize, -5); + + leg3.addBox(-2, 0, -2, 4, legSize, 4, g); // Leg3 + leg3.setPos(3, 18 + 6 - (float)legSize, -5); +} + +void QuadrupedModel::render( Entity* entity, float time, float r, float bob, float yRot, float xRot, float scale ) +{ + setupAnim(time, r, bob, yRot, xRot, scale); + + if (young) { + float ss = 2.0f; + glPushMatrix(); + glTranslatef(0, yHeadOffs * scale, zHeadOffs * scale); + head.render(scale); + glPopMatrix(); + glPushMatrix(); + glScalef(1 / ss, 1 / ss, 1 / ss); + glTranslatef(0, 24 * scale, 0); + body.render(scale); + leg0.render(scale); + leg1.render(scale); + leg2.render(scale); + leg3.render(scale); + glPopMatrix(); + } else { + head.render(scale); + body.render(scale); + leg0.render(scale); + leg1.render(scale); + leg2.render(scale); + leg3.render(scale); + } +} + +void QuadrupedModel::render( QuadrupedModel* model, float scale ) +{ + head.yRot = model->head.yRot; + head.xRot = model->head.xRot; + + head.y = model->head.y; + head.x = model->head.x; + + body.yRot = model->body.yRot; + body.xRot = model->body.xRot; + + leg0.xRot = model->leg0.xRot; + leg1.xRot = model->leg1.xRot; + leg2.xRot = model->leg2.xRot; + leg3.xRot = model->leg3.xRot; + + if (young) { + float ss = 2.0f; + glPushMatrix(); + glTranslatef(0, 8 * scale, 4 * scale); + head.render(scale); + glPopMatrix(); + glPushMatrix(); + glScalef(1 / ss, 1 / ss, 1 / ss); + glTranslatef(0, 24 * scale, 0); + body.render(scale); + leg0.render(scale); + leg1.render(scale); + leg2.render(scale); + leg3.render(scale); + glPopMatrix(); + } else { + head.render(scale); + body.render(scale); + leg0.render(scale); + leg1.render(scale); + leg2.render(scale); + leg3.render(scale); + } +} + +void QuadrupedModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) +{ + head.xRot = xRot / (180.f / Mth::PI); + head.yRot = yRot / (180.f / Mth::PI); + body.xRot = 90 / (180.f / Mth::PI); + + const float pend = Mth::cos(time * 0.6662f) * 1.4f * r; + leg0.xRot = pend; + leg1.xRot = -pend; + leg2.xRot = -pend; + leg3.xRot = pend; +} diff --git a/src/client/model/QuadrupedModel.h b/src/client/model/QuadrupedModel.hpp similarity index 91% rename from src/client/model/QuadrupedModel.h rename to src/client/model/QuadrupedModel.hpp index 0a32405..2ee8980 100755 --- a/src/client/model/QuadrupedModel.h +++ b/src/client/model/QuadrupedModel.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.model; -#include "Model.h" -#include "geom/ModelPart.h" +#include "Model.hpp" +#include "geom/ModelPart.hpp" class Entity; diff --git a/src/client/model/SheepFurModel.cpp b/src/client/model/SheepFurModel.cpp index 0dd5368..178d67c 100755 --- a/src/client/model/SheepFurModel.cpp +++ b/src/client/model/SheepFurModel.cpp @@ -1,49 +1,49 @@ -#include "SheepFurModel.h" -#include "geom/ModelPart.h" -#include "../../world/entity/Mob.h" -#include "../../world/entity/animal/Sheep.h" - -SheepFurModel::SheepFurModel() -: super(12, 0) -{ - head = ModelPart(this, 0, 0); - head.addBox(-3, -4, -4, 6, 6, 6, 0.6f); // Head - head.setPos(0, 12 - 6, -8); - - body = ModelPart(this, 28, 8); - body.addBox(-4, -10, -7, 8, 16, 6, 1.75f); // Body - body.setPos(0, 11 + 6 - 12, 2); - - float g = 0.5f; - leg0 = ModelPart(this, 0, 16); - leg0.addBox(-2, 0, -2, 4, 6, 4, g); // Leg0 - leg0.setPos(-3, 18 + 6 - 12, 7); - - leg1 = ModelPart(this, 0, 16); - leg1.addBox(-2, 0, -2, 4, 6, 4, g); // Leg1 - leg1.setPos(3, 18 + 6 - 12, 7); - - leg2 = ModelPart(this, 0, 16); - leg2.addBox(-2, 0, -2, 4, 6, 4, g); // Leg2 - leg2.setPos(-3, 18 + 6 - 12, -5); - - leg3 = ModelPart(this, 0, 16); - leg3.addBox(-2, 0, -2, 4, 6, 4, g); // Leg3 - leg3.setPos(3, 18 + 6 - 12, -5); -} - -void SheepFurModel::prepareMobModel( Mob* mob, float time, float r, float a ) -{ - super::prepareMobModel(mob, time, r, a); - - Sheep* sheep = (Sheep*) mob; - head.y = 6 + sheep->getHeadEatPositionScale(a) * 9.f; - headXRot = sheep->getHeadEatAngleScale(a); -} - -void SheepFurModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) -{ - super::setupAnim(time, r, bob, yRot, xRot, scale); - - head.xRot = headXRot; -} +#include "SheepFurModel.hpp" +#include "geom/ModelPart.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/animal/Sheep.hpp" + +SheepFurModel::SheepFurModel() +: super(12, 0) +{ + head = ModelPart(this, 0, 0); + head.addBox(-3, -4, -4, 6, 6, 6, 0.6f); // Head + head.setPos(0, 12 - 6, -8); + + body = ModelPart(this, 28, 8); + body.addBox(-4, -10, -7, 8, 16, 6, 1.75f); // Body + body.setPos(0, 11 + 6 - 12, 2); + + float g = 0.5f; + leg0 = ModelPart(this, 0, 16); + leg0.addBox(-2, 0, -2, 4, 6, 4, g); // Leg0 + leg0.setPos(-3, 18 + 6 - 12, 7); + + leg1 = ModelPart(this, 0, 16); + leg1.addBox(-2, 0, -2, 4, 6, 4, g); // Leg1 + leg1.setPos(3, 18 + 6 - 12, 7); + + leg2 = ModelPart(this, 0, 16); + leg2.addBox(-2, 0, -2, 4, 6, 4, g); // Leg2 + leg2.setPos(-3, 18 + 6 - 12, -5); + + leg3 = ModelPart(this, 0, 16); + leg3.addBox(-2, 0, -2, 4, 6, 4, g); // Leg3 + leg3.setPos(3, 18 + 6 - 12, -5); +} + +void SheepFurModel::prepareMobModel( Mob* mob, float time, float r, float a ) +{ + super::prepareMobModel(mob, time, r, a); + + Sheep* sheep = (Sheep*) mob; + head.y = 6 + sheep->getHeadEatPositionScale(a) * 9.f; + headXRot = sheep->getHeadEatAngleScale(a); +} + +void SheepFurModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) +{ + super::setupAnim(time, r, bob, yRot, xRot, scale); + + head.xRot = headXRot; +} diff --git a/src/client/model/SheepFurModel.h b/src/client/model/SheepFurModel.hpp similarity index 92% rename from src/client/model/SheepFurModel.h rename to src/client/model/SheepFurModel.hpp index 960e7d9..681b2b8 100755 --- a/src/client/model/SheepFurModel.h +++ b/src/client/model/SheepFurModel.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.model; -#include "QuadrupedModel.h" +#include "QuadrupedModel.hpp" class SheepFurModel: public QuadrupedModel { diff --git a/src/client/model/SheepModel.cpp b/src/client/model/SheepModel.cpp index 2dac992..ca4427c 100755 --- a/src/client/model/SheepModel.cpp +++ b/src/client/model/SheepModel.cpp @@ -1,32 +1,32 @@ -#include "SheepModel.h" -#include "geom/ModelPart.h" -#include "../../world/entity/Mob.h" -#include "../../world/entity/animal/Sheep.h" - -SheepModel::SheepModel() -: super(12, 0) -{ - head = ModelPart(this, 0, 0); - head.addBox(-3, -4, -6, 6, 6, 8, 0); // Head - head.setPos(0, 12 - 6, -8); - - body = ModelPart(this, 28, 8); - body.addBox(-4, -10, -7, 8, 16, 6, 0); // Body - body.setPos(0, 11 + 6 - 12, 2); -} - -void SheepModel::prepareMobModel( Mob* mob, float time, float r, float a ) -{ - super::prepareMobModel(mob, time, r, a); - - Sheep* sheep = (Sheep*) mob; - head.y = 6 + sheep->getHeadEatPositionScale(a) * 9.f; - headXRot = sheep->getHeadEatAngleScale(a); -} - -void SheepModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) -{ - super::setupAnim(time, r, bob, yRot, xRot, scale); - - head.xRot = headXRot; -} +#include "SheepModel.hpp" +#include "geom/ModelPart.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/animal/Sheep.hpp" + +SheepModel::SheepModel() +: super(12, 0) +{ + head = ModelPart(this, 0, 0); + head.addBox(-3, -4, -6, 6, 6, 8, 0); // Head + head.setPos(0, 12 - 6, -8); + + body = ModelPart(this, 28, 8); + body.addBox(-4, -10, -7, 8, 16, 6, 0); // Body + body.setPos(0, 11 + 6 - 12, 2); +} + +void SheepModel::prepareMobModel( Mob* mob, float time, float r, float a ) +{ + super::prepareMobModel(mob, time, r, a); + + Sheep* sheep = (Sheep*) mob; + head.y = 6 + sheep->getHeadEatPositionScale(a) * 9.f; + headXRot = sheep->getHeadEatAngleScale(a); +} + +void SheepModel::setupAnim( float time, float r, float bob, float yRot, float xRot, float scale ) +{ + super::setupAnim(time, r, bob, yRot, xRot, scale); + + head.xRot = headXRot; +} diff --git a/src/client/model/SheepModel.h b/src/client/model/SheepModel.hpp similarity index 92% rename from src/client/model/SheepModel.h rename to src/client/model/SheepModel.hpp index 1e510f7..532c3a8 100755 --- a/src/client/model/SheepModel.h +++ b/src/client/model/SheepModel.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.model; -#include "QuadrupedModel.h" +#include "QuadrupedModel.hpp" class SheepModel: public QuadrupedModel { diff --git a/src/client/model/SignModel.h b/src/client/model/SignModel.hpp similarity index 89% rename from src/client/model/SignModel.h rename to src/client/model/SignModel.hpp index 916ae18..ca6e845 100755 --- a/src/client/model/SignModel.h +++ b/src/client/model/SignModel.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.model; -#include "Model.h" -#include "geom/ModelPart.h" +#include "Model.hpp" +#include "geom/ModelPart.hpp" class SignModel: public Model { diff --git a/src/client/model/SkeletonModel.h b/src/client/model/SkeletonModel.hpp similarity index 94% rename from src/client/model/SkeletonModel.h rename to src/client/model/SkeletonModel.hpp index 3ff814b..7ea2559 100755 --- a/src/client/model/SkeletonModel.h +++ b/src/client/model/SkeletonModel.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.model; -#include "ZombieModel.h" -#include "geom/ModelPart.h" +#include "ZombieModel.hpp" +#include "geom/ModelPart.hpp" class SkeletonModel: public ZombieModel { diff --git a/src/client/model/SpiderModel.h b/src/client/model/SpiderModel.hpp similarity index 97% rename from src/client/model/SpiderModel.h rename to src/client/model/SpiderModel.hpp index 3dfc72b..62f33b2 100755 --- a/src/client/model/SpiderModel.h +++ b/src/client/model/SpiderModel.hpp @@ -2,11 +2,11 @@ //package net.minecraft.client.model; -#include "Model.h" +#include "Model.hpp" -#include "geom/ModelPart.h" -#include "../../world/entity/Entity.h" -#include "../../util/Mth.h" +#include "geom/ModelPart.hpp" +#include "world/entity/Entity.hpp" +#include "util/Mth.hpp" class SpiderModel: public Model { diff --git a/src/client/model/ZombieModel.h b/src/client/model/ZombieModel.hpp similarity index 97% rename from src/client/model/ZombieModel.h rename to src/client/model/ZombieModel.hpp index b3d2053..9a95f14 100755 --- a/src/client/model/ZombieModel.h +++ b/src/client/model/ZombieModel.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.model; -#include "HumanoidModel.h" +#include "HumanoidModel.hpp" class ZombieModel: public HumanoidModel { diff --git a/src/client/model/geom/Cube.cpp b/src/client/model/geom/Cube.cpp index bb3c030..4ac9d96 100755 --- a/src/client/model/geom/Cube.cpp +++ b/src/client/model/geom/Cube.cpp @@ -1,75 +1,75 @@ -#include "Cube.h" -#include "ModelPart.h" -#include "../../renderer/Tesselator.h" -#include "../../renderer/gles.h" -#include "../../../util/Mth.h" - -Cube::Cube(ModelPart* modelPart, int xTexOffs, int yTexOffs, float x0, float y0, float z0, int w, int h, int d, float g) -: x0(x0), - y0(y0), - z0(z0), - x1(x0 + w), - y1(y0 + h), - z1(z0 + d) -{ - float x1 = this->x1; - float y1 = this->y1; - float z1 = this->z1; - - x0 -= g; - y0 -= g; - z0 -= g; - x1 += g; - y1 += g; - z1 += g; - - if (modelPart->mirror) { - float tmp = x1; - x1 = x0; - x0 = tmp; - } - - vertices[0] = VertexPT(x0, y0, z0, 0, 0); - vertices[1] = VertexPT(x1, y0, z0, 0, 8); - vertices[2] = VertexPT(x1, y1, z0, 8, 8); - vertices[3] = VertexPT(x0, y1, z0, 8, 0); - - vertices[4] = VertexPT(x0, y0, z1, 0, 0); - vertices[5] = VertexPT(x1, y0, z1, 0, 8); - vertices[6] = VertexPT(x1, y1, z1, 8, 8); - vertices[7] = VertexPT(x0, y1, z1, 8, 0); - - VertexPT* ptr = vertices - 1; - VertexPT* u0 = ++ptr; - VertexPT* u1 = ++ptr; - VertexPT* u2 = ++ptr; - VertexPT* u3 = ++ptr; - - VertexPT* l0 = ++ptr; - VertexPT* l1 = ++ptr; - VertexPT* l2 = ++ptr; - VertexPT* l3 = ++ptr; - - polygons[0] = PolygonQuad(l1, u1, u2, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + d, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Right - polygons[1] = PolygonQuad(u0, l0, l3, u3, xTexOffs + 0, yTexOffs + d, xTexOffs + d, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Left - polygons[2] = PolygonQuad(l1, l0, u0, u1, xTexOffs + d, yTexOffs + 0, xTexOffs + d + w, yTexOffs + d, modelPart->xTexSize, modelPart->yTexSize); // Up - polygons[3] = PolygonQuad(u2, u3, l3, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + w, yTexOffs, modelPart->xTexSize, modelPart->yTexSize); // Down - polygons[4] = PolygonQuad(u1, u0, u3, u2, xTexOffs + d, yTexOffs + d, xTexOffs + d + w, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Front - polygons[5] = PolygonQuad(l0, l1, l2, l3, xTexOffs + d + w + d, yTexOffs + d, xTexOffs + d + w + d + w, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Back - - if (modelPart->mirror) { - for (int i = 0; i < 6; i++) - polygons[i].mirror(); - } -} - -void Cube::compile(Tesselator& t, float scale) { - for (int i = 0; i < 6; i++) { - polygons[i].render(t, scale); - } -} - -Cube* Cube::setId(const std::string& id) { - this->id = id; - return this; +#include "Cube.hpp" +#include "ModelPart.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/gles.hpp" +#include "util/Mth.hpp" + +Cube::Cube(ModelPart* modelPart, int xTexOffs, int yTexOffs, float x0, float y0, float z0, int w, int h, int d, float g) +: x0(x0), + y0(y0), + z0(z0), + x1(x0 + w), + y1(y0 + h), + z1(z0 + d) +{ + float x1 = this->x1; + float y1 = this->y1; + float z1 = this->z1; + + x0 -= g; + y0 -= g; + z0 -= g; + x1 += g; + y1 += g; + z1 += g; + + if (modelPart->mirror) { + float tmp = x1; + x1 = x0; + x0 = tmp; + } + + vertices[0] = VertexPT(x0, y0, z0, 0, 0); + vertices[1] = VertexPT(x1, y0, z0, 0, 8); + vertices[2] = VertexPT(x1, y1, z0, 8, 8); + vertices[3] = VertexPT(x0, y1, z0, 8, 0); + + vertices[4] = VertexPT(x0, y0, z1, 0, 0); + vertices[5] = VertexPT(x1, y0, z1, 0, 8); + vertices[6] = VertexPT(x1, y1, z1, 8, 8); + vertices[7] = VertexPT(x0, y1, z1, 8, 0); + + VertexPT* ptr = vertices - 1; + VertexPT* u0 = ++ptr; + VertexPT* u1 = ++ptr; + VertexPT* u2 = ++ptr; + VertexPT* u3 = ++ptr; + + VertexPT* l0 = ++ptr; + VertexPT* l1 = ++ptr; + VertexPT* l2 = ++ptr; + VertexPT* l3 = ++ptr; + + polygons[0] = PolygonQuad(l1, u1, u2, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + d, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Right + polygons[1] = PolygonQuad(u0, l0, l3, u3, xTexOffs + 0, yTexOffs + d, xTexOffs + d, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Left + polygons[2] = PolygonQuad(l1, l0, u0, u1, xTexOffs + d, yTexOffs + 0, xTexOffs + d + w, yTexOffs + d, modelPart->xTexSize, modelPart->yTexSize); // Up + polygons[3] = PolygonQuad(u2, u3, l3, l2, xTexOffs + d + w, yTexOffs + d, xTexOffs + d + w + w, yTexOffs, modelPart->xTexSize, modelPart->yTexSize); // Down + polygons[4] = PolygonQuad(u1, u0, u3, u2, xTexOffs + d, yTexOffs + d, xTexOffs + d + w, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Front + polygons[5] = PolygonQuad(l0, l1, l2, l3, xTexOffs + d + w + d, yTexOffs + d, xTexOffs + d + w + d + w, yTexOffs + d + h, modelPart->xTexSize, modelPart->yTexSize); // Back + + if (modelPart->mirror) { + for (int i = 0; i < 6; i++) + polygons[i].mirror(); + } +} + +void Cube::compile(Tesselator& t, float scale) { + for (int i = 0; i < 6; i++) { + polygons[i].render(t, scale); + } +} + +Cube* Cube::setId(const std::string& id) { + this->id = id; + return this; } \ No newline at end of file diff --git a/src/client/model/geom/Cube.h b/src/client/model/geom/Cube.hpp similarity index 95% rename from src/client/model/geom/Cube.h rename to src/client/model/geom/Cube.hpp index 544e06f..d529ef7 100755 --- a/src/client/model/geom/Cube.h +++ b/src/client/model/geom/Cube.hpp @@ -3,7 +3,7 @@ //package net.minecraft.client.model; #include -#include "Polygon.h" +#include "Polygon.hpp" class Tesselator; class ModelPart; diff --git a/src/client/model/geom/ModelPart.cpp b/src/client/model/geom/ModelPart.cpp index 7fa8f70..953351a 100755 --- a/src/client/model/geom/ModelPart.cpp +++ b/src/client/model/geom/ModelPart.cpp @@ -1,303 +1,303 @@ -#include "ModelPart.h" -#include "Cube.h" -#include "../Model.h" -#include "../../renderer/Tesselator.h" -#include "../../../util/Mth.h" - - -ModelPart::ModelPart( const std::string& id ) -: id(id), - model(NULL), - xTexOffs(0), - yTexOffs(0) -{ - _init(); -} - -ModelPart::ModelPart( int xTexOffs /*= 0*/, int yTexOffs /*= 0*/ ) -: xTexOffs(xTexOffs), - yTexOffs(yTexOffs), - model(NULL) -{ - _init(); -} - -ModelPart::ModelPart( Model* model, int xTexOffs /*= 0*/, int yTexOffs /*= 0*/ ) -: model(model), - xTexOffs(xTexOffs), - yTexOffs(yTexOffs) -{ - _init(); -} - -ModelPart::~ModelPart() { - clear(); -} - -void ModelPart::_init() { - x = y = z = 0; - xRot = yRot = zRot = 0; - list = 0; - mirror = false; - visible = true; - neverRender = false; - compiled = false; - xTexSize = 64; - yTexSize = 32; - - vboId = 0; - glGenBuffers2(1, &vboId); -} - -void ModelPart::setModel(Model* model) { - if (this->model) { - Util::remove(this->model->cubes, this); - } - if (model) { - model->cubes.push_back(this); - setTexSize(model->texWidth, model->texHeight); - } - this->model = model; -} - -void ModelPart::addChild(ModelPart* child) { - children.push_back(child); -} - -ModelPart& ModelPart::addBox(const std::string& id, float x0, float y0, float z0, int w, int h, int d) { - std::string newid = this->id + "." + id; - //TexOffs offs = model.getMapTex(id); //@todo @diff - //texOffs(offs.x, offs.y); - cubes.push_back((new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, 0))->setId(newid)); - return *this; -} - -ModelPart& ModelPart::addBox(float x0, float y0, float z0, int w, int h, int d) { - cubes.push_back(new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, 0)); - return *this; -} - -void ModelPart::addBox(float x0, float y0, float z0, int w, int h, int d, float g) { - cubes.push_back(new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, g)); -} - -//This Cube constructor is commented out -//void ModelPart::addTexBox(float x0, float y0, float z0, int w, int h, int d, int tex) { -// cubes.push_back(new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, tex)); -//} - - -void ModelPart::setPos( float x, float y, float z ) -{ - this->x = x; - this->y = y; - this->z = z; -} - -void ModelPart::render( float scale ) -{ - if (neverRender) return; - if (!visible) return; - if (!compiled) compile(scale); - - if (xRot != 0 || yRot != 0 || zRot != 0) { - glPushMatrix2(); - glTranslatef2(x * scale, y * scale, z * scale); - - const float c = Mth::RADDEG; - if (zRot != 0) glRotatef2(zRot * c, 0.0f, 0.0f, 1.0f); - if (yRot != 0) glRotatef2(yRot * c, 0.0f, 1.0f, 0.0f); - if (xRot != 0) glRotatef2(xRot * c, 1.0f, 0.0f, 0.0f); - - //LOGI("A"); - draw(); - if (!children.empty()) { - for (unsigned int i = 0; i < children.size(); i++) { - children[i]->render(scale); - } - } - - glPopMatrix2(); - } else if (x != 0 || y != 0 || z != 0) { - glTranslatef2(x * scale, y * scale, z * scale); - //LOGI("B"); - draw(); - if (!children.empty()) { - for (unsigned int i = 0; i < children.size(); i++) { - children[i]->render(scale); - } - } - - glTranslatef2(-x * scale, -y * scale, -z * scale); - } else { - //LOGI("C"); - draw(); - if (!children.empty()) { - for (unsigned int i = 0; i < children.size(); i++) { - children[i]->render(scale); - } - } - } -} - - -void ModelPart::renderRollable( float scale ) -{ - if (neverRender) return; - if (!visible) return; - if (!compiled) compile(scale); - - glPushMatrix2(); - glTranslatef2(x * scale, y * scale, z * scale); - - const float c = Mth::RADDEG; - if (yRot != 0) glRotatef2(yRot * c, 0.0f, 1.0f, 0.0f); - if (xRot != 0) glRotatef2(xRot * c, 1.0f, 0.0f, 0.0f); - if (zRot != 0) glRotatef2(zRot * c, 0.0f, 0.0f, 1.0f); - - draw(); - glPopMatrix2(); -} - - -void ModelPart::translateTo( float scale ) -{ - if (neverRender) return; - if (!visible) return; - if (!compiled) compile(scale); - - if (xRot != 0 || yRot != 0 || zRot != 0) { - const float c = Mth::RADDEG; - glTranslatef2(x * scale, y * scale, z * scale); - if (zRot != 0) glRotatef2(zRot * c, 0.0f, 0.0f, 1.0f); - if (yRot != 0) glRotatef2(yRot * c, 0.0f, 1.0f, 0.0f); - if (xRot != 0) glRotatef2(xRot * c, 1.0f, 0.0f, 0.0f); - } else if (x != 0 || y != 0 || z != 0) { - glTranslatef2(x * scale, y * scale, z * scale); - } else { - } -} - - -void ModelPart::compile( float scale ) -{ -#ifndef OPENGL_ES - list = glGenLists(1); - // FIX NORMAL BUG HERE - glNewList(list, GL_COMPILE); -#endif - Tesselator& t = Tesselator::instance; - t.begin(); - t.color(255, 255, 255, 255); - for (int i = 0; i < 6; i++) { - for (unsigned int i = 0; i < cubes.size(); ++i) - cubes[i]->compile(t, scale); - } - t.end(true, vboId); -#ifndef OPENGL_ES - glEndList(); -#endif - compiled = true; -} - -void ModelPart::draw() -{ -#ifdef OPENGL_ES - drawArrayVT_NoState(vboId, cubes.size() * 2 * 3 * 6, 24); -#else - glCallList(list); -#endif -} - -ModelPart& ModelPart::setTexSize(int xs, int ys) { - xTexSize = (float)xs; - yTexSize = (float)ys; - return *this; -} - -ModelPart& ModelPart::texOffs(int xTexOffs, int yTexOffs) { - this->xTexOffs = xTexOffs; - this->yTexOffs = yTexOffs; - return *this; -} - -void ModelPart::mimic(const ModelPart* o) { - x = o->x; - y = o->y; - z = o->z; - - xRot = o->xRot; - yRot = o->yRot; - zRot = o->zRot; -} - -void ModelPart::renderHorrible( float scale ) -{ - if (neverRender) { - return; - } - if (!visible) { - return; - } - //if (!compiled) compile(scale); - - if (xRot != 0 || yRot != 0 || zRot != 0) { - glPushMatrix2(); - glTranslatef2(x * scale, y * scale, z * scale); - if (zRot != 0) glRotatef2(zRot * Mth::RADDEG, 0.0f, 0.0f, 1.0f); - if (yRot != 0) glRotatef2(yRot * Mth::RADDEG, 0.0f, 1.0f, 0.0f); - if (xRot != 0) glRotatef2(xRot * Mth::RADDEG, 1.0f, 0.0f, 0.0f); - - drawSlow(scale); - glPopMatrix2(); - } else if (x != 0 || y != 0 || z != 0) { - glTranslatef2(x * scale, y * scale, z * scale); - drawSlow(scale); - glTranslatef2(-x * scale, -y * scale, -z * scale); - } else { - drawSlow(scale); - } -} - -void ModelPart::drawSlow( float scale ) -{ - Tesselator& t = Tesselator::instance; - t.begin(); - for (int j = 0; j < (int)cubes.size(); ++j) { - Cube* c = cubes[j]; - for (int i = 0; i < 6; i++) { - c->polygons[i].render(t, scale, vboId); - } - } - t.draw(); -} - -void ModelPart::clear() -{ - for (unsigned int i = 0; i < cubes.size(); ++i) - delete cubes[i]; - cubes.clear(); - - setModel(NULL); -} - -ModelPart& ModelPart::operator=( const ModelPart& rhs ) -{ - clear(); - - if (!id.empty() || !rhs.id.empty()) { - id = rhs.id; - } - xTexOffs = rhs.xTexOffs; - yTexOffs = rhs.yTexOffs; - - compiled = false; - mirror = rhs.mirror; - - setModel(rhs.model); - cubes.assign(rhs.cubes.begin(), rhs.cubes.end()); - - mimic(&rhs); - - return *this; -} +#include "ModelPart.hpp" +#include "Cube.hpp" +#include "client/model/Model.hpp" +#include "client/renderer/Tesselator.hpp" +#include "util/Mth.hpp" + + +ModelPart::ModelPart( const std::string& id ) +: id(id), + model(NULL), + xTexOffs(0), + yTexOffs(0) +{ + _init(); +} + +ModelPart::ModelPart( int xTexOffs /*= 0*/, int yTexOffs /*= 0*/ ) +: xTexOffs(xTexOffs), + yTexOffs(yTexOffs), + model(NULL) +{ + _init(); +} + +ModelPart::ModelPart( Model* model, int xTexOffs /*= 0*/, int yTexOffs /*= 0*/ ) +: model(model), + xTexOffs(xTexOffs), + yTexOffs(yTexOffs) +{ + _init(); +} + +ModelPart::~ModelPart() { + clear(); +} + +void ModelPart::_init() { + x = y = z = 0; + xRot = yRot = zRot = 0; + list = 0; + mirror = false; + visible = true; + neverRender = false; + compiled = false; + xTexSize = 64; + yTexSize = 32; + + vboId = 0; + glGenBuffers2(1, &vboId); +} + +void ModelPart::setModel(Model* model) { + if (this->model) { + Util::remove(this->model->cubes, this); + } + if (model) { + model->cubes.push_back(this); + setTexSize(model->texWidth, model->texHeight); + } + this->model = model; +} + +void ModelPart::addChild(ModelPart* child) { + children.push_back(child); +} + +ModelPart& ModelPart::addBox(const std::string& id, float x0, float y0, float z0, int w, int h, int d) { + std::string newid = this->id + "." + id; + //TexOffs offs = model.getMapTex(id); //@todo @diff + //texOffs(offs.x, offs.y); + cubes.push_back((new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, 0))->setId(newid)); + return *this; +} + +ModelPart& ModelPart::addBox(float x0, float y0, float z0, int w, int h, int d) { + cubes.push_back(new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, 0)); + return *this; +} + +void ModelPart::addBox(float x0, float y0, float z0, int w, int h, int d, float g) { + cubes.push_back(new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, g)); +} + +//This Cube constructor is commented out +//void ModelPart::addTexBox(float x0, float y0, float z0, int w, int h, int d, int tex) { +// cubes.push_back(new Cube(this, xTexOffs, yTexOffs, x0, y0, z0, w, h, d, tex)); +//} + + +void ModelPart::setPos( float x, float y, float z ) +{ + this->x = x; + this->y = y; + this->z = z; +} + +void ModelPart::render( float scale ) +{ + if (neverRender) return; + if (!visible) return; + if (!compiled) compile(scale); + + if (xRot != 0 || yRot != 0 || zRot != 0) { + glPushMatrix2(); + glTranslatef2(x * scale, y * scale, z * scale); + + const float c = Mth::RADDEG; + if (zRot != 0) glRotatef2(zRot * c, 0.0f, 0.0f, 1.0f); + if (yRot != 0) glRotatef2(yRot * c, 0.0f, 1.0f, 0.0f); + if (xRot != 0) glRotatef2(xRot * c, 1.0f, 0.0f, 0.0f); + + //LOGI("A"); + draw(); + if (!children.empty()) { + for (unsigned int i = 0; i < children.size(); i++) { + children[i]->render(scale); + } + } + + glPopMatrix2(); + } else if (x != 0 || y != 0 || z != 0) { + glTranslatef2(x * scale, y * scale, z * scale); + //LOGI("B"); + draw(); + if (!children.empty()) { + for (unsigned int i = 0; i < children.size(); i++) { + children[i]->render(scale); + } + } + + glTranslatef2(-x * scale, -y * scale, -z * scale); + } else { + //LOGI("C"); + draw(); + if (!children.empty()) { + for (unsigned int i = 0; i < children.size(); i++) { + children[i]->render(scale); + } + } + } +} + + +void ModelPart::renderRollable( float scale ) +{ + if (neverRender) return; + if (!visible) return; + if (!compiled) compile(scale); + + glPushMatrix2(); + glTranslatef2(x * scale, y * scale, z * scale); + + const float c = Mth::RADDEG; + if (yRot != 0) glRotatef2(yRot * c, 0.0f, 1.0f, 0.0f); + if (xRot != 0) glRotatef2(xRot * c, 1.0f, 0.0f, 0.0f); + if (zRot != 0) glRotatef2(zRot * c, 0.0f, 0.0f, 1.0f); + + draw(); + glPopMatrix2(); +} + + +void ModelPart::translateTo( float scale ) +{ + if (neverRender) return; + if (!visible) return; + if (!compiled) compile(scale); + + if (xRot != 0 || yRot != 0 || zRot != 0) { + const float c = Mth::RADDEG; + glTranslatef2(x * scale, y * scale, z * scale); + if (zRot != 0) glRotatef2(zRot * c, 0.0f, 0.0f, 1.0f); + if (yRot != 0) glRotatef2(yRot * c, 0.0f, 1.0f, 0.0f); + if (xRot != 0) glRotatef2(xRot * c, 1.0f, 0.0f, 0.0f); + } else if (x != 0 || y != 0 || z != 0) { + glTranslatef2(x * scale, y * scale, z * scale); + } else { + } +} + + +void ModelPart::compile( float scale ) +{ +#ifndef OPENGL_ES + list = glGenLists(1); + // FIX NORMAL BUG HERE + glNewList(list, GL_COMPILE); +#endif + Tesselator& t = Tesselator::instance; + t.begin(); + t.color(255, 255, 255, 255); + for (int i = 0; i < 6; i++) { + for (unsigned int i = 0; i < cubes.size(); ++i) + cubes[i]->compile(t, scale); + } + t.end(true, vboId); +#ifndef OPENGL_ES + glEndList(); +#endif + compiled = true; +} + +void ModelPart::draw() +{ +#ifdef OPENGL_ES + drawArrayVT_NoState(vboId, cubes.size() * 2 * 3 * 6, 24); +#else + glCallList(list); +#endif +} + +ModelPart& ModelPart::setTexSize(int xs, int ys) { + xTexSize = (float)xs; + yTexSize = (float)ys; + return *this; +} + +ModelPart& ModelPart::texOffs(int xTexOffs, int yTexOffs) { + this->xTexOffs = xTexOffs; + this->yTexOffs = yTexOffs; + return *this; +} + +void ModelPart::mimic(const ModelPart* o) { + x = o->x; + y = o->y; + z = o->z; + + xRot = o->xRot; + yRot = o->yRot; + zRot = o->zRot; +} + +void ModelPart::renderHorrible( float scale ) +{ + if (neverRender) { + return; + } + if (!visible) { + return; + } + //if (!compiled) compile(scale); + + if (xRot != 0 || yRot != 0 || zRot != 0) { + glPushMatrix2(); + glTranslatef2(x * scale, y * scale, z * scale); + if (zRot != 0) glRotatef2(zRot * Mth::RADDEG, 0.0f, 0.0f, 1.0f); + if (yRot != 0) glRotatef2(yRot * Mth::RADDEG, 0.0f, 1.0f, 0.0f); + if (xRot != 0) glRotatef2(xRot * Mth::RADDEG, 1.0f, 0.0f, 0.0f); + + drawSlow(scale); + glPopMatrix2(); + } else if (x != 0 || y != 0 || z != 0) { + glTranslatef2(x * scale, y * scale, z * scale); + drawSlow(scale); + glTranslatef2(-x * scale, -y * scale, -z * scale); + } else { + drawSlow(scale); + } +} + +void ModelPart::drawSlow( float scale ) +{ + Tesselator& t = Tesselator::instance; + t.begin(); + for (int j = 0; j < (int)cubes.size(); ++j) { + Cube* c = cubes[j]; + for (int i = 0; i < 6; i++) { + c->polygons[i].render(t, scale, vboId); + } + } + t.draw(); +} + +void ModelPart::clear() +{ + for (unsigned int i = 0; i < cubes.size(); ++i) + delete cubes[i]; + cubes.clear(); + + setModel(NULL); +} + +ModelPart& ModelPart::operator=( const ModelPart& rhs ) +{ + clear(); + + if (!id.empty() || !rhs.id.empty()) { + id = rhs.id; + } + xTexOffs = rhs.xTexOffs; + yTexOffs = rhs.yTexOffs; + + compiled = false; + mirror = rhs.mirror; + + setModel(rhs.model); + cubes.assign(rhs.cubes.begin(), rhs.cubes.end()); + + mimic(&rhs); + + return *this; +} diff --git a/src/client/model/geom/ModelPart.h b/src/client/model/geom/ModelPart.hpp similarity index 97% rename from src/client/model/geom/ModelPart.h rename to src/client/model/geom/ModelPart.hpp index b532bb3..183654b 100755 --- a/src/client/model/geom/ModelPart.h +++ b/src/client/model/geom/ModelPart.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../renderer/gles.h" +#include "client/renderer/gles.hpp" class Model; class Cube; diff --git a/src/client/model/geom/Polygon.cpp b/src/client/model/geom/Polygon.cpp index bfb1467..b146295 100755 --- a/src/client/model/geom/Polygon.cpp +++ b/src/client/model/geom/Polygon.cpp @@ -1,55 +1,55 @@ -#include "Polygon.h" -#include "../../renderer/Tesselator.h" -#include "../../../world/phys/Vec3.h" - -PolygonQuad::PolygonQuad(VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3) -: _flipNormal(false) -{ - vertices[0] = *v0; - vertices[1] = *v1; - vertices[2] = *v2; - vertices[3] = *v3; -} - -PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3, - int uu0, int vv0, int uu1, int vv1, float texW, float texH) -: _flipNormal(false) -{ - const float us = -0.002f / texW; - const float vs = -0.002f / texH; - vertices[0] = v0->remap(uu1 / texW - us, vv0 / texH + vs); - vertices[1] = v1->remap(uu0 / texW + us, vv0 / texH + vs); - vertices[2] = v2->remap(uu0 / texW + us, vv1 / texH - vs); - vertices[3] = v3->remap(uu1 / texW - us, vv1 / texH - vs); -} - -PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3, - float uu0, float vv0, float uu1, float vv1) -: _flipNormal(false) -{ - vertices[0] = v0->remap(uu1, vv0); - vertices[1] = v1->remap(uu0, vv0); - vertices[2] = v2->remap(uu0, vv1); - vertices[3] = v3->remap(uu1, vv1); -} - -void PolygonQuad::mirror() { - for (int i = 0; i < VERTEX_COUNT / 2; ++i) { - const int j = VERTEX_COUNT - i - 1; - VertexPT tmp = vertices[i]; - vertices[i] = vertices[j]; - vertices[j] = tmp; - } -} - -void PolygonQuad::render(Tesselator& t, float scale, int vboId /* = -1 */) { - for (int i = 0; i < 4; i++) { - VertexPT& v = vertices[i]; - t.vertexUV(v.pos.x * scale, v.pos.y * scale, v.pos.z * scale, v.u, v.v); - } -} - -PolygonQuad* PolygonQuad::flipNormal() { - _flipNormal = true; - return this; -} +#include "Polygon.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/phys/Vec3.hpp" + +PolygonQuad::PolygonQuad(VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3) +: _flipNormal(false) +{ + vertices[0] = *v0; + vertices[1] = *v1; + vertices[2] = *v2; + vertices[3] = *v3; +} + +PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3, + int uu0, int vv0, int uu1, int vv1, float texW, float texH) +: _flipNormal(false) +{ + const float us = -0.002f / texW; + const float vs = -0.002f / texH; + vertices[0] = v0->remap(uu1 / texW - us, vv0 / texH + vs); + vertices[1] = v1->remap(uu0 / texW + us, vv0 / texH + vs); + vertices[2] = v2->remap(uu0 / texW + us, vv1 / texH - vs); + vertices[3] = v3->remap(uu1 / texW - us, vv1 / texH - vs); +} + +PolygonQuad::PolygonQuad( VertexPT* v0, VertexPT* v1, VertexPT* v2, VertexPT* v3, + float uu0, float vv0, float uu1, float vv1) +: _flipNormal(false) +{ + vertices[0] = v0->remap(uu1, vv0); + vertices[1] = v1->remap(uu0, vv0); + vertices[2] = v2->remap(uu0, vv1); + vertices[3] = v3->remap(uu1, vv1); +} + +void PolygonQuad::mirror() { + for (int i = 0; i < VERTEX_COUNT / 2; ++i) { + const int j = VERTEX_COUNT - i - 1; + VertexPT tmp = vertices[i]; + vertices[i] = vertices[j]; + vertices[j] = tmp; + } +} + +void PolygonQuad::render(Tesselator& t, float scale, int vboId /* = -1 */) { + for (int i = 0; i < 4; i++) { + VertexPT& v = vertices[i]; + t.vertexUV(v.pos.x * scale, v.pos.y * scale, v.pos.z * scale, v.u, v.v); + } +} + +PolygonQuad* PolygonQuad::flipNormal() { + _flipNormal = true; + return this; +} diff --git a/src/client/model/geom/Polygon.h b/src/client/model/geom/Polygon.hpp similarity index 96% rename from src/client/model/geom/Polygon.h rename to src/client/model/geom/Polygon.hpp index 3f05602..025554b 100755 --- a/src/client/model/geom/Polygon.h +++ b/src/client/model/geom/Polygon.hpp @@ -1,7 +1,7 @@ #pragma once //package net.minecraft.client.model; -#include "Vertex.h" +#include "Vertex.hpp" class Tesselator; diff --git a/src/client/model/geom/Vertex.h b/src/client/model/geom/Vertex.hpp similarity index 93% rename from src/client/model/geom/Vertex.h rename to src/client/model/geom/Vertex.hpp index d1378cf..0afae27 100755 --- a/src/client/model/geom/Vertex.h +++ b/src/client/model/geom/Vertex.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.model; -#include "../../../world/phys/Vec3.h" +#include "world/phys/Vec3.hpp" class VertexPT { diff --git a/src/client/multiplayer/MultiPlayerLevel.h b/src/client/multiplayer/MultiPlayerLevel.hpp similarity index 95% rename from src/client/multiplayer/MultiPlayerLevel.h rename to src/client/multiplayer/MultiPlayerLevel.hpp index 2876b84..df2a64f 100755 --- a/src/client/multiplayer/MultiPlayerLevel.h +++ b/src/client/multiplayer/MultiPlayerLevel.hpp @@ -1,12 +1,12 @@ #pragma once -#include "../../world/Pos.h" -#include "../../world/level/Level.h" -//#include "../../network/packet/DisconnectPacket.h" -#include "../../world/entity/Entity.h" -#include "../../world/level/chunk/ChunkSource.h" -#include "../../world/level/dimension/Dimension.h" -//#include "../../world/level/storage/MockedLevelStorage.h" +#include "world/Pos.hpp" +#include "world/level/Level.hpp" +//#include "network/packet/DisconnectPacket.hpp" +#include "world/entity/Entity.hpp" +#include "world/level/chunk/ChunkSource.hpp" +#include "world/level/dimension/Dimension.hpp" +//#include "world/level/storage/MockedLevelStorage.hpp" #include #include diff --git a/src/client/particle/BreakingItemParticle.h b/src/client/particle/BreakingItemParticle.hpp similarity index 90% rename from src/client/particle/BreakingItemParticle.h rename to src/client/particle/BreakingItemParticle.hpp index 1951641..d3ed473 100755 --- a/src/client/particle/BreakingItemParticle.h +++ b/src/client/particle/BreakingItemParticle.hpp @@ -2,11 +2,11 @@ //package net.minecraft.client.particle; -#include "Particle.h" -#include "../renderer/Tesselator.h" -#include "../../world/item/Item.h" -#include "../../world/level/Level.h" -#include "../../world/level/tile/Tile.h" +#include "Particle.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" class BreakingItemParticle: public Particle { diff --git a/src/client/particle/BubbleParticle.h b/src/client/particle/BubbleParticle.hpp similarity index 88% rename from src/client/particle/BubbleParticle.h rename to src/client/particle/BubbleParticle.hpp index 2508d22..5623d3c 100755 --- a/src/client/particle/BubbleParticle.h +++ b/src/client/particle/BubbleParticle.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.particle; -#include "../../util/Mth.h" -#include "../../world/level/Level.h" -#include "../../world/level/material/Material.h" -#include "Particle.h" +#include "util/Mth.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "Particle.hpp" class BubbleParticle: public Particle { diff --git a/src/client/particle/CritParticle2.h b/src/client/particle/CritParticle2.hpp similarity index 89% rename from src/client/particle/CritParticle2.h rename to src/client/particle/CritParticle2.hpp index 4f1444a..09baea7 100755 --- a/src/client/particle/CritParticle2.h +++ b/src/client/particle/CritParticle2.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.particle; -#include "Particle.h" -#include "../../util/Mth.h" -#include "../../world/level/Level.h" -#include "../../world/level/material/Material.h" +#include "Particle.hpp" +#include "util/Mth.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" class CritParticle2: public Particle { diff --git a/src/client/particle/ExplodeParticle.h b/src/client/particle/ExplodeParticle.hpp similarity index 91% rename from src/client/particle/ExplodeParticle.h rename to src/client/particle/ExplodeParticle.hpp index dce0272..83828e1 100755 --- a/src/client/particle/ExplodeParticle.h +++ b/src/client/particle/ExplodeParticle.hpp @@ -2,9 +2,9 @@ //package net.minecraft.client.particle; -#include "Particle.h" -#include "../renderer/Tesselator.h" -#include "../../world/level/Level.h" +#include "Particle.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/level/Level.hpp" class ExplodeParticle: public Particle { diff --git a/src/client/particle/FlameParticle.h b/src/client/particle/FlameParticle.hpp similarity index 94% rename from src/client/particle/FlameParticle.h rename to src/client/particle/FlameParticle.hpp index aefd61c..84bed33 100755 --- a/src/client/particle/FlameParticle.h +++ b/src/client/particle/FlameParticle.hpp @@ -2,9 +2,9 @@ //package net.minecraft.client.particle; -#include "Particle.h" -#include "../renderer/Tesselator.h" -#include "../../world/level/Level.h" +#include "Particle.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/level/Level.hpp" class FlameParticle: public Particle { diff --git a/src/client/particle/HugeExplosionParticle.h b/src/client/particle/HugeExplosionParticle.hpp similarity index 94% rename from src/client/particle/HugeExplosionParticle.h rename to src/client/particle/HugeExplosionParticle.hpp index 4225ee0..8808391 100755 --- a/src/client/particle/HugeExplosionParticle.h +++ b/src/client/particle/HugeExplosionParticle.hpp @@ -2,9 +2,9 @@ //package net.minecraft.client.particle; -#include "../renderer/Tesselator.h" -#include "../renderer/Textures.h" -#include "../../world/level/Level.h" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "world/level/Level.hpp" class HugeExplosionParticle: public Particle { diff --git a/src/client/particle/HugeExplosionSeedParticle.h b/src/client/particle/HugeExplosionSeedParticle.hpp similarity index 97% rename from src/client/particle/HugeExplosionSeedParticle.h rename to src/client/particle/HugeExplosionSeedParticle.hpp index 15f30c3..acd194b 100755 --- a/src/client/particle/HugeExplosionSeedParticle.h +++ b/src/client/particle/HugeExplosionSeedParticle.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.particle; -#include "Particle.h" +#include "Particle.hpp" class HugeExplosionSeedParticle: public Particle { diff --git a/src/client/particle/LavaParticle.h b/src/client/particle/LavaParticle.hpp similarity index 94% rename from src/client/particle/LavaParticle.h rename to src/client/particle/LavaParticle.hpp index 6ed2ee1..24390c5 100755 --- a/src/client/particle/LavaParticle.h +++ b/src/client/particle/LavaParticle.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.particle; -#include "../renderer/Tesselator.h" -#include "../../world/level/Level.h" +#include "client/renderer/Tesselator.hpp" +#include "world/level/Level.hpp" class LavaParticle: public Particle { diff --git a/src/client/particle/Particle.cpp b/src/client/particle/Particle.cpp index 2a31e2a..88dae90 100755 --- a/src/client/particle/Particle.cpp +++ b/src/client/particle/Particle.cpp @@ -1,99 +1,99 @@ -#include "Particle.h" - -float - Particle::xOff = 0, - Particle::yOff = 0, - Particle::zOff = 0; - -Particle::Particle( Level* level, float x, float y, float z, float xa, float ya, float za ) -: super(level), - age(0), - gravity(0), - rCol(1), gCol(1), bCol(1), - tex(0) -{ - setSize(0.2f, 0.2f); - heightOffset = bbHeight / 2.0f; - setPos(x, y, z); - - xd = xa + (float) (Mth::random() * 2 - 1) * 0.4f; - yd = ya + (float) (Mth::random() * 2 - 1) * 0.4f; - zd = za + (float) (Mth::random() * 2 - 1) * 0.4f; - float speed = (float) (Mth::random() + Mth::random() + 1) * 0.15f; - - float dd = (float) (Mth::sqrt(xd * xd + yd * yd + zd * zd)); - const float mul = 0.4f * speed / dd; - xd = xd * mul; - yd = yd * mul + 0.1f; - zd = zd * mul; - - uo = sharedRandom.nextFloat() * 3; - vo = sharedRandom.nextFloat() * 3; - - size = (sharedRandom.nextFloat() * 0.5f + 0.5f) * 2; - - lifetime = (int) (4.0f / (sharedRandom.nextFloat() * 0.9f + 0.1f)); - makeStepSound = false; -} - -Particle* Particle::setPower( float power ) -{ - xd *= power; - yd = (yd - 0.1f) * power + 0.1f; - zd *= power; - return this; -} - -Particle* Particle::scale( float scale ) -{ - setSize(0.2f * scale, 0.2f * scale); - size *= scale; - return this; -} - -void Particle::tick() -{ - xo = x; - yo = y; - zo = z; - - if (age++ >= lifetime) remove(); - - yd -= 0.04f * gravity; - move(xd, yd, zd); - xd *= 0.98f; - yd *= 0.98f; - zd *= 0.98f; - - if (onGround) { - xd *= 0.7f; - zd *= 0.7f; - } -} - -void Particle::render( Tesselator& t, float a, float xa, float ya, float za, float xa2, float za2 ) -{ - float u0 = (tex % 16) / 16.0f; - float u1 = u0 + 0.999f / 16.0f; - float v0 = (tex / 16) / 16.0f; - float v1 = v0 + 0.999f / 16.0f; - float r = 0.1f * size; - - float x = (float) (xo + (this->x - xo) * a - xOff); - float y = (float) (yo + (this->y - yo) * a - yOff); - float z = (float) (zo + (this->z - zo) * a - zOff); - - float br = getBrightness(a); - t.color(rCol * br, gCol * br, bCol * br); - - t.vertexUV(x - xa * r - xa2 * r, y - ya * r, z - za * r - za2 * r, u1, v1); - t.vertexUV(x - xa * r + xa2 * r, y + ya * r, z - za * r + za2 * r, u1, v0); - t.vertexUV(x + xa * r + xa2 * r, y + ya * r, z + za * r + za2 * r, u0, v0); - t.vertexUV(x + xa * r - xa2 * r, y - ya * r, z + za * r - za2 * r, u0, v1); - //printf("uv: %f, %f, %f, %f\n", u0, v0, u1, v1); -} - -int Particle::getParticleTexture() -{ - return ParticleEngine::MISC_TEXTURE; -} +#include "Particle.hpp" + +float + Particle::xOff = 0, + Particle::yOff = 0, + Particle::zOff = 0; + +Particle::Particle( Level* level, float x, float y, float z, float xa, float ya, float za ) +: super(level), + age(0), + gravity(0), + rCol(1), gCol(1), bCol(1), + tex(0) +{ + setSize(0.2f, 0.2f); + heightOffset = bbHeight / 2.0f; + setPos(x, y, z); + + xd = xa + (float) (Mth::random() * 2 - 1) * 0.4f; + yd = ya + (float) (Mth::random() * 2 - 1) * 0.4f; + zd = za + (float) (Mth::random() * 2 - 1) * 0.4f; + float speed = (float) (Mth::random() + Mth::random() + 1) * 0.15f; + + float dd = (float) (Mth::sqrt(xd * xd + yd * yd + zd * zd)); + const float mul = 0.4f * speed / dd; + xd = xd * mul; + yd = yd * mul + 0.1f; + zd = zd * mul; + + uo = sharedRandom.nextFloat() * 3; + vo = sharedRandom.nextFloat() * 3; + + size = (sharedRandom.nextFloat() * 0.5f + 0.5f) * 2; + + lifetime = (int) (4.0f / (sharedRandom.nextFloat() * 0.9f + 0.1f)); + makeStepSound = false; +} + +Particle* Particle::setPower( float power ) +{ + xd *= power; + yd = (yd - 0.1f) * power + 0.1f; + zd *= power; + return this; +} + +Particle* Particle::scale( float scale ) +{ + setSize(0.2f * scale, 0.2f * scale); + size *= scale; + return this; +} + +void Particle::tick() +{ + xo = x; + yo = y; + zo = z; + + if (age++ >= lifetime) remove(); + + yd -= 0.04f * gravity; + move(xd, yd, zd); + xd *= 0.98f; + yd *= 0.98f; + zd *= 0.98f; + + if (onGround) { + xd *= 0.7f; + zd *= 0.7f; + } +} + +void Particle::render( Tesselator& t, float a, float xa, float ya, float za, float xa2, float za2 ) +{ + float u0 = (tex % 16) / 16.0f; + float u1 = u0 + 0.999f / 16.0f; + float v0 = (tex / 16) / 16.0f; + float v1 = v0 + 0.999f / 16.0f; + float r = 0.1f * size; + + float x = (float) (xo + (this->x - xo) * a - xOff); + float y = (float) (yo + (this->y - yo) * a - yOff); + float z = (float) (zo + (this->z - zo) * a - zOff); + + float br = getBrightness(a); + t.color(rCol * br, gCol * br, bCol * br); + + t.vertexUV(x - xa * r - xa2 * r, y - ya * r, z - za * r - za2 * r, u1, v1); + t.vertexUV(x - xa * r + xa2 * r, y + ya * r, z - za * r + za2 * r, u1, v0); + t.vertexUV(x + xa * r + xa2 * r, y + ya * r, z + za * r + za2 * r, u0, v0); + t.vertexUV(x + xa * r - xa2 * r, y - ya * r, z + za * r - za2 * r, u0, v1); + //printf("uv: %f, %f, %f, %f\n", u0, v0, u1, v1); +} + +int Particle::getParticleTexture() +{ + return ParticleEngine::MISC_TEXTURE; +} diff --git a/src/client/particle/Particle.h b/src/client/particle/Particle.hpp similarity index 85% rename from src/client/particle/Particle.h rename to src/client/particle/Particle.hpp index 1c71339..98030a5 100755 --- a/src/client/particle/Particle.h +++ b/src/client/particle/Particle.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.particle; -#include "../renderer/Tesselator.h" -#include "../../world/entity/Entity.h" -#include "../../world/level/Level.h" -#include "ParticleEngine.h" +#include "client/renderer/Tesselator.hpp" +#include "world/entity/Entity.hpp" +#include "world/level/Level.hpp" +#include "ParticleEngine.hpp" class CompoundTag; diff --git a/src/client/particle/ParticleEngine.cpp b/src/client/particle/ParticleEngine.cpp index 725b1da..5912008 100755 --- a/src/client/particle/ParticleEngine.cpp +++ b/src/client/particle/ParticleEngine.cpp @@ -1,157 +1,157 @@ -#include "ParticleEngine.h" -#include "Particle.h" -#include "TerrainParticle.h" -#include "../renderer/Textures.h" -#include "../../world/level/Level.h" -#include "../../NinecraftApp.h" - -ParticleEngine::ParticleEngine(Level* level, Textures* textures) -: level(level), - textures(textures) -{ - textures->loadTexture("particles.png"); -} - -ParticleEngine::~ParticleEngine() { - clear(); -} - -void ParticleEngine::add(Particle* p) { - int t = p->getParticleTexture(); - particles[t].push_back(p); -} - -void ParticleEngine::tick() { - for (int tt = 0; tt < TEXTURE_COUNT; tt++) { - ParticleList& list = particles[tt]; - unsigned int size = list.size(); - for (unsigned int i = 0; i < size; ++i) { - Particle* p = list[i]; - p->tick(); - if (p->removed) { - list.erase(list.begin() + (i--)); - --size; - delete p; - } - } - } -} - -void ParticleEngine::render(Entity* player, float a) { - float xa = (float) Mth::cos(player->yRot * Mth::PI / 180); - float za = (float) Mth::sin(player->yRot * Mth::PI / 180); - - float xa2 = -za * (float) Mth::sin(player->xRot * Mth::PI / 180); - float za2 = xa * (float) Mth::sin(player->xRot * Mth::PI / 180); - float ya = (float) Mth::cos(player->xRot * Mth::PI / 180); - - Particle::xOff = (player->xOld+(player->x-player->xOld)*a); - Particle::yOff = (player->yOld+(player->y-player->yOld)*a); - Particle::zOff = (player->zOld+(player->z-player->zOld)*a); - for (int tt = 0; tt < 3; tt++) { - if (particles[tt].size() == 0) continue; - - if (tt == MISC_TEXTURE) - textures->loadAndBindTexture("particles.png"); - else if (tt == TERRAIN_TEXTURE) - textures->loadAndBindTexture("terrain.png"); - else if (tt == ITEM_TEXTURE) - textures->loadAndBindTexture("gui/items.png"); - - Tesselator& t = Tesselator::instance; - t.begin(); - for (unsigned int i = 0; i < particles[tt].size(); i++) { - Particle* p = particles[tt][i]; - - p->render(t, a, xa, ya, za, xa2, za2); - } - t.draw(); - } - - renderLit(player, a); -} - -void ParticleEngine::renderLit(Entity* player, float a) { - int tt = ENTITY_PARTICLE_TEXTURE; - ParticleList& pl = particles[tt]; - const int size = pl.size(); - if (size == 0) return; - - float xa = Mth::cos(player->yRot * Mth::DEGRAD); - float za = Mth::sin(player->yRot * Mth::DEGRAD); - - float xs = Mth::sin(player->xRot * Mth::DEGRAD); - float xa2 = -za * xs; - float za2 = xa * xs; - float ya = Mth::cos(player->xRot * Mth::DEGRAD); - - Tesselator& t = Tesselator::instance; - for (int i = 0; i < size; i++) { - Particle* p = pl[i]; - p->render(t, a, xa, ya, za, xa2, za2); - } -} - -void ParticleEngine::setLevel(Level* level) { - this->level = level; - clear(); -} - -void ParticleEngine::destroy(int x, int y, int z) { - int tid = level->getTile(x, y, z); - if (tid == 0) return; - int data = level->getData(x, y, z); - - //static Stopwatch sw; - //sw.start(); - Tile* tile = Tile::tiles[tid]; - const int SD = 3; - for (int xx = 0; xx < SD; xx++) - for (int yy = 1; yy < SD; yy++) - for (int zz = 0; zz < SD; zz++) { - float xp = x + (xx + 0.5f) / SD; - float yp = y + (yy + 0.5f) / SD; - float zp = z + (zz + 0.5f) / SD; - add((new TerrainParticle(level, xp, yp, zp, 2*(xp - x - 0.5f), 2*(yp - y - 0.5f), 2*(zp - z - 0.5f), tile, data))->init(x, y, z)); - } - //sw.stop(); - //sw.print("gen destroy particles: "); -} - -void ParticleEngine::crack(int x, int y, int z, int face) { - int tid = level->getTile(x, y, z); - if (tid == 0) return; - int data = level->getData(x, y, z); - Tile* tile = Tile::tiles[tid]; - float r = 0.10f; - float xp = x + random.nextFloat() * ((tile->xx1 - tile->xx0) - r * 2) + r + tile->xx0; - float yp = y + random.nextFloat() * ((tile->yy1 - tile->yy0) - r * 2) + r + tile->yy0; - float zp = z + random.nextFloat() * ((tile->zz1 - tile->zz0) - r * 2) + r + tile->zz0; - switch (face) { - case 0: yp = y + tile->yy0 - r; break; - case 1: yp = y + tile->yy1 + r; break; - case 2: zp = z + tile->zz0 - r; break; - case 3: zp = z + tile->zz1 + r; break; - case 4: xp = x + tile->xx0 - r; break; - case 5: xp = x + tile->xx1 + r; break; - } - add((new TerrainParticle(level, xp, yp, zp, 0, 0, 0, tile, data))->init(x, y, z)->setPower(0.2f)->scale(0.6f)); -} - -std::string ParticleEngine::countParticles() { - std::stringstream ss; - int count = 0; - for (int i = 0; i < TEXTURE_COUNT; ++i) - count += particles[i].size(); - ss << count; - return ss.str(); -} - -void ParticleEngine::clear() -{ - for (int tt = 0; tt < TEXTURE_COUNT; tt++) { - for (unsigned int i = 0; i < particles[tt].size(); i++) - delete particles[tt][i]; - particles[tt].clear(); - } -} +#include "ParticleEngine.hpp" +#include "Particle.hpp" +#include "TerrainParticle.hpp" +#include "client/renderer/Textures.hpp" +#include "world/level/Level.hpp" +#include "NinecraftApp.hpp" + +ParticleEngine::ParticleEngine(Level* level, Textures* textures) +: level(level), + textures(textures) +{ + textures->loadTexture("particles.png"); +} + +ParticleEngine::~ParticleEngine() { + clear(); +} + +void ParticleEngine::add(Particle* p) { + int t = p->getParticleTexture(); + particles[t].push_back(p); +} + +void ParticleEngine::tick() { + for (int tt = 0; tt < TEXTURE_COUNT; tt++) { + ParticleList& list = particles[tt]; + unsigned int size = list.size(); + for (unsigned int i = 0; i < size; ++i) { + Particle* p = list[i]; + p->tick(); + if (p->removed) { + list.erase(list.begin() + (i--)); + --size; + delete p; + } + } + } +} + +void ParticleEngine::render(Entity* player, float a) { + float xa = (float) Mth::cos(player->yRot * Mth::PI / 180); + float za = (float) Mth::sin(player->yRot * Mth::PI / 180); + + float xa2 = -za * (float) Mth::sin(player->xRot * Mth::PI / 180); + float za2 = xa * (float) Mth::sin(player->xRot * Mth::PI / 180); + float ya = (float) Mth::cos(player->xRot * Mth::PI / 180); + + Particle::xOff = (player->xOld+(player->x-player->xOld)*a); + Particle::yOff = (player->yOld+(player->y-player->yOld)*a); + Particle::zOff = (player->zOld+(player->z-player->zOld)*a); + for (int tt = 0; tt < 3; tt++) { + if (particles[tt].size() == 0) continue; + + if (tt == MISC_TEXTURE) + textures->loadAndBindTexture("particles.png"); + else if (tt == TERRAIN_TEXTURE) + textures->loadAndBindTexture("terrain.png"); + else if (tt == ITEM_TEXTURE) + textures->loadAndBindTexture("gui/items.png"); + + Tesselator& t = Tesselator::instance; + t.begin(); + for (unsigned int i = 0; i < particles[tt].size(); i++) { + Particle* p = particles[tt][i]; + + p->render(t, a, xa, ya, za, xa2, za2); + } + t.draw(); + } + + renderLit(player, a); +} + +void ParticleEngine::renderLit(Entity* player, float a) { + int tt = ENTITY_PARTICLE_TEXTURE; + ParticleList& pl = particles[tt]; + const int size = pl.size(); + if (size == 0) return; + + float xa = Mth::cos(player->yRot * Mth::DEGRAD); + float za = Mth::sin(player->yRot * Mth::DEGRAD); + + float xs = Mth::sin(player->xRot * Mth::DEGRAD); + float xa2 = -za * xs; + float za2 = xa * xs; + float ya = Mth::cos(player->xRot * Mth::DEGRAD); + + Tesselator& t = Tesselator::instance; + for (int i = 0; i < size; i++) { + Particle* p = pl[i]; + p->render(t, a, xa, ya, za, xa2, za2); + } +} + +void ParticleEngine::setLevel(Level* level) { + this->level = level; + clear(); +} + +void ParticleEngine::destroy(int x, int y, int z) { + int tid = level->getTile(x, y, z); + if (tid == 0) return; + int data = level->getData(x, y, z); + + //static Stopwatch sw; + //sw.start(); + Tile* tile = Tile::tiles[tid]; + const int SD = 3; + for (int xx = 0; xx < SD; xx++) + for (int yy = 1; yy < SD; yy++) + for (int zz = 0; zz < SD; zz++) { + float xp = x + (xx + 0.5f) / SD; + float yp = y + (yy + 0.5f) / SD; + float zp = z + (zz + 0.5f) / SD; + add((new TerrainParticle(level, xp, yp, zp, 2*(xp - x - 0.5f), 2*(yp - y - 0.5f), 2*(zp - z - 0.5f), tile, data))->init(x, y, z)); + } + //sw.stop(); + //sw.print("gen destroy particles: "); +} + +void ParticleEngine::crack(int x, int y, int z, int face) { + int tid = level->getTile(x, y, z); + if (tid == 0) return; + int data = level->getData(x, y, z); + Tile* tile = Tile::tiles[tid]; + float r = 0.10f; + float xp = x + random.nextFloat() * ((tile->xx1 - tile->xx0) - r * 2) + r + tile->xx0; + float yp = y + random.nextFloat() * ((tile->yy1 - tile->yy0) - r * 2) + r + tile->yy0; + float zp = z + random.nextFloat() * ((tile->zz1 - tile->zz0) - r * 2) + r + tile->zz0; + switch (face) { + case 0: yp = y + tile->yy0 - r; break; + case 1: yp = y + tile->yy1 + r; break; + case 2: zp = z + tile->zz0 - r; break; + case 3: zp = z + tile->zz1 + r; break; + case 4: xp = x + tile->xx0 - r; break; + case 5: xp = x + tile->xx1 + r; break; + } + add((new TerrainParticle(level, xp, yp, zp, 0, 0, 0, tile, data))->init(x, y, z)->setPower(0.2f)->scale(0.6f)); +} + +std::string ParticleEngine::countParticles() { + std::stringstream ss; + int count = 0; + for (int i = 0; i < TEXTURE_COUNT; ++i) + count += particles[i].size(); + ss << count; + return ss.str(); +} + +void ParticleEngine::clear() +{ + for (int tt = 0; tt < TEXTURE_COUNT; tt++) { + for (unsigned int i = 0; i < particles[tt].size(); i++) + delete particles[tt][i]; + particles[tt].clear(); + } +} diff --git a/src/client/particle/ParticleEngine.h b/src/client/particle/ParticleEngine.hpp similarity index 89% rename from src/client/particle/ParticleEngine.h rename to src/client/particle/ParticleEngine.hpp index afb5c03..3c96c0d 100755 --- a/src/client/particle/ParticleEngine.h +++ b/src/client/particle/ParticleEngine.hpp @@ -3,9 +3,9 @@ //package net.minecraft.client.particle; #include -#include "../../world/entity/Entity.h" -#include "../../world/level/tile/Tile.h" -#include "../renderer/gles.h" +#include "world/entity/Entity.hpp" +#include "world/level/tile/Tile.hpp" +#include "client/renderer/gles.hpp" class Textures; class Level; diff --git a/src/client/particle/ParticleInclude.h b/src/client/particle/ParticleInclude.h deleted file mode 100755 index 61702be..0000000 --- a/src/client/particle/ParticleInclude.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include "Particle.h" - -#include "BubbleParticle.h" -#include "CritParticle2.h" -#include "ExplodeParticle.h" -#include "FlameParticle.h" -#include "LavaParticle.h" -#include "RedDustParticle.h" -#include "SmokeParticle.h" -#include "TerrainParticle.h" -#include "HugeExplosionSeedParticle.h" -#include "HugeExplosionParticle.h" - diff --git a/src/client/particle/ParticleInclude.hpp b/src/client/particle/ParticleInclude.hpp new file mode 100755 index 0000000..cb8bf81 --- /dev/null +++ b/src/client/particle/ParticleInclude.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "Particle.hpp" + +#include "BubbleParticle.hpp" +#include "CritParticle2.hpp" +#include "ExplodeParticle.hpp" +#include "FlameParticle.hpp" +#include "LavaParticle.hpp" +#include "RedDustParticle.hpp" +#include "SmokeParticle.hpp" +#include "TerrainParticle.hpp" +#include "HugeExplosionSeedParticle.hpp" +#include "HugeExplosionParticle.hpp" + diff --git a/src/client/particle/RedDustParticle.h b/src/client/particle/RedDustParticle.hpp similarity index 95% rename from src/client/particle/RedDustParticle.h rename to src/client/particle/RedDustParticle.hpp index 9c4278c..df5bd29 100755 --- a/src/client/particle/RedDustParticle.h +++ b/src/client/particle/RedDustParticle.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.particle; -#include "../renderer/Tesselator.h" -#include "../../world/level/Level.h" +#include "client/renderer/Tesselator.hpp" +#include "world/level/Level.hpp" class RedDustParticle: public Particle diff --git a/src/client/particle/SmokeParticle.h b/src/client/particle/SmokeParticle.hpp similarity index 98% rename from src/client/particle/SmokeParticle.h rename to src/client/particle/SmokeParticle.hpp index 5f1ccc6..10ddd82 100755 --- a/src/client/particle/SmokeParticle.h +++ b/src/client/particle/SmokeParticle.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.particle; -#include "Particle.h" +#include "Particle.hpp" class SmokeParticle: public Particle { diff --git a/src/client/particle/SplashParticle.h b/src/client/particle/SplashParticle.hpp similarity index 86% rename from src/client/particle/SplashParticle.h rename to src/client/particle/SplashParticle.hpp index 2a9444c..b0d4dfc 100755 --- a/src/client/particle/SplashParticle.h +++ b/src/client/particle/SplashParticle.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.particle; -#include "WaterDropParticle.h" -#include "../../world/level/Level.h" +#include "WaterDropParticle.hpp" +#include "world/level/Level.hpp" class SplashParticle: public WaterDropParticle { diff --git a/src/client/particle/TakeAnimationParticle.h b/src/client/particle/TakeAnimationParticle.hpp similarity index 87% rename from src/client/particle/TakeAnimationParticle.h rename to src/client/particle/TakeAnimationParticle.hpp index 62fa70e..a3b8279 100755 --- a/src/client/particle/TakeAnimationParticle.h +++ b/src/client/particle/TakeAnimationParticle.hpp @@ -2,14 +2,14 @@ //package net.minecraft.client.particle; -#include "Particle.h" +#include "Particle.hpp" -#include "../renderer/entity/EntityRenderDispatcher.h" -#include "../renderer/Tesselator.h" -#include "../../world/entity/Entity.h" -#include "../../world/level/Level.h" -#include "../../util/Mth.h" -#include "../../world/entity/item/ItemEntity.h" +#include "client/renderer/entity/EntityRenderDispatcher.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/entity/Entity.hpp" +#include "world/level/Level.hpp" +#include "util/Mth.hpp" +#include "world/entity/item/ItemEntity.hpp" class TakeAnimationParticle: public Particle { diff --git a/src/client/particle/TerrainParticle.h b/src/client/particle/TerrainParticle.hpp similarity index 91% rename from src/client/particle/TerrainParticle.h rename to src/client/particle/TerrainParticle.hpp index 98da959..92b50be 100755 --- a/src/client/particle/TerrainParticle.h +++ b/src/client/particle/TerrainParticle.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.particle; -#include "../renderer/Tesselator.h" -#include "../../world/level/Level.h" -#include "../../world/level/tile/Tile.h" -#include "../../world/level/tile/GrassTile.h" +#include "client/renderer/Tesselator.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/GrassTile.hpp" class TerrainParticle: public Particle { diff --git a/src/client/player/LocalPlayer.cpp b/src/client/player/LocalPlayer.cpp index caea946..8b92280 100755 --- a/src/client/player/LocalPlayer.cpp +++ b/src/client/player/LocalPlayer.cpp @@ -1,825 +1,825 @@ -#include "LocalPlayer.h" -#include -#include "../../world/entity/EntityEvent.h" -#include "../../world/entity/player/Player.h" -#include "../../world/inventory/BaseContainerMenu.h" -#include "../../world/item/BowItem.h" -#include "../../world/level/Level.h" -#include "../../world/level/tile/Tile.h" -#include "../../world/level/tile/entity/TileEntity.h" -#include "../../world/level/material/Material.h" -#include "../../network/packet/ContainerClosePacket.h" -#include "../../network/packet/MovePlayerPacket.h" -#include "../../network/packet/PlayerEquipmentPacket.h" -#include "../../network/RakNetInstance.h" -#include "../../network/packet/DropItemPacket.h" -#include "../../network/packet/SetHealthPacket.h" -#include "../../network/packet/SendInventoryPacket.h" -#include "../../network/packet/EntityEventPacket.h" -#include "../../network/packet/PlayerActionPacket.h" -#include -#include -#include "../../platform/log.h" -#include "../../platform/HttpClient.h" -#include "../../platform/CThread.h" -#include "../../util/StringUtils.h" -#include "client/Options.h" - -#if defined(_WIN32) -#include -#include -#else -#include -#include -#include -#endif - - -#include "../gui/Screen.h" -#include "../gui/screens/FurnaceScreen.h" -#include "../gui/screens/ChestScreen.h" -#include "../gui/screens/crafting/WorkbenchScreen.h" -#include "../gui/screens/crafting/StonecutterScreen.h" -#include "../gui/screens/InBedScreen.h" -#include "../gui/screens/TextEditScreen.h" -#include "../particle/TakeAnimationParticle.h" -#include "../../network/packet/AnimatePacket.h" -#include "../../world/item/ArmorItem.h" -#include "../../network/packet/PlayerArmorEquipmentPacket.h" -#include - -namespace { - - -static bool isBase64(unsigned char c) { - return (std::isalnum(c) || (c == '+') || (c == '/')); -} - -static std::string base64Decode(const std::string& encoded) { - static const std::string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - std::string out; - int in_len = (int)encoded.size(); - int i = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - - while (in_len-- && (encoded[in_] != '=') && isBase64(encoded[in_])) { - char_array_4[i++] = encoded[in_]; in_++; - if (i == 4) { - for (i = 0; i < 4; i++) - char_array_4[i] = (unsigned char)base64Chars.find(char_array_4[i]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (i = 0; i < 3; i++) - out += char_array_3[i]; - i = 0; - } - } - - if (i) { - for (int j = i; j < 4; j++) - char_array_4[j] = 0; - for (int j = 0; j < 4; j++) - char_array_4[j] = (unsigned char)base64Chars.find(char_array_4[j]); - - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - - for (int j = 0; (j < i - 1); j++) - out += char_array_3[j]; - } - return out; -} - -static std::string extractJsonString(const std::string& json, const std::string& key) { - std::string search = "\"" + key + "\""; - size_t pos = json.find(search); - if (pos == std::string::npos) return ""; - pos = json.find(':', pos + search.size()); - if (pos == std::string::npos) return ""; - pos++; - while (pos < json.size() && std::isspace((unsigned char)json[pos])) pos++; - if (pos >= json.size() || json[pos] != '"') return ""; - pos++; - size_t end = json.find('"', pos); - if (end == std::string::npos) return ""; - return json.substr(pos, end - pos); -} - -static std::string getTextureUrlForUsername(const std::string& username, const std::string& textureKey) { - if (username.empty()) { - LOGI("[%s] username empty\n", textureKey.c_str()); - return ""; - } - - LOGI("[%s] resolving UUID for user '%s'...\n", textureKey.c_str(), username.c_str()); - std::vector body; - std::string apiUrl = "http://api.mojang.com/users/profiles/minecraft/" + username; - if (!HttpClient::download(apiUrl, body)) { - LOGW("[%s] failed to download UUID for %s\n", textureKey.c_str(), username.c_str()); - return ""; - } - - std::string response(body.begin(), body.end()); - std::string uuid = extractJsonString(response, "id"); - if (uuid.empty()) { - LOGW("[%s] no UUID found in Mojang response for %s\n", textureKey.c_str(), username.c_str()); - return ""; - } - - LOGI("[%s] UUID=%s for user %s\n", textureKey.c_str(), uuid.c_str(), username.c_str()); - - std::string profileUrl = "http://sessionserver.mojang.com/session/minecraft/profile/" + uuid; - if (!HttpClient::download(profileUrl, body)) { - LOGW("[%s] failed to download profile for UUID %s\n", textureKey.c_str(), uuid.c_str()); - return ""; - } - - response.assign(body.begin(), body.end()); - std::string encoded = extractJsonString(response, "value"); - if (encoded.empty()) { - LOGW("[%s] no value field in profile response for UUID %s\n", textureKey.c_str(), uuid.c_str()); - return ""; - } - - std::string decoded = base64Decode(encoded); - - std::string searchKey = "\"" + textureKey + "\""; - size_t texturePos = decoded.find(searchKey); - if (texturePos == std::string::npos) { - LOGW("[%s] no %s entry in decoded profile for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str()); - return ""; - } - size_t urlPos = decoded.find("\"url\"", texturePos); - if (urlPos == std::string::npos) { - LOGW("[%s] no url field under %s for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str()); - return ""; - } - - // extract the URL value from the substring starting at urlPos - std::string urlFragment = decoded.substr(urlPos); - std::string textureUrl = extractJsonString(urlFragment, "url"); - if (textureUrl.empty()) { - LOGW("[%s] failed to parse %s URL for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str()); - return ""; - } - - LOGI("[%s] %s URL for %s: %s\n", textureKey.c_str(), textureKey.c_str(), username.c_str(), textureUrl.c_str()); - return textureUrl; -} - -static std::string getSkinUrlForUsername(const std::string& username) { - return getTextureUrlForUsername(username, "SKIN"); -} - -static std::string getCapeUrlForUsername(const std::string& username) { - return getTextureUrlForUsername(username, "CAPE"); -} - -#endif - -static bool ensureDirectoryExists(const std::string& path) { -#if defined(_WIN32) - return _mkdir(path.c_str()) == 0 || errno == EEXIST; -#else - struct stat st; - if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) - return true; - - std::string subPath; - size_t i = 0; - while (i < path.length()) { - i = path.find_first_of("/\\", i); - if (i == std::string::npos) { - subPath = path; - } else { - subPath = path.substr(0, i); - } - - if (!subPath.empty()) { - if (stat(subPath.c_str(), &st) != 0) { - if (mkdir(subPath.c_str(), 0755) != 0 && errno != EEXIST) - return false; - } else if (!S_ISDIR(st.st_mode)) { - return false; - } - } - - if (i == std::string::npos) - break; - i += 1; - } - - if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) - return true; - return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST; -#endif -} - -static bool fileExists(const std::string& path) { - struct stat st; - if (stat(path.c_str(), &st) != 0) - return false; - -#if defined(_WIN32) - return (st.st_mode & _S_IFREG) != 0; -#else - return S_ISREG(st.st_mode); -#endif -} - - - -static void* fetchSkinForPlayer(void* param) { - LocalPlayer* player = (LocalPlayer*)param; - if (!player) return NULL; - - LOGI("[Skin] starting skin download for %s\n", player->name.c_str()); - - const std::string cacheDir = "data/images/skins"; - if (!ensureDirectoryExists(cacheDir)) { - LOGW("[Skin] failed to create cache directory %s\n", cacheDir.c_str()); - } - - std::string cacheFile = cacheDir + "/" + player->name + ".png"; - if (fileExists(cacheFile)) { - LOGI("[Skin] using cached skin for %s\n", player->name.c_str()); - player->setTextureName("skins/" + player->name + ".png"); - return NULL; - } - - std::string skinUrl = getSkinUrlForUsername(player->name); - if (skinUrl.empty()) { - LOGW("[Skin] skin URL lookup failed for %s\n", player->name.c_str()); - player->setTextureName("mob/char.png"); - return NULL; - } - - LOGI("[Skin] downloading skin from %s\n", skinUrl.c_str()); - std::vector skinData; - if (!HttpClient::download(skinUrl, skinData) || skinData.empty()) { - LOGW("[Skin] download failed for %s\n", skinUrl.c_str()); - player->setTextureName("mob/char.png"); - return NULL; - } - - // Save to cache - FILE* fp = fopen(cacheFile.c_str(), "wb"); - if (fp) { - fwrite(skinData.data(), 1, skinData.size(), fp); - fclose(fp); - LOGI("[Skin] cached skin to %s\n", cacheFile.c_str()); - - player->setTextureName("skins/" + player->name + ".png"); - } else { - LOGW("[Skin] failed to write skin cache %s\n", cacheFile.c_str()); - player->setTextureName("mob/char.png"); - } - - return NULL; -} - -static void* fetchCapeForPlayer(void* param) { - LocalPlayer* player = (LocalPlayer*)param; - if (!player) return NULL; - - LOGI("[Cape] starting cape download for %s\n", player->name.c_str()); - - const std::string cacheDir = "data/images/capes"; - if (!ensureDirectoryExists(cacheDir)) { - LOGW("[Cape] failed to create cache directory %s\n", cacheDir.c_str()); - } - - std::string cacheFile = cacheDir + "/" + player->name + ".png"; - if (fileExists(cacheFile)) { - LOGI("[Cape] using cached cape for %s\n", player->name.c_str()); - player->setCapeTextureName("capes/" + player->name + ".png"); - return NULL; - } - - std::string capeUrl = getCapeUrlForUsername(player->name); - if (capeUrl.empty()) { - LOGW("[Cape] cape URL lookup failed for %s\n", player->name.c_str()); - return NULL; - } - - LOGI("[Cape] downloading cape from %s\n", capeUrl.c_str()); - std::vector capeData; - if (!HttpClient::download(capeUrl, capeData) || capeData.empty()) { - LOGW("[Cape] download failed for %s\n", capeUrl.c_str()); - return NULL; - } - - // Save to cache - FILE* fp = fopen(cacheFile.c_str(), "wb"); - if (fp) { - fwrite(capeData.data(), 1, capeData.size(), fp); - fclose(fp); - LOGI("[Cape] cached cape to %s\n", cacheFile.c_str()); - - player->setCapeTextureName("capes/" + player->name + ".png"); - } else { - LOGW("[Cape] failed to write cape cache %s\n", cacheFile.c_str()); - } - - return NULL; -} - -#endif - -//@note: doesn't work completely, since it doesn't care about stairs rotation -static bool isJumpable(int tileId) { - return tileId != Tile::fence->id - && tileId != Tile::fenceGate->id - && tileId != Tile::stoneSlabHalf->id - && tileId != Tile::trapdoor->id - && tileId != Tile::sign->id - && tileId != Tile::wallSign->id - && (Tile::tiles[tileId] != NULL && Tile::tiles[tileId]->getRenderShape() != Tile::SHAPE_STAIRS); -} - -} // anonymous namespace - -LocalPlayer::LocalPlayer(MinecraftClient& minecraft, Level* level, const std::string& username, int dimension, bool isCreative) -: Player(level, isCreative), minecraft(minecraft) { - this->dimension = dimension; - _init(); - - if (minecraft.options().getStringValue(OPTIONS_USERNAME).size() != 0) { - textureName = "mob/char.png"; - - this->name = minecraft.options().getStringValue(OPTIONS_USERNAME); - printf("test \n"); - // Fetch user skin and cape from Mojang servers in the background (avoids blocking the main thread) - // TODO: Fix this memory leak - new CThread(fetchSkinForPlayer, this); - new CThread(fetchCapeForPlayer, this); - } -} - -LocalPlayer::~LocalPlayer() { - //delete input; - //input = NULL; -} - -/*private*/ -void LocalPlayer::calculateFlight(float xa, float ya, float za) { - float flySpeed = minecraft.options().getProgressValue(OPTIONS_FLY_SPEED); - float sensivity = minecraft.options().getProgressValue(OPTIONS_SENSITIVITY); - - xa = xa * flySpeed; - ya = 0; - za = za * flySpeed; - - if (sprinting) { - float sprintBoost = getWalkingSpeedModifier(); // 1.3x - xa *= sprintBoost; - za *= sprintBoost; - } - -#ifdef ANDROID - if (Keyboard::isKeyDown(103)) ya = .2f * flySpeed; - if (Keyboard::isKeyDown(102)) ya = -.2f * flySpeed; -#else - if (Keyboard::isKeyDown(Keyboard::KEY_E)) ya = .2f * flySpeed; - if (Keyboard::isKeyDown(Keyboard::KEY_Q)) ya = -.2f * flySpeed; -#endif - - flyX = 10 * smoothFlyX.getNewDeltaValue(xa, .35f * sensivity); - flyY = 10 * smoothFlyY.getNewDeltaValue(ya, .35f * sensivity); - flyZ = 10 * smoothFlyZ.getNewDeltaValue(za, .35f * sensivity); -} - -bool LocalPlayer::isSolidTile(int x, int y, int z) { - int tileId = level->getTile(x, y, z); - return tileId > 0 && Tile::tiles[tileId]->material->isSolid(); -} - -void LocalPlayer::tick() { - - super::tick(); - if(!useItem.isNull()) { - ItemInstance* item = inventory->getSelected(); - if(item != NULL && *item == useItem) { - if (useItemDuration <= 25 && useItemDuration % 4 == 0) { - spawnEatParticles(item, 5); - } - if(--useItemDuration == 0) { - if(!level->isClientSide) { - completeUsingItem(); - } else { - EntityEventPacket p(entityId, EntityEvent::USE_ITEM_COMPLETE); - level->raknetInstance->send(p); - } - } - } - else { - stopUsingItem(); - } - } - if (minecraft.isOnline()) - { - if (std::abs(x - sentX) > .1f || std::abs(y - sentY) > .01f || std::abs(z - sentZ) > .1f || std::abs(sentRotX - xRot) > 1 || std::abs(sentRotY - yRot) > 1) - { - MovePlayerPacket packet(entityId, x, y - heightOffset, z, xRot, yRot); - minecraft.raknetInstance->send(packet); - sentX = x; - sentY = y; - sentZ = z; - sentRotX = xRot; - sentRotY = yRot; - } - - ItemInstance* item = inventory->getSelected(); - int newItemId = (item && item->count > 0) ? item->id : 0; - int newItemData = (item && item->count > 0) ? item->getAuxValue() : 0; - - if (sentInventoryItemId != newItemId - || sentInventoryItemData != newItemData) - { - sentInventoryItemId = newItemId; - sentInventoryItemData = newItemData; - PlayerEquipmentPacket packet(entityId, newItemId, newItemData); - minecraft.raknetInstance->send(packet); - } - } -/* - for (int i = 0; i < 4; ++i) { - ItemInstance* a = getArmor(i); - if (!a) continue; - - ArmorItem* item = (ArmorItem*) a->getItem(); - - printf("armor %d: %d\n", i, a->getAuxValue()); - } -*/ - - updateArmorTypeHash(); - if (!minecraft.getScreen() && containerMenu) { - static bool hasPostedError = false; - if (!hasPostedError) { - // @todo - // minecraft.gui().postError( ErrorCodes::ContainerRefStillExistsAfterDestruction ); - hasPostedError = true; - } - } - //LOGI("biome: %s\n", level->getBiomeSource()->getBiome((int)x >> 4, (int)z >> 4)->name.c_str()); -} - -/*public*/ -void LocalPlayer::aiStep() { - jumpTriggerTime--; - ascendTriggerTime--; - descendTriggerTime--; - - bool wasJumping = input->jumping; - bool screenCovering = minecraft.getScreen() && !minecraft.getScreen()->passEvents; - if (!screenCovering) - input->tick(this); - - // Sprint: detect W double-tap - { - bool forwardHeld = (input->ya > 0); - if (forwardHeld && !prevForwardHeld && minecraft.options().getBooleanValue(OPTIONS_ALLOW_SPRINT)) { - // leading edge of W press - if (sprintDoubleTapTimer > 0) - sprinting = true; - else - sprintDoubleTapTimer = 7; - } - if (!forwardHeld) { - sprinting = false; - } - if (sprintDoubleTapTimer > 0) sprintDoubleTapTimer--; - prevForwardHeld = forwardHeld; - } - if (input->sneaking) - sprinting = false; - - if (input->sneaking) { - if (ySlideOffset < 0.2f) ySlideOffset = 0.2f; - } - - if (abilities.mayfly) { - // Check for flight toggle - if (!wasJumping && input->jumping) { - if (jumpTriggerTime <= 0) jumpTriggerTime = 7; - else { - abilities.flying = !abilities.flying; - jumpTriggerTime = 0; - } - } - if (abilities.flying) { - if (input->wantUp) { - yd += 0.15f; - //xd = zd = 0; - } - if (input->wantDown) { - yd -= 0.15f; - } - } - } - - if(isUsingItem()) { - const float k = 0.35f; - input->xa *= k; - input->ya *= k; - } - - Mob::aiStep(); - super::aiStep(); - - //if (onGround && abilities.flying) - // abilities.flying = false; - - if (interpolateOnly()) - updateAi(); -} - -/*public*/ -void LocalPlayer::closeContainer() { - if (level->isClientSide) { - ContainerClosePacket packet(containerMenu->containerId); - minecraft.raknetInstance->send(packet); - } - super::closeContainer(); - minecraft.setScreen(NULL); -} - -//@Override -void LocalPlayer::move(float xa, float ya, float za) { - //@note: why is this == minecraft.player needed? - if (this == minecraft.getPlayer() && minecraft.options().getBooleanValue(OPTIONS_IS_FLYING)) { - noPhysics = true; - float tmp = walkDist; // update - calculateFlight((float) xa, (float) ya, (float) za); - fallDistance = 0; - yd = 0; - super::move(flyX, flyY, flyZ); - onGround = true; - walkDist = tmp; - } else { - if (autoJumpTime > 0) { - autoJumpTime--; - input->jumping = true; - } - float prevX = x, prevZ = z; - - super::move(xa, ya, za); - - float newX = x, newZ = z; - - if (autoJumpTime <= 0 && minecraft.options().getBooleanValue(OPTIONS_AUTOJUMP)) - { - // auto-jump when crossing the middle of a tile, and the tile in the front is blocked - bool jump = false; - if (Mth::floor(prevX * 2.0f) != Mth::floor(newX * 2.0f) || Mth::floor(prevZ * 2.0f) != Mth::floor(newZ * 2.0f)) - { - float dist = Mth::sqrt(xa * xa + za * za); - const int xx = Mth::floor(x + xa / dist); - const int zz = Mth::floor(z + za / dist); - const int tileId = level->getTile(xx, (int)(y-1), zz); - jump = (isSolidTile(xx, (int)(y-1), zz) // Solid block to jump up on - && !isSolidTile(xx, (int)y, zz) && !isSolidTile(xx, (int)(y+1), zz)) // Enough space - && isJumpable(tileId); - } - if (jump) - { - autoJumpTime = 1; - } - } - } -} - -void LocalPlayer::updateAi() { - super::updateAi(); - this->xxa = input->xa; - this->yya = input->ya; - this->jumping = input->jumping || autoJumpTime > 0; -} - -void LocalPlayer::take( Entity* e, int orgCount ) { - if (e->isItemEntity()) - minecraft.getParticleEngine()->add(new TakeAnimationParticle(minecraft.level, (ItemEntity*)e, this, -0.5f)); -} - -void LocalPlayer::setKey( int eventKey, bool eventKeyState ) -{ - input->setKey(eventKey, eventKeyState); -} - -void LocalPlayer::releaseAllKeys() -{ - if (input) input->releaseAllKeys(); -} - -float LocalPlayer::getWalkingSpeedModifier() { - return sprinting ? 1.3f : 1.0f; -} - -float LocalPlayer::getFieldOfViewModifier() { - float targetFov = 1.0f; - if(abilities.flying) targetFov *= 1.1f; - targetFov *= ((walkingSpeed * getWalkingSpeedModifier()) / DEFAULT_WALK_SPEED +1) / 2; - - if(isUsingItem() && getUseItem()->id == Item::bow->id) { - float ticksHeld = (float)getTicksUsingItem(); - float scale = ticksHeld / BowItem::MAX_DRAW_DURATION; - if(scale > 1) { - scale = 1; - } - else { - scale *= scale; - } - targetFov *= 1.0f - scale * 0.15f; - } - return targetFov; -} -void LocalPlayer::addAdditonalSaveData( CompoundTag* entityTag ) -{ - super::addAdditonalSaveData(entityTag); - entityTag->putInt("Score", score); -} - -void LocalPlayer::readAdditionalSaveData( CompoundTag* entityTag ) -{ - super::readAdditionalSaveData(entityTag); - score = entityTag->getInt("Score"); -} - -bool LocalPlayer::isSneaking() -{ - return input->sneaking; -} - -void LocalPlayer::hurtTo( int newHealth ) -{ - int dmg = health - newHealth; - if (dmg <= 0) { - this->health = newHealth; - } else { - lastHurt = dmg; - lastHealth = health; - invulnerableTime = invulnerableDuration; - - minecraft.getPlayer()->bypassArmor = true; - actuallyHurt(dmg); - minecraft.getPlayer()->bypassArmor = false; - - hurtTime = hurtDuration = 10; - } -} - -void LocalPlayer::actuallyHurt( int dmg ) { - if (minecraft.getScreen() && minecraft.getScreen()->closeOnPlayerHurt()) { - if (containerMenu) closeContainer(); - else minecraft.setScreen(NULL); - } - - super::actuallyHurt(dmg); -} - -void LocalPlayer::respawn() { - minecraft.respawnPlayer(); -} - -void LocalPlayer::die(Entity* source) -{ - // If we're an online client, send the inventory to be dropped - // If we're the server, drop the inventory immediately - if (level->isClientSide) { - SendInventoryPacket packet(this, true); - minecraft.raknetInstance->send(packet); - } - inventory->dropAll(level->isClientSide); - for (int i = 0; i < NUM_ARMOR; ++i) { - ItemInstance* item = getArmor(i); - if (!ItemInstance::isArmorItem(item)) return; - - drop(new ItemInstance(*item), true); - setArmor(i, NULL); - } - - super::die(source); -} - -void LocalPlayer::swing() { - super::swing(); - - if (swingTime == -1) { - AnimatePacket packet(AnimatePacket::Swing, this); - packet.reliability = UNRELIABLE; - packet.priority = MEDIUM_PRIORITY; - minecraft.raknetInstance->send(packet); - } -} - -void LocalPlayer::reset() { - super::reset(); - this->_init(); -} - -void LocalPlayer::_init() { - autoJumpTime = 0; - jumpTriggerTime = 0; - ascendTriggerTime = 0; - descendTriggerTime = 0; - ascending = false; - descending = false; - - ItemInstance* item = inventory->getSelected(); - sentInventoryItemId = item? item->id : 0; - sentInventoryItemData = item? item->getAuxValue() : 0; -} - -void LocalPlayer::startCrafting(int x, int y, int z, int tableSize) { - if (!minecraft.isCreativeMode()) - minecraft.setScreen( new WorkbenchScreen(tableSize) ); -} - -void LocalPlayer::startStonecutting(int x, int y, int z) { - if (!minecraft.isCreativeMode()) - minecraft.setScreen( new StonecutterScreen() ); -} - -void LocalPlayer::openFurnace( FurnaceTileEntity* e ) { - if (!minecraft.isCreativeMode()) - minecraft.setScreen( new FurnaceScreen(this, e) ); -} - -void LocalPlayer::openContainer( ChestTileEntity* container ) { - if (!minecraft.isCreativeMode()) - minecraft.setScreen( new ChestScreen(this, container) ); -} - -void LocalPlayer::drop( ItemInstance* item, bool randomly ) -{ - if (!item) - return; - - if (level->isClientSide) { - DropItemPacket packet(entityId, *item); - minecraft.raknetInstance->send(packet); - // delete the ItemEntity here, since we don't add it to level - delete item; - } else { - super::drop(item, randomly); - } -} - -void LocalPlayer::causeFallDamage( float distance ) -{ - int dmg = (int) ceil((distance - 3)); - if (dmg > 0) { - if (level->isClientSide) { - SetHealthPacket packet(SetHealthPacket::HEALTH_MODIFY_OFFSET + dmg); - minecraft.raknetInstance->send(packet); - } - } - super::causeFallDamage(distance); - -} - -void LocalPlayer::displayClientMessage( const std::string& messageId ) { - minecraft.gui().displayClientMessage(messageId); -} - -int LocalPlayer::startSleepInBed( int x, int y, int z ) { - int startSleepInBedReturnValue = super::startSleepInBed(x, y, z); - - if(startSleepInBedReturnValue == BedSleepingResult::OK) - minecraft.setScreen(new InBedScreen()); - - return startSleepInBedReturnValue; -} - -void LocalPlayer::stopSleepInBed( bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint ) { - if(level->isClientSide) { - PlayerActionPacket packet(PlayerActionPacket::STOP_SLEEPING, 0, 0, 0, 0, entityId); - minecraft.raknetInstance->send(packet); - } - - minecraft.setScreen(NULL); - - super::stopSleepInBed(forcefulWakeUp, updateLevelList, saveRespawnPoint); -} - -void LocalPlayer::openTextEdit( TileEntity* tileEntity ) { -#if !defined(RPI) - if(tileEntity->type == TileEntityType::Sign) - minecraft.setScreen(new TextEditScreen((SignTileEntity*) tileEntity)); -#endif -} - -void LocalPlayer::updateArmorTypeHash() { - int hash = getArmorTypeHash(); - if (hash != armorTypeHash) { - PlayerArmorEquipmentPacket p(this); - minecraft.raknetInstance->send(p); - armorTypeHash = hash; - } -} +#include "LocalPlayer.hpp" +#include +#include "world/entity/EntityEvent.hpp" +#include "world/entity/player/Player.hpp" +#include "world/inventory/BaseContainerMenu.hpp" +#include "world/item/BowItem.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/entity/TileEntity.hpp" +#include "world/level/material/Material.hpp" +#include "network/packet/ContainerClosePacket.hpp" +#include "network/packet/MovePlayerPacket.hpp" +#include "network/packet/PlayerEquipmentPacket.hpp" +#include "network/RakNetInstance.hpp" +#include "network/packet/DropItemPacket.hpp" +#include "network/packet/SetHealthPacket.hpp" +#include "network/packet/SendInventoryPacket.hpp" +#include "network/packet/EntityEventPacket.hpp" +#include "network/packet/PlayerActionPacket.hpp" +#include +#include +#include "platform/log.hpp" +#include "platform/HttpClient.hpp" +#include "platform/CThread.hpp" +#include "util/StringUtils.hpp" +#include "client/Options.hpp" + +#if defined(_WIN32) +#include +#include +#else +#include +#include +#include +#endif + + +#include "client/gui/Screen.hpp" +#include "client/gui/screens/FurnaceScreen.hpp" +#include "client/gui/screens/ChestScreen.hpp" +#include "client/gui/screens/crafting/WorkbenchScreen.hpp" +#include "client/gui/screens/crafting/StonecutterScreen.hpp" +#include "client/gui/screens/InBedScreen.hpp" +#include "client/gui/screens/TextEditScreen.hpp" +#include "client/particle/TakeAnimationParticle.hpp" +#include "network/packet/AnimatePacket.hpp" +#include "world/item/ArmorItem.hpp" +#include "network/packet/PlayerArmorEquipmentPacket.hpp" +#include + +namespace { + + +static bool isBase64(unsigned char c) { + return (std::isalnum(c) || (c == '+') || (c == '/')); +} + +static std::string base64Decode(const std::string& encoded) { + static const std::string base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + std::string out; + int in_len = (int)encoded.size(); + int i = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + + while (in_len-- && (encoded[in_] != '=') && isBase64(encoded[in_])) { + char_array_4[i++] = encoded[in_]; in_++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = (unsigned char)base64Chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; i < 3; i++) + out += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (int j = i; j < 4; j++) + char_array_4[j] = 0; + for (int j = 0; j < 4; j++) + char_array_4[j] = (unsigned char)base64Chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (int j = 0; (j < i - 1); j++) + out += char_array_3[j]; + } + return out; +} + +static std::string extractJsonString(const std::string& json, const std::string& key) { + std::string search = "\"" + key + "\""; + size_t pos = json.find(search); + if (pos == std::string::npos) return ""; + pos = json.find(':', pos + search.size()); + if (pos == std::string::npos) return ""; + pos++; + while (pos < json.size() && std::isspace((unsigned char)json[pos])) pos++; + if (pos >= json.size() || json[pos] != '"') return ""; + pos++; + size_t end = json.find('"', pos); + if (end == std::string::npos) return ""; + return json.substr(pos, end - pos); +} + +static std::string getTextureUrlForUsername(const std::string& username, const std::string& textureKey) { + if (username.empty()) { + LOGI("[%s] username empty\n", textureKey.c_str()); + return ""; + } + + LOGI("[%s] resolving UUID for user '%s'...\n", textureKey.c_str(), username.c_str()); + std::vector body; + std::string apiUrl = "http://api.mojang.com/users/profiles/minecraft/" + username; + if (!HttpClient::download(apiUrl, body)) { + LOGW("[%s] failed to download UUID for %s\n", textureKey.c_str(), username.c_str()); + return ""; + } + + std::string response(body.begin(), body.end()); + std::string uuid = extractJsonString(response, "id"); + if (uuid.empty()) { + LOGW("[%s] no UUID found in Mojang response for %s\n", textureKey.c_str(), username.c_str()); + return ""; + } + + LOGI("[%s] UUID=%s for user %s\n", textureKey.c_str(), uuid.c_str(), username.c_str()); + + std::string profileUrl = "http://sessionserver.mojang.com/session/minecraft/profile/" + uuid; + if (!HttpClient::download(profileUrl, body)) { + LOGW("[%s] failed to download profile for UUID %s\n", textureKey.c_str(), uuid.c_str()); + return ""; + } + + response.assign(body.begin(), body.end()); + std::string encoded = extractJsonString(response, "value"); + if (encoded.empty()) { + LOGW("[%s] no value field in profile response for UUID %s\n", textureKey.c_str(), uuid.c_str()); + return ""; + } + + std::string decoded = base64Decode(encoded); + + std::string searchKey = "\"" + textureKey + "\""; + size_t texturePos = decoded.find(searchKey); + if (texturePos == std::string::npos) { + LOGW("[%s] no %s entry in decoded profile for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str()); + return ""; + } + size_t urlPos = decoded.find("\"url\"", texturePos); + if (urlPos == std::string::npos) { + LOGW("[%s] no url field under %s for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str()); + return ""; + } + + // extract the URL value from the substring starting at urlPos + std::string urlFragment = decoded.substr(urlPos); + std::string textureUrl = extractJsonString(urlFragment, "url"); + if (textureUrl.empty()) { + LOGW("[%s] failed to parse %s URL for UUID %s\n", textureKey.c_str(), textureKey.c_str(), uuid.c_str()); + return ""; + } + + LOGI("[%s] %s URL for %s: %s\n", textureKey.c_str(), textureKey.c_str(), username.c_str(), textureUrl.c_str()); + return textureUrl; +} + +static std::string getSkinUrlForUsername(const std::string& username) { + return getTextureUrlForUsername(username, "SKIN"); +} + +static std::string getCapeUrlForUsername(const std::string& username) { + return getTextureUrlForUsername(username, "CAPE"); +} + +#endif + +static bool ensureDirectoryExists(const std::string& path) { +#if defined(_WIN32) + return _mkdir(path.c_str()) == 0 || errno == EEXIST; +#else + struct stat st; + if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) + return true; + + std::string subPath; + size_t i = 0; + while (i < path.length()) { + i = path.find_first_of("/\\", i); + if (i == std::string::npos) { + subPath = path; + } else { + subPath = path.substr(0, i); + } + + if (!subPath.empty()) { + if (stat(subPath.c_str(), &st) != 0) { + if (mkdir(subPath.c_str(), 0755) != 0 && errno != EEXIST) + return false; + } else if (!S_ISDIR(st.st_mode)) { + return false; + } + } + + if (i == std::string::npos) + break; + i += 1; + } + + if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) + return true; + return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST; +#endif +} + +static bool fileExists(const std::string& path) { + struct stat st; + if (stat(path.c_str(), &st) != 0) + return false; + +#if defined(_WIN32) + return (st.st_mode & _S_IFREG) != 0; +#else + return S_ISREG(st.st_mode); +#endif +} + + + +static void* fetchSkinForPlayer(void* param) { + LocalPlayer* player = (LocalPlayer*)param; + if (!player) return NULL; + + LOGI("[Skin] starting skin download for %s\n", player->name.c_str()); + + const std::string cacheDir = "data/images/skins"; + if (!ensureDirectoryExists(cacheDir)) { + LOGW("[Skin] failed to create cache directory %s\n", cacheDir.c_str()); + } + + std::string cacheFile = cacheDir + "/" + player->name + ".png"; + if (fileExists(cacheFile)) { + LOGI("[Skin] using cached skin for %s\n", player->name.c_str()); + player->setTextureName("skins/" + player->name + ".png"); + return NULL; + } + + std::string skinUrl = getSkinUrlForUsername(player->name); + if (skinUrl.empty()) { + LOGW("[Skin] skin URL lookup failed for %s\n", player->name.c_str()); + player->setTextureName("mob/char.png"); + return NULL; + } + + LOGI("[Skin] downloading skin from %s\n", skinUrl.c_str()); + std::vector skinData; + if (!HttpClient::download(skinUrl, skinData) || skinData.empty()) { + LOGW("[Skin] download failed for %s\n", skinUrl.c_str()); + player->setTextureName("mob/char.png"); + return NULL; + } + + // Save to cache + FILE* fp = fopen(cacheFile.c_str(), "wb"); + if (fp) { + fwrite(skinData.data(), 1, skinData.size(), fp); + fclose(fp); + LOGI("[Skin] cached skin to %s\n", cacheFile.c_str()); + + player->setTextureName("skins/" + player->name + ".png"); + } else { + LOGW("[Skin] failed to write skin cache %s\n", cacheFile.c_str()); + player->setTextureName("mob/char.png"); + } + + return NULL; +} + +static void* fetchCapeForPlayer(void* param) { + LocalPlayer* player = (LocalPlayer*)param; + if (!player) return NULL; + + LOGI("[Cape] starting cape download for %s\n", player->name.c_str()); + + const std::string cacheDir = "data/images/capes"; + if (!ensureDirectoryExists(cacheDir)) { + LOGW("[Cape] failed to create cache directory %s\n", cacheDir.c_str()); + } + + std::string cacheFile = cacheDir + "/" + player->name + ".png"; + if (fileExists(cacheFile)) { + LOGI("[Cape] using cached cape for %s\n", player->name.c_str()); + player->setCapeTextureName("capes/" + player->name + ".png"); + return NULL; + } + + std::string capeUrl = getCapeUrlForUsername(player->name); + if (capeUrl.empty()) { + LOGW("[Cape] cape URL lookup failed for %s\n", player->name.c_str()); + return NULL; + } + + LOGI("[Cape] downloading cape from %s\n", capeUrl.c_str()); + std::vector capeData; + if (!HttpClient::download(capeUrl, capeData) || capeData.empty()) { + LOGW("[Cape] download failed for %s\n", capeUrl.c_str()); + return NULL; + } + + // Save to cache + FILE* fp = fopen(cacheFile.c_str(), "wb"); + if (fp) { + fwrite(capeData.data(), 1, capeData.size(), fp); + fclose(fp); + LOGI("[Cape] cached cape to %s\n", cacheFile.c_str()); + + player->setCapeTextureName("capes/" + player->name + ".png"); + } else { + LOGW("[Cape] failed to write cape cache %s\n", cacheFile.c_str()); + } + + return NULL; +} + +#endif + +//@note: doesn't work completely, since it doesn't care about stairs rotation +static bool isJumpable(int tileId) { + return tileId != Tile::fence->id + && tileId != Tile::fenceGate->id + && tileId != Tile::stoneSlabHalf->id + && tileId != Tile::trapdoor->id + && tileId != Tile::sign->id + && tileId != Tile::wallSign->id + && (Tile::tiles[tileId] != NULL && Tile::tiles[tileId]->getRenderShape() != Tile::SHAPE_STAIRS); +} + +} // anonymous namespace + +LocalPlayer::LocalPlayer(MinecraftClient& minecraft, Level* level, const std::string& username, int dimension, bool isCreative) +: Player(level, isCreative), minecraft(minecraft) { + this->dimension = dimension; + _init(); + + if (minecraft.options().getStringValue(OPTIONS_USERNAME).size() != 0) { + textureName = "mob/char.png"; + + this->name = minecraft.options().getStringValue(OPTIONS_USERNAME); + printf("test \n"); + // Fetch user skin and cape from Mojang servers in the background (avoids blocking the main thread) + // TODO: Fix this memory leak + new CThread(fetchSkinForPlayer, this); + new CThread(fetchCapeForPlayer, this); + } +} + +LocalPlayer::~LocalPlayer() { + //delete input; + //input = NULL; +} + +/*private*/ +void LocalPlayer::calculateFlight(float xa, float ya, float za) { + float flySpeed = minecraft.options().getProgressValue(OPTIONS_FLY_SPEED); + float sensivity = minecraft.options().getProgressValue(OPTIONS_SENSITIVITY); + + xa = xa * flySpeed; + ya = 0; + za = za * flySpeed; + + if (sprinting) { + float sprintBoost = getWalkingSpeedModifier(); // 1.3x + xa *= sprintBoost; + za *= sprintBoost; + } + +#ifdef ANDROID + if (Keyboard::isKeyDown(103)) ya = .2f * flySpeed; + if (Keyboard::isKeyDown(102)) ya = -.2f * flySpeed; +#else + if (Keyboard::isKeyDown(Keyboard::KEY_E)) ya = .2f * flySpeed; + if (Keyboard::isKeyDown(Keyboard::KEY_Q)) ya = -.2f * flySpeed; +#endif + + flyX = 10 * smoothFlyX.getNewDeltaValue(xa, .35f * sensivity); + flyY = 10 * smoothFlyY.getNewDeltaValue(ya, .35f * sensivity); + flyZ = 10 * smoothFlyZ.getNewDeltaValue(za, .35f * sensivity); +} + +bool LocalPlayer::isSolidTile(int x, int y, int z) { + int tileId = level->getTile(x, y, z); + return tileId > 0 && Tile::tiles[tileId]->material->isSolid(); +} + +void LocalPlayer::tick() { + + super::tick(); + if(!useItem.isNull()) { + ItemInstance* item = inventory->getSelected(); + if(item != NULL && *item == useItem) { + if (useItemDuration <= 25 && useItemDuration % 4 == 0) { + spawnEatParticles(item, 5); + } + if(--useItemDuration == 0) { + if(!level->isClientSide) { + completeUsingItem(); + } else { + EntityEventPacket p(entityId, EntityEvent::USE_ITEM_COMPLETE); + level->raknetInstance->send(p); + } + } + } + else { + stopUsingItem(); + } + } + if (minecraft.isOnline()) + { + if (std::abs(x - sentX) > .1f || std::abs(y - sentY) > .01f || std::abs(z - sentZ) > .1f || std::abs(sentRotX - xRot) > 1 || std::abs(sentRotY - yRot) > 1) + { + MovePlayerPacket packet(entityId, x, y - heightOffset, z, xRot, yRot); + minecraft.raknetInstance->send(packet); + sentX = x; + sentY = y; + sentZ = z; + sentRotX = xRot; + sentRotY = yRot; + } + + ItemInstance* item = inventory->getSelected(); + int newItemId = (item && item->count > 0) ? item->id : 0; + int newItemData = (item && item->count > 0) ? item->getAuxValue() : 0; + + if (sentInventoryItemId != newItemId + || sentInventoryItemData != newItemData) + { + sentInventoryItemId = newItemId; + sentInventoryItemData = newItemData; + PlayerEquipmentPacket packet(entityId, newItemId, newItemData); + minecraft.raknetInstance->send(packet); + } + } +/* + for (int i = 0; i < 4; ++i) { + ItemInstance* a = getArmor(i); + if (!a) continue; + + ArmorItem* item = (ArmorItem*) a->getItem(); + + printf("armor %d: %d\n", i, a->getAuxValue()); + } +*/ + + updateArmorTypeHash(); + if (!minecraft.getScreen() && containerMenu) { + static bool hasPostedError = false; + if (!hasPostedError) { + // @todo + // minecraft.gui().postError( ErrorCodes::ContainerRefStillExistsAfterDestruction ); + hasPostedError = true; + } + } + //LOGI("biome: %s\n", level->getBiomeSource()->getBiome((int)x >> 4, (int)z >> 4)->name.c_str()); +} + +/*public*/ +void LocalPlayer::aiStep() { + jumpTriggerTime--; + ascendTriggerTime--; + descendTriggerTime--; + + bool wasJumping = input->jumping; + bool screenCovering = minecraft.getScreen() && !minecraft.getScreen()->passEvents; + if (!screenCovering) + input->tick(this); + + // Sprint: detect W double-tap + { + bool forwardHeld = (input->ya > 0); + if (forwardHeld && !prevForwardHeld && minecraft.options().getBooleanValue(OPTIONS_ALLOW_SPRINT)) { + // leading edge of W press + if (sprintDoubleTapTimer > 0) + sprinting = true; + else + sprintDoubleTapTimer = 7; + } + if (!forwardHeld) { + sprinting = false; + } + if (sprintDoubleTapTimer > 0) sprintDoubleTapTimer--; + prevForwardHeld = forwardHeld; + } + if (input->sneaking) + sprinting = false; + + if (input->sneaking) { + if (ySlideOffset < 0.2f) ySlideOffset = 0.2f; + } + + if (abilities.mayfly) { + // Check for flight toggle + if (!wasJumping && input->jumping) { + if (jumpTriggerTime <= 0) jumpTriggerTime = 7; + else { + abilities.flying = !abilities.flying; + jumpTriggerTime = 0; + } + } + if (abilities.flying) { + if (input->wantUp) { + yd += 0.15f; + //xd = zd = 0; + } + if (input->wantDown) { + yd -= 0.15f; + } + } + } + + if(isUsingItem()) { + const float k = 0.35f; + input->xa *= k; + input->ya *= k; + } + + Mob::aiStep(); + super::aiStep(); + + //if (onGround && abilities.flying) + // abilities.flying = false; + + if (interpolateOnly()) + updateAi(); +} + +/*public*/ +void LocalPlayer::closeContainer() { + if (level->isClientSide) { + ContainerClosePacket packet(containerMenu->containerId); + minecraft.raknetInstance->send(packet); + } + super::closeContainer(); + minecraft.setScreen(NULL); +} + +//@Override +void LocalPlayer::move(float xa, float ya, float za) { + //@note: why is this == minecraft.player needed? + if (this == minecraft.getPlayer() && minecraft.options().getBooleanValue(OPTIONS_IS_FLYING)) { + noPhysics = true; + float tmp = walkDist; // update + calculateFlight((float) xa, (float) ya, (float) za); + fallDistance = 0; + yd = 0; + super::move(flyX, flyY, flyZ); + onGround = true; + walkDist = tmp; + } else { + if (autoJumpTime > 0) { + autoJumpTime--; + input->jumping = true; + } + float prevX = x, prevZ = z; + + super::move(xa, ya, za); + + float newX = x, newZ = z; + + if (autoJumpTime <= 0 && minecraft.options().getBooleanValue(OPTIONS_AUTOJUMP)) + { + // auto-jump when crossing the middle of a tile, and the tile in the front is blocked + bool jump = false; + if (Mth::floor(prevX * 2.0f) != Mth::floor(newX * 2.0f) || Mth::floor(prevZ * 2.0f) != Mth::floor(newZ * 2.0f)) + { + float dist = Mth::sqrt(xa * xa + za * za); + const int xx = Mth::floor(x + xa / dist); + const int zz = Mth::floor(z + za / dist); + const int tileId = level->getTile(xx, (int)(y-1), zz); + jump = (isSolidTile(xx, (int)(y-1), zz) // Solid block to jump up on + && !isSolidTile(xx, (int)y, zz) && !isSolidTile(xx, (int)(y+1), zz)) // Enough space + && isJumpable(tileId); + } + if (jump) + { + autoJumpTime = 1; + } + } + } +} + +void LocalPlayer::updateAi() { + super::updateAi(); + this->xxa = input->xa; + this->yya = input->ya; + this->jumping = input->jumping || autoJumpTime > 0; +} + +void LocalPlayer::take( Entity* e, int orgCount ) { + if (e->isItemEntity()) + minecraft.getParticleEngine()->add(new TakeAnimationParticle(minecraft.level, (ItemEntity*)e, this, -0.5f)); +} + +void LocalPlayer::setKey( int eventKey, bool eventKeyState ) +{ + input->setKey(eventKey, eventKeyState); +} + +void LocalPlayer::releaseAllKeys() +{ + if (input) input->releaseAllKeys(); +} + +float LocalPlayer::getWalkingSpeedModifier() { + return sprinting ? 1.3f : 1.0f; +} + +float LocalPlayer::getFieldOfViewModifier() { + float targetFov = 1.0f; + if(abilities.flying) targetFov *= 1.1f; + targetFov *= ((walkingSpeed * getWalkingSpeedModifier()) / DEFAULT_WALK_SPEED +1) / 2; + + if(isUsingItem() && getUseItem()->id == Item::bow->id) { + float ticksHeld = (float)getTicksUsingItem(); + float scale = ticksHeld / BowItem::MAX_DRAW_DURATION; + if(scale > 1) { + scale = 1; + } + else { + scale *= scale; + } + targetFov *= 1.0f - scale * 0.15f; + } + return targetFov; +} +void LocalPlayer::addAdditonalSaveData( CompoundTag* entityTag ) +{ + super::addAdditonalSaveData(entityTag); + entityTag->putInt("Score", score); +} + +void LocalPlayer::readAdditionalSaveData( CompoundTag* entityTag ) +{ + super::readAdditionalSaveData(entityTag); + score = entityTag->getInt("Score"); +} + +bool LocalPlayer::isSneaking() +{ + return input->sneaking; +} + +void LocalPlayer::hurtTo( int newHealth ) +{ + int dmg = health - newHealth; + if (dmg <= 0) { + this->health = newHealth; + } else { + lastHurt = dmg; + lastHealth = health; + invulnerableTime = invulnerableDuration; + + minecraft.getPlayer()->bypassArmor = true; + actuallyHurt(dmg); + minecraft.getPlayer()->bypassArmor = false; + + hurtTime = hurtDuration = 10; + } +} + +void LocalPlayer::actuallyHurt( int dmg ) { + if (minecraft.getScreen() && minecraft.getScreen()->closeOnPlayerHurt()) { + if (containerMenu) closeContainer(); + else minecraft.setScreen(NULL); + } + + super::actuallyHurt(dmg); +} + +void LocalPlayer::respawn() { + minecraft.respawnPlayer(); +} + +void LocalPlayer::die(Entity* source) +{ + // If we're an online client, send the inventory to be dropped + // If we're the server, drop the inventory immediately + if (level->isClientSide) { + SendInventoryPacket packet(this, true); + minecraft.raknetInstance->send(packet); + } + inventory->dropAll(level->isClientSide); + for (int i = 0; i < NUM_ARMOR; ++i) { + ItemInstance* item = getArmor(i); + if (!ItemInstance::isArmorItem(item)) return; + + drop(new ItemInstance(*item), true); + setArmor(i, NULL); + } + + super::die(source); +} + +void LocalPlayer::swing() { + super::swing(); + + if (swingTime == -1) { + AnimatePacket packet(AnimatePacket::Swing, this); + packet.reliability = UNRELIABLE; + packet.priority = MEDIUM_PRIORITY; + minecraft.raknetInstance->send(packet); + } +} + +void LocalPlayer::reset() { + super::reset(); + this->_init(); +} + +void LocalPlayer::_init() { + autoJumpTime = 0; + jumpTriggerTime = 0; + ascendTriggerTime = 0; + descendTriggerTime = 0; + ascending = false; + descending = false; + + ItemInstance* item = inventory->getSelected(); + sentInventoryItemId = item? item->id : 0; + sentInventoryItemData = item? item->getAuxValue() : 0; +} + +void LocalPlayer::startCrafting(int x, int y, int z, int tableSize) { + if (!minecraft.isCreativeMode()) + minecraft.setScreen( new WorkbenchScreen(tableSize) ); +} + +void LocalPlayer::startStonecutting(int x, int y, int z) { + if (!minecraft.isCreativeMode()) + minecraft.setScreen( new StonecutterScreen() ); +} + +void LocalPlayer::openFurnace( FurnaceTileEntity* e ) { + if (!minecraft.isCreativeMode()) + minecraft.setScreen( new FurnaceScreen(this, e) ); +} + +void LocalPlayer::openContainer( ChestTileEntity* container ) { + if (!minecraft.isCreativeMode()) + minecraft.setScreen( new ChestScreen(this, container) ); +} + +void LocalPlayer::drop( ItemInstance* item, bool randomly ) +{ + if (!item) + return; + + if (level->isClientSide) { + DropItemPacket packet(entityId, *item); + minecraft.raknetInstance->send(packet); + // delete the ItemEntity here, since we don't add it to level + delete item; + } else { + super::drop(item, randomly); + } +} + +void LocalPlayer::causeFallDamage( float distance ) +{ + int dmg = (int) ceil((distance - 3)); + if (dmg > 0) { + if (level->isClientSide) { + SetHealthPacket packet(SetHealthPacket::HEALTH_MODIFY_OFFSET + dmg); + minecraft.raknetInstance->send(packet); + } + } + super::causeFallDamage(distance); + +} + +void LocalPlayer::displayClientMessage( const std::string& messageId ) { + minecraft.gui().displayClientMessage(messageId); +} + +int LocalPlayer::startSleepInBed( int x, int y, int z ) { + int startSleepInBedReturnValue = super::startSleepInBed(x, y, z); + + if(startSleepInBedReturnValue == BedSleepingResult::OK) + minecraft.setScreen(new InBedScreen()); + + return startSleepInBedReturnValue; +} + +void LocalPlayer::stopSleepInBed( bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint ) { + if(level->isClientSide) { + PlayerActionPacket packet(PlayerActionPacket::STOP_SLEEPING, 0, 0, 0, 0, entityId); + minecraft.raknetInstance->send(packet); + } + + minecraft.setScreen(NULL); + + super::stopSleepInBed(forcefulWakeUp, updateLevelList, saveRespawnPoint); +} + +void LocalPlayer::openTextEdit( TileEntity* tileEntity ) { +#if !defined(RPI) + if(tileEntity->type == TileEntityType::Sign) + minecraft.setScreen(new TextEditScreen((SignTileEntity*) tileEntity)); +#endif +} + +void LocalPlayer::updateArmorTypeHash() { + int hash = getArmorTypeHash(); + if (hash != armorTypeHash) { + PlayerArmorEquipmentPacket p(this); + minecraft.raknetInstance->send(p); + armorTypeHash = hash; + } +} diff --git a/src/client/player/LocalPlayer.h b/src/client/player/LocalPlayer.hpp similarity index 95% rename from src/client/player/LocalPlayer.h rename to src/client/player/LocalPlayer.hpp index aba7053..131e003 100755 --- a/src/client/player/LocalPlayer.h +++ b/src/client/player/LocalPlayer.hpp @@ -2,9 +2,9 @@ //package net.minecraft.client.player; -#include "input/IMoveInput.h" -#include "../../util/SmoothFloat.h" -#include "../../world/entity/player/Player.h" +#include "input/IMoveInput.hpp" +#include "util/SmoothFloat.hpp" +#include "world/entity/player/Player.hpp" class MinecraftClient; class Stat; diff --git a/src/client/player/RemotePlayer.cpp b/src/client/player/RemotePlayer.cpp index 56b20d7..11759c7 100755 --- a/src/client/player/RemotePlayer.cpp +++ b/src/client/player/RemotePlayer.cpp @@ -1,35 +1,35 @@ -#include "RemotePlayer.h" -#include "../../world/entity/player/Inventory.h" -#include "../../world/entity/SharedFlags.h" - -RemotePlayer::RemotePlayer(Level* level, bool isCreative) -: Player(level, isCreative), - hasStartedUsingItem(false) -{ - hasFakeInventory = true; -} - -void RemotePlayer::tick() { - super::tick(); - - if (!hasStartedUsingItem && getSharedFlag(SharedFlagsInformation::FLAG_USINGITEM)) { - hasStartedUsingItem = true; - ItemInstance* instance = inventory->getItem(Inventory::MAX_SELECTION_SIZE); - if (instance) { - Item* item = Item::items[instance->id]; - if (item) { - startUsingItem(*instance, item->getUseDuration(instance)); - //LOGI("Start using item! %s\n", instance->getDescriptionId().c_str()); - } - } - } else if (hasStartedUsingItem && !getSharedFlag(SharedFlagsInformation::FLAG_USINGITEM)) { -// LOGI("Stop using item! %s\n", useItem.getDescriptionId().c_str()); - stopUsingItem(); - hasStartedUsingItem = false; - } -} - -void RemotePlayer::aiStep() { - updateAttackAnim(); - super::aiStep(); -} +#include "RemotePlayer.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/entity/SharedFlags.hpp" + +RemotePlayer::RemotePlayer(Level* level, bool isCreative) +: Player(level, isCreative), + hasStartedUsingItem(false) +{ + hasFakeInventory = true; +} + +void RemotePlayer::tick() { + super::tick(); + + if (!hasStartedUsingItem && getSharedFlag(SharedFlagsInformation::FLAG_USINGITEM)) { + hasStartedUsingItem = true; + ItemInstance* instance = inventory->getItem(Inventory::MAX_SELECTION_SIZE); + if (instance) { + Item* item = Item::items[instance->id]; + if (item) { + startUsingItem(*instance, item->getUseDuration(instance)); + //LOGI("Start using item! %s\n", instance->getDescriptionId().c_str()); + } + } + } else if (hasStartedUsingItem && !getSharedFlag(SharedFlagsInformation::FLAG_USINGITEM)) { +// LOGI("Stop using item! %s\n", useItem.getDescriptionId().c_str()); + stopUsingItem(); + hasStartedUsingItem = false; + } +} + +void RemotePlayer::aiStep() { + updateAttackAnim(); + super::aiStep(); +} diff --git a/src/client/player/RemotePlayer.h b/src/client/player/RemotePlayer.hpp similarity index 84% rename from src/client/player/RemotePlayer.h rename to src/client/player/RemotePlayer.hpp index 37bf407..9502dc6 100755 --- a/src/client/player/RemotePlayer.h +++ b/src/client/player/RemotePlayer.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.player; -#include "../../world/entity/player/Player.h" +#include "world/entity/player/Player.hpp" class Level; diff --git a/src/client/player/input/ControllerTurnInput.h b/src/client/player/input/ControllerTurnInput.hpp similarity index 95% rename from src/client/player/input/ControllerTurnInput.h rename to src/client/player/input/ControllerTurnInput.hpp index fc6694c..14bc604 100755 --- a/src/client/player/input/ControllerTurnInput.h +++ b/src/client/player/input/ControllerTurnInput.hpp @@ -1,7 +1,7 @@ #pragma once -#include "ITurnInput.h" -#include "../../../platform/input/Controller.h" +#include "ITurnInput.hpp" +#include "platform/input/Controller.hpp" /** A Controller Turn input */ class ControllerTurnInput : public ITurnInput { diff --git a/src/client/player/input/IBuildInput.h b/src/client/player/input/IBuildInput.hpp similarity index 96% rename from src/client/player/input/IBuildInput.h rename to src/client/player/input/IBuildInput.hpp index c228c71..b359fcd 100755 --- a/src/client/player/input/IBuildInput.h +++ b/src/client/player/input/IBuildInput.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../IConfigListener.h" +#include "client/IConfigListener.hpp" class Player; class BuildActionIntention { diff --git a/src/client/player/input/IInputHolder.h b/src/client/player/input/IInputHolder.hpp similarity index 91% rename from src/client/player/input/IInputHolder.h rename to src/client/player/input/IInputHolder.hpp index 9ae7d4c..fb82fe9 100755 --- a/src/client/player/input/IInputHolder.h +++ b/src/client/player/input/IInputHolder.hpp @@ -1,10 +1,10 @@ #pragma once -#include "IMoveInput.h" -#include "ITurnInput.h" -#include "IBuildInput.h" +#include "IMoveInput.hpp" +#include "ITurnInput.hpp" +#include "IBuildInput.hpp" -#include "../../../platform/input/Mouse.h" +#include "platform/input/Mouse.hpp" class Player; diff --git a/src/client/player/input/IMoveInput.h b/src/client/player/input/IMoveInput.hpp similarity index 94% rename from src/client/player/input/IMoveInput.h rename to src/client/player/input/IMoveInput.hpp index 359a65b..66b840e 100755 --- a/src/client/player/input/IMoveInput.h +++ b/src/client/player/input/IMoveInput.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.player; -#include "../../IConfigListener.h" +#include "client/IConfigListener.hpp" class Player; class Minecraft; diff --git a/src/client/player/input/ITurnInput.h b/src/client/player/input/ITurnInput.hpp similarity index 93% rename from src/client/player/input/ITurnInput.h rename to src/client/player/input/ITurnInput.hpp index 0db08d0..bf10c9d 100755 --- a/src/client/player/input/ITurnInput.h +++ b/src/client/player/input/ITurnInput.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../../../platform/time.h" -#include "../../IConfigListener.h" +#include "platform/time.hpp" +#include "client/IConfigListener.hpp" #include /** Representing a Turn delta value */ diff --git a/src/client/player/input/KeyboardInput.cpp b/src/client/player/input/KeyboardInput.cpp index b84fe75..4533cd8 100755 --- a/src/client/player/input/KeyboardInput.cpp +++ b/src/client/player/input/KeyboardInput.cpp @@ -1,61 +1,61 @@ -#include "KeyboardInput.h" -#include "../../Options.h" -#include "../../../world/entity/player/Player.h" - -KeyboardInput::KeyboardInput( Options* options ) -{ - for (int i = 0; i < NumKeys; ++i) - keys[i] = false; - this->options = options; -} - -void KeyboardInput::setKey( int key, bool state ) -{ - int id = -1; - if (key == options->getIntValue(OPTIONS_KEY_FORWARD)) id = KEY_UP; - if (key == options->getIntValue(OPTIONS_KEY_BACK)) id = KEY_DOWN; - if (key == options->getIntValue(OPTIONS_KEY_LEFT)) id = KEY_LEFT; - if (key == options->getIntValue(OPTIONS_KEY_RIGHT)) id = KEY_RIGHT; - if (key == options->getIntValue(OPTIONS_KEY_JUMP)) id = KEY_JUMP; - if (key == options->getIntValue(OPTIONS_KEY_SNEAK)) id = KEY_SNEAK; - if (id >= 0) { - keys[id] = state; - } -} - -void KeyboardInput::releaseAllKeys() -{ - xa = 0; - ya = 0; - - for (int i = 0; i < NumKeys; i++) { - keys[i] = false; - } - wantUp = wantDown = false; -} - -void KeyboardInput::tick( Player* player ) -{ - xa = 0; - ya = 0; - - if (keys[KEY_UP]) ya++; - if (keys[KEY_DOWN]) ya--; - if (keys[KEY_LEFT]) xa++; - if (keys[KEY_RIGHT]) xa--; - jumping = keys[KEY_JUMP]; - sneaking = keys[KEY_SNEAK]; - if (sneaking) { - xa *= 0.3f; - ya *= 0.3f; - } - - wantUp = jumping; - wantDown = sneaking; - - if (keys[KEY_CRAFT]) - player->startCrafting((int)player->x, (int)player->y, (int)player->z, Recipe::SIZE_2X2); - - //printf("\n>- %f %f\n", xa, ya); -} - +#include "KeyboardInput.hpp" +#include "client/Options.hpp" +#include "world/entity/player/Player.hpp" + +KeyboardInput::KeyboardInput( Options* options ) +{ + for (int i = 0; i < NumKeys; ++i) + keys[i] = false; + this->options = options; +} + +void KeyboardInput::setKey( int key, bool state ) +{ + int id = -1; + if (key == options->getIntValue(OPTIONS_KEY_FORWARD)) id = KEY_UP; + if (key == options->getIntValue(OPTIONS_KEY_BACK)) id = KEY_DOWN; + if (key == options->getIntValue(OPTIONS_KEY_LEFT)) id = KEY_LEFT; + if (key == options->getIntValue(OPTIONS_KEY_RIGHT)) id = KEY_RIGHT; + if (key == options->getIntValue(OPTIONS_KEY_JUMP)) id = KEY_JUMP; + if (key == options->getIntValue(OPTIONS_KEY_SNEAK)) id = KEY_SNEAK; + if (id >= 0) { + keys[id] = state; + } +} + +void KeyboardInput::releaseAllKeys() +{ + xa = 0; + ya = 0; + + for (int i = 0; i < NumKeys; i++) { + keys[i] = false; + } + wantUp = wantDown = false; +} + +void KeyboardInput::tick( Player* player ) +{ + xa = 0; + ya = 0; + + if (keys[KEY_UP]) ya++; + if (keys[KEY_DOWN]) ya--; + if (keys[KEY_LEFT]) xa++; + if (keys[KEY_RIGHT]) xa--; + jumping = keys[KEY_JUMP]; + sneaking = keys[KEY_SNEAK]; + if (sneaking) { + xa *= 0.3f; + ya *= 0.3f; + } + + wantUp = jumping; + wantDown = sneaking; + + if (keys[KEY_CRAFT]) + player->startCrafting((int)player->x, (int)player->y, (int)player->z, Recipe::SIZE_2X2); + + //printf("\n>- %f %f\n", xa, ya); +} + diff --git a/src/client/player/input/KeyboardInput.h b/src/client/player/input/KeyboardInput.hpp similarity index 96% rename from src/client/player/input/KeyboardInput.h rename to src/client/player/input/KeyboardInput.hpp index 7342451..35e43b1 100755 --- a/src/client/player/input/KeyboardInput.h +++ b/src/client/player/input/KeyboardInput.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.player; -#include "IMoveInput.h" +#include "IMoveInput.hpp" class Options; class Player; diff --git a/src/client/player/input/MouseBuildInput.h b/src/client/player/input/MouseBuildInput.hpp similarity index 92% rename from src/client/player/input/MouseBuildInput.h rename to src/client/player/input/MouseBuildInput.hpp index 91938e8..d5e0443 100755 --- a/src/client/player/input/MouseBuildInput.h +++ b/src/client/player/input/MouseBuildInput.hpp @@ -1,7 +1,7 @@ #pragma once -#include "IBuildInput.h" -#include "../../../platform/input/Mouse.h" +#include "IBuildInput.hpp" +#include "platform/input/Mouse.hpp" /** A Mouse Build input */ class MouseBuildInput : public IBuildInput { diff --git a/src/client/player/input/MouseTurnInput.h b/src/client/player/input/MouseTurnInput.hpp similarity index 92% rename from src/client/player/input/MouseTurnInput.h rename to src/client/player/input/MouseTurnInput.hpp index 5fc25cd..61e6561 100755 --- a/src/client/player/input/MouseTurnInput.h +++ b/src/client/player/input/MouseTurnInput.hpp @@ -1,7 +1,7 @@ #pragma once -#include "ITurnInput.h" -#include "../../../platform/input/Mouse.h" +#include "ITurnInput.hpp" +#include "platform/input/Mouse.hpp" /** A Mouse Turn input */ class MouseTurnInput : public ITurnInput { diff --git a/src/client/player/input/XperiaPlayInput.h b/src/client/player/input/XperiaPlayInput.hpp similarity index 89% rename from src/client/player/input/XperiaPlayInput.h rename to src/client/player/input/XperiaPlayInput.hpp index bfba51f..1a5bdd0 100755 --- a/src/client/player/input/XperiaPlayInput.h +++ b/src/client/player/input/XperiaPlayInput.hpp @@ -2,9 +2,9 @@ //package net.minecraft.client.player; -#include "KeyboardInput.h" -#include "platform/input/Controller.h" -#include "world/entity/player/Player.h" +#include "KeyboardInput.hpp" +#include "platform/input/Controller.hpp" +#include "world/entity/player/Player.hpp" // @note: This is just copy-pasted from KeyboardInput right now. class XperiaPlayInput: public KeyboardInput diff --git a/src/client/player/input/touchscreen/ITouchScreenModel.h b/src/client/player/input/touchscreen/ITouchScreenModel.hpp similarity index 82% rename from src/client/player/input/touchscreen/ITouchScreenModel.h rename to src/client/player/input/touchscreen/ITouchScreenModel.hpp index c3f0820..ee60fb2 100755 --- a/src/client/player/input/touchscreen/ITouchScreenModel.h +++ b/src/client/player/input/touchscreen/ITouchScreenModel.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../../../platform/input/Mouse.h" +#include "platform/input/Mouse.hpp" class ITouchScreenModel { diff --git a/src/client/player/input/touchscreen/TouchAreaModel.h b/src/client/player/input/touchscreen/TouchAreaModel.hpp similarity index 98% rename from src/client/player/input/touchscreen/TouchAreaModel.h rename to src/client/player/input/touchscreen/TouchAreaModel.hpp index 3a937de..f5e3628 100755 --- a/src/client/player/input/touchscreen/TouchAreaModel.h +++ b/src/client/player/input/touchscreen/TouchAreaModel.hpp @@ -1,8 +1,8 @@ #pragma once -#include "ITouchScreenModel.h" +#include "ITouchScreenModel.hpp" #include -#include "../../../../platform/time.h" +#include "platform/time.hpp" /// Interface for an area that can be point tested class IArea{ diff --git a/src/client/player/input/touchscreen/TouchInputHolder.h b/src/client/player/input/touchscreen/TouchInputHolder.hpp similarity index 97% rename from src/client/player/input/touchscreen/TouchInputHolder.h rename to src/client/player/input/touchscreen/TouchInputHolder.hpp index b2ae433..8c0c36a 100755 --- a/src/client/player/input/touchscreen/TouchInputHolder.h +++ b/src/client/player/input/touchscreen/TouchInputHolder.hpp @@ -1,16 +1,16 @@ #pragma once -#include "../IInputHolder.h" -#include "TouchscreenInput.h" +#include "client/player/input/IInputHolder.hpp" +#include "TouchscreenInput.hpp" -#include "../ITurnInput.h" -#include "TouchAreaModel.h" -#include "../../../../platform/input/Multitouch.h" -#include "../../../../platform/time.h" -#include "../../../../util/SmoothFloat.h" +#include "client/player/input/ITurnInput.hpp" +#include "TouchAreaModel.hpp" +#include "platform/input/Multitouch.hpp" +#include "platform/time.hpp" +#include "util/SmoothFloat.hpp" -#include "../../../../world/entity/player/Player.h" -#include "../../../../world/entity/player/Inventory.h" +#include "world/entity/player/Player.hpp" +#include "world/entity/player/Inventory.hpp" template class ModifyNotify { diff --git a/src/client/player/input/touchscreen/TouchTurnInput.h b/src/client/player/input/touchscreen/TouchTurnInput.hpp similarity index 93% rename from src/client/player/input/touchscreen/TouchTurnInput.h rename to src/client/player/input/touchscreen/TouchTurnInput.hpp index 8252164..3dc56e8 100755 --- a/src/client/player/input/touchscreen/TouchTurnInput.h +++ b/src/client/player/input/touchscreen/TouchTurnInput.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../ITurnInput.h" -#include "TouchAreaModel.h" -#include "../../../../platform/input/Multitouch.h" +#include "client/player/input/ITurnInput.hpp" +#include "TouchAreaModel.hpp" +#include "platform/input/Multitouch.hpp" class TouchTurnInput: public ITurnInput { diff --git a/src/client/player/input/touchscreen/TouchscreenInput.cpp b/src/client/player/input/touchscreen/TouchscreenInput.cpp index 37cb6d8..ad3b080 100755 --- a/src/client/player/input/touchscreen/TouchscreenInput.cpp +++ b/src/client/player/input/touchscreen/TouchscreenInput.cpp @@ -1,524 +1,524 @@ -#include "TouchscreenInput.h" -#include "../../../Options.h" -#include "../../../../platform/input/Multitouch.h" -#include "../../../gui/Gui.h" -#include "../../../renderer/Tesselator.h" -#include "../../../../world/entity/player/Player.h" - -#include "../../../Minecraft.h" -#include "../../../../platform/log.h" -#include "../../../renderer/Textures.h" -#include "../../../sound/SoundEngine.h" -#include "client/gui/screens/ScreenChooser.h" - - -// ARGHHHHHH WHY NOT FUCKING ENUM -static const int AREA_DPAD_FIRST = 100; -static const int AREA_DPAD_N = 100; -static const int AREA_DPAD_S = 101; -static const int AREA_DPAD_W = 102; -static const int AREA_DPAD_E = 103; -static const int AREA_DPAD_C = 104; -static const int AREA_PAUSE = 105; -static const int AREA_CHAT = 106; - -static int cPressed = 0; -static int cReleased = 0; -static int cDiscreet = 0; -static int cPressedPause = 0; -static int cReleasedPause = 0; -//static const int AREA_DPAD_N_JUMP = 105; - -// -// TouchscreenInput_TestFps -// - -static void Copy(int n, float* x, float* y, float* dx, float* dy) { - for (int i = 0; i < n; ++i) { - dx[i] = x[i]; - dy[i] = y[i]; - } -} - -static void Translate(int n, float* x, float* y, float xt, float yt) { - for (int i = 0; i < n; ++i) { - x[i] += xt; - y[i] += yt; - } -} - -static void Scale(int n, float* x, float* y, float xt, float yt) { - for (int i = 0; i < n; ++i) { - x[i] *= xt; - y[i] *= yt; - } -} - -static void Transformed(int n, float* x, float* y, float* dx, float* dy, float xt, float yt, float sx=1.0f, float sy=1.0f) { - Copy(n, x, y, dx, dy); - Scale(n, dx, dy, sx, sy); - Translate(n, dx, dy, xt, yt); - - //for (int i = 0; i < n; ++i) { - // LOGI("%d. (%f, %f)\n", i, dx[i], dy[i]); - //} -} - -TouchscreenInput_TestFps::TouchscreenInput_TestFps( Minecraft* mc, Options* options ) -: _minecraft(mc), - _options(options), - _northJump(false), - _forward(false), - _boundingRectangle(0, 0, 1, 1), - _pressedJump(false), - _pauseIsDown(false), - _sneakTapTime(-999), - aLeft(0), - aRight(0), - aUp(0), - aDown(0), - aJump(0), - aUpLeft(0), - aUpRight(0), - _allowHeightChange(false) -{ - releaseAllKeys(); - onConfigChanged( createConfig(mc) ); - - Tesselator& t = Tesselator::instance; - const int alpha = 128; - t.color( 0xc0c0c0, alpha); cPressed = t.getColor(); - t.color( 0xffffff, alpha); cReleased = t.getColor(); - t.color( 0xffffff, alpha / 4); cDiscreet = t.getColor(); - t.color( 0xc0c0c0, 80); cPressedPause=t.getColor(); - t.color( 0xffffff, 80); cReleasedPause=t.getColor(); -} - -TouchscreenInput_TestFps::~TouchscreenInput_TestFps() { - clear(); -} - -void TouchscreenInput_TestFps::clear() { - _model.clear(); - - delete aUpLeft; aUpLeft = NULL; // @todo: SAFEDEL - delete aUpRight; aUpRight = NULL; -} - -bool TouchscreenInput_TestFps::isButtonDown(int areaId) { - return _buttons[areaId - AREA_DPAD_FIRST]; -} - - -void TouchscreenInput_TestFps::onConfigChanged(const Config& c) { - clear(); - - const float w = (float)c.width; - const float h = (float)c.height; - - /* - // Code for "Move when touching left side of the screen" - float x0[] = { 0, w * 0.3f, w * 0.3f, 0 }; - float y0[] = { 0, 0, h-32, h-32 }; - - _model.addArea(AREA_MOVE, new RectangleArea(0, 0, w*0.3f, h-32)); - */ - - // Code for "D-pad with jump in center" - float Bw = w * 0.11f;//0.08f; - float Bh = Bw;//0.15f; - - // If too large (like playing on Tablet) - PixelCalc& pc = _minecraft->pixelCalc; - if (pc.pixelsToMillimeters(Bw) > 200) { //14 - Bw = Bh = pc.millimetersToPixels(200); //14 - } - // temp data - float xx; - float yy; - - const float BaseY = -8 + h - 3.0f * Bh; - const float BaseX = _options->getBooleanValue(OPTIONS_IS_LEFT_HANDED)? -8 + w - 3 * Bw - : 8 + 0; - // Setup the bounding rectangle - _boundingRectangle = RectangleArea(BaseX, BaseY, BaseX + 3 * Bw, BaseY + 3 * Bh); - - xx = BaseX + Bw; yy = BaseY; - _model.addArea(AREA_DPAD_N, aUp = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); - xx = BaseX; - aUpLeft = new RectangleArea(xx, yy, xx+Bw, yy+Bh); - xx = BaseX + 2 * Bw; - aUpRight = new RectangleArea(xx, yy, xx+Bw, yy+Bh); - - xx = BaseX + Bw; yy = BaseY + Bh; - _model.addArea(AREA_DPAD_C, aJump = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); - - xx = BaseX + Bw; yy = BaseY + 2 * Bh; - _model.addArea(AREA_DPAD_S, aDown = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); - - xx = BaseX; yy = BaseY + Bh; - _model.addArea(AREA_DPAD_W, aLeft = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); - - xx = BaseX + 2 * Bw; yy = BaseY + Bh; - _model.addArea(AREA_DPAD_E, aRight = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); - - float maxPixels = _minecraft->pixelCalc.millimetersToPixels(10); - // float btnSize = Mth::Min(18 * Gui::GuiScale, maxPixels); - float btnSize = pc.millimetersToPixels(18 * Gui::GuiScale); - _model.addArea(AREA_PAUSE, aPause = new RectangleArea(w - 4 - btnSize, 4, w - 4, 4 + btnSize)); - _model.addArea(AREA_CHAT, aChat = new RectangleArea(w - 8 - btnSize * 2, 4, w - 8 - btnSize, 4 + btnSize)); - - //rebuild(); -} - -void TouchscreenInput_TestFps::setKey(int key, bool state) -{ - #ifdef WIN32 - //LOGI("key: %d, %d\n", key, state); - - int id = -1; - // theres no keyUp etc??? - //if (key == _options->keyUp.key) id = KEY_UP; - //if (key == _options->keyDown.key) id = KEY_DOWN; - //if (key == _options->keyLeft.key) id = KEY_LEFT; - //if (key == _options->keyRight.key) id = KEY_RIGHT; - //if (key == _options->keyJump.key) id = KEY_JUMP; - //if (key == _options->keySneak.key) id = KEY_SNEAK; - //if (key == _options->keyCraft.key) id = KEY_CRAFT; - //if (id >= 0) { - // _keys[id] = state; - //} - - if (key == _options->getIntValue(OPTIONS_KEY_FORWARD)) id = KEY_UP; - if (key == _options->getIntValue(OPTIONS_KEY_BACK)) id = KEY_DOWN; - if (key == _options->getIntValue(OPTIONS_KEY_LEFT)) id = KEY_LEFT; - if (key == _options->getIntValue(OPTIONS_KEY_RIGHT)) id = KEY_RIGHT; - if (key == _options->getIntValue(OPTIONS_KEY_JUMP)) id = KEY_JUMP; - if (key == _options->getIntValue(OPTIONS_KEY_SNEAK)) id = KEY_SNEAK; - //if (key == _options->getIntValue(OPTIONS_KEY_CRAFT)) id = KEY_CRAFT; - #endif -} - -void TouchscreenInput_TestFps::releaseAllKeys() -{ - xa = 0; - ya = 0; - - for (int i = 0; i<8; ++i) - _buttons[i] = false; -#ifdef WIN32 - for (int i = 0; iisInWater()) { - jumping = true; - } - else if (Multitouch::isPressed(p)) { - jumping = true; - } // Or if we are walking forward, jump while going forward! - else if (_forward && !player->abilities.flying) { - areaId = AREA_DPAD_N; - tmpNorthJump = true; - //jumping = true; - ya += 1; - } - } - - if (areaId == AREA_DPAD_N) - { - setButton = true; - if (player->isInWater()) - jumping = true; - else if (!isChangingFlightHeight) - tmpForward = true; - ya += 1; - } - else if (areaId == AREA_DPAD_S && !_forward) - { - setButton = true; - ya -= 1; - /* - if (Multitouch::isReleased(p)) { - float now = getTimeS(); - if (now - _sneakTapTime < 0.4f) { - ya += 1; - sneaking = !sneaking; - player->setSneaking(sneaking); - _sneakTapTime = -1; - } else { - _sneakTapTime = now; - } - } - */ - } - else if (areaId == AREA_DPAD_W && !_forward) - { - setButton = true; - xa += 1; - } - else if (areaId == AREA_DPAD_E && !_forward) - { - setButton = true; - xa -= 1; - } - else if (areaId == AREA_PAUSE) { - if (Multitouch::isReleased(p)) { - _minecraft->soundEngine->playUI("random.click", 1, 1); - _minecraft->screenChooser.setScreen(SCREEN_PAUSE); - } - } - else if (areaId == AREA_CHAT) { - if (Multitouch::isReleased(p)) { - _minecraft->soundEngine->playUI("random.click", 1, 1); - _minecraft->screenChooser.setScreen(SCREEN_CONSOLE); - _minecraft->platform()->showKeyboard(); - } - } - - _buttons[areaId - AREA_DPAD_FIRST] = setButton; - } - - _forward = tmpForward; - - // Only jump once at a time - if (tmpNorthJump) { - if (!_northJump) - jumping = true; - _northJump = true; - } - else _northJump = false; - - isChangingFlightHeight = false; - wantUp = isButtonDown(AREA_DPAD_N) && (_allowHeightChange & (_pressedJump | wantUp)); - wantDown = isButtonDown(AREA_DPAD_S) && (_allowHeightChange & (_pressedJump | wantDown)); - if (player->abilities.flying && (wantUp || wantDown || (heldJump && !_forward))) - { - isChangingFlightHeight = true; - ya = 0; - } - _renderFlightImage = player->abilities.flying; - -#ifdef WIN32 - if (_keys[KEY_UP]) ya++; - if (_keys[KEY_DOWN]) ya--; - if (_keys[KEY_LEFT]) xa++; - if (_keys[KEY_RIGHT]) xa--; - if (_keys[KEY_JUMP]) jumping = true; - //sneaking = _keys[KEY_SNEAK]; - if (_keys[KEY_CRAFT]) - player->startCrafting((int)player->x, (int)player->y, (int)player->z, Recipe::SIZE_2X2); -#endif - - if (sneaking) { - xa *= 0.3f; - ya *= 0.3f; - } - //printf("\n>- %f %f\n", xa, ya); - _pressedJump = heldJump; -} - -static void drawRectangleArea(Tesselator& t, RectangleArea* a, int ux, int vy, float ssz = 64.0f) { - const float pm = 1.0f / 256.0f; - const float sz = ssz * pm; - const float uu = (float)(ux) * pm; - const float vv = (float)(vy) * pm; - const float x0 = a->_x0 * Gui::InvGuiScale; - const float x1 = a->_x1 * Gui::InvGuiScale; - const float y0 = a->_y0 * Gui::InvGuiScale; - const float y1 = a->_y1 * Gui::InvGuiScale; - - t.vertexUV(x0, y1, 0, uu, vv+sz); - t.vertexUV(x1, y1, 0, uu+sz,vv+sz); - t.vertexUV(x1, y0, 0, uu+sz,vv); - t.vertexUV(x0, y0, 0, uu, vv); -} - -static void drawPolygonArea(Tesselator& t, PolygonArea* a, int x, int y) { - float pm = 1.0f / 256.0f; - float sz = 64.0f * pm; - float uu = (float)(x) * pm; - float vv = (float)(y) * pm; - - float uvs[] = {uu, vv, uu+sz, vv, uu+sz, vv+sz, uu, vv+sz}; - const int o = 0; - - for (int j = 0; j < a->_numPoints; ++j) { - t.vertexUV(a->_x[j] * Gui::InvGuiScale, a->_y[j] * Gui::InvGuiScale, 0, uvs[(o+j+j)&7], uvs[(o+j+j+1)&7]); - } -} - -void TouchscreenInput_TestFps::render( float a ) { - //return; - - //static Stopwatch sw; - //sw.start(); - - - //glColor4f2(1, 0, 1, 1.0f); - //glDisable2(GL_CULL_FACE); - glDisable2(GL_ALPHA_TEST); - - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - _minecraft->textures->loadAndBindTexture("gui/gui.png"); - - //glDisable2(GL_TEXTURE_2D); - - rebuild(); - //drawArrayVTC(_bufferId, 5 * 2 * 3, 24); - - glDisable2(GL_BLEND); - //glEnable2(GL_TEXTURE_2D); - //glEnable2(GL_CULL_FACE); - - //sw.stop(); - //sw.printEvery(100, "buttons"); -} - -const RectangleArea& TouchscreenInput_TestFps::getRectangleArea() -{ - return _boundingRectangle; -} -const RectangleArea& TouchscreenInput_TestFps::getPauseRectangleArea() -{ - return *aPause; -} - -void TouchscreenInput_TestFps::rebuild() { - if (_options->getBooleanValue(OPTIONS_HIDEGUI)) - return; - - Tesselator& t = Tesselator::instance; - //LOGI("instance is: %p, %p, %p, %p, %p FOR %d\n", &t, aLeft, aRight, aUp, aDown, aJump, _bufferId); - //t.setAccessMode(Tesselator::ACCESS_DYNAMIC); - t.begin(); - - const int imageU = 0; - const int imageV = 107; - const int imageSize = 26; - - bool northDiagonals = !isChangingFlightHeight && (_northJump || _forward); - - // render left button - if (northDiagonals || isChangingFlightHeight) t.colorABGR(cDiscreet); - else if (isButtonDown(AREA_DPAD_W)) t.colorABGR(cPressed); - else t.colorABGR(cReleased); - drawRectangleArea(t, aLeft, imageU + imageSize, imageV, (float)imageSize); - - // render right button - if (northDiagonals || isChangingFlightHeight) t.colorABGR(cDiscreet); - else if (isButtonDown(AREA_DPAD_E)) t.colorABGR(cPressed); - else t.colorABGR(cReleased); - drawRectangleArea(t, aRight, imageU + imageSize * 3, imageV, (float)imageSize); - - // render forward button - if (isButtonDown(AREA_DPAD_N)) t.colorABGR(cPressed); - else t.colorABGR(cReleased); - if (isChangingFlightHeight) - { - drawRectangleArea(t, aUp, imageU + imageSize * 2, imageV + imageSize, (float)imageSize); - } - else - { - drawRectangleArea(t, aUp, imageU, imageV, (float)imageSize); - } - - // render diagonals, if available - if (northDiagonals) - { - t.colorABGR(cReleased); - drawRectangleArea(t, aUpLeft, imageU, imageV + imageSize, (float)imageSize); - drawRectangleArea(t, aUpRight, imageU + imageSize, imageV + imageSize, (float)imageSize); - } - - // render backwards button - if (northDiagonals) t.colorABGR(cDiscreet); - else if (isButtonDown(AREA_DPAD_S)) t.colorABGR(cPressed); - else t.colorABGR(cReleased); - if (isChangingFlightHeight) - { - drawRectangleArea(t, aDown, imageU + imageSize * 3, imageV + imageSize, (float)imageSize); - } - else - { - drawRectangleArea(t, aDown, imageU + imageSize * 2, imageV, (float)imageSize); - } - - // render jump / flight button - if (_renderFlightImage && northDiagonals) t.colorABGR(cDiscreet); - else if (isButtonDown(AREA_DPAD_C)) t.colorABGR(cPressed); - else t.colorABGR(cReleased); - if (_renderFlightImage) - { - drawRectangleArea(t, aJump, imageU + imageSize * 4, imageV + imageSize, (float)imageSize); - } - else - { - drawRectangleArea(t, aJump, imageU + imageSize * 4, imageV, (float)imageSize); - } - - if (!_minecraft->screen) { - t.colorABGR(0xFFFFFFFF); - // if (isButtonDown(AREA_PAUSE)) t.colorABGR(cPressedPause); - // else t.colorABGR(cReleasedPause); - - drawRectangleArea(t, aPause, 200, 64, 18.0f); - drawRectangleArea(t, aChat, 200, 82, 18.0f); - } -//t.end(true, _bufferId); - //return; - - t.draw(); - //RenderChunk _render = t.end(true, _bufferId); - //t.setAccessMode(Tesselator::ACCESS_STATIC); - //_bufferId = _render.vboId; -} +#include "TouchscreenInput.hpp" +#include "client/Options.hpp" +#include "platform/input/Multitouch.hpp" +#include "client/gui/Gui.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/entity/player/Player.hpp" + +#include "client/Minecraft.hpp" +#include "platform/log.hpp" +#include "client/renderer/Textures.hpp" +#include "client/sound/SoundEngine.hpp" +#include "client/gui/screens/ScreenChooser.hpp" + + +// ARGHHHHHH WHY NOT FUCKING ENUM +static const int AREA_DPAD_FIRST = 100; +static const int AREA_DPAD_N = 100; +static const int AREA_DPAD_S = 101; +static const int AREA_DPAD_W = 102; +static const int AREA_DPAD_E = 103; +static const int AREA_DPAD_C = 104; +static const int AREA_PAUSE = 105; +static const int AREA_CHAT = 106; + +static int cPressed = 0; +static int cReleased = 0; +static int cDiscreet = 0; +static int cPressedPause = 0; +static int cReleasedPause = 0; +//static const int AREA_DPAD_N_JUMP = 105; + +// +// TouchscreenInput_TestFps +// + +static void Copy(int n, float* x, float* y, float* dx, float* dy) { + for (int i = 0; i < n; ++i) { + dx[i] = x[i]; + dy[i] = y[i]; + } +} + +static void Translate(int n, float* x, float* y, float xt, float yt) { + for (int i = 0; i < n; ++i) { + x[i] += xt; + y[i] += yt; + } +} + +static void Scale(int n, float* x, float* y, float xt, float yt) { + for (int i = 0; i < n; ++i) { + x[i] *= xt; + y[i] *= yt; + } +} + +static void Transformed(int n, float* x, float* y, float* dx, float* dy, float xt, float yt, float sx=1.0f, float sy=1.0f) { + Copy(n, x, y, dx, dy); + Scale(n, dx, dy, sx, sy); + Translate(n, dx, dy, xt, yt); + + //for (int i = 0; i < n; ++i) { + // LOGI("%d. (%f, %f)\n", i, dx[i], dy[i]); + //} +} + +TouchscreenInput_TestFps::TouchscreenInput_TestFps( Minecraft* mc, Options* options ) +: _minecraft(mc), + _options(options), + _northJump(false), + _forward(false), + _boundingRectangle(0, 0, 1, 1), + _pressedJump(false), + _pauseIsDown(false), + _sneakTapTime(-999), + aLeft(0), + aRight(0), + aUp(0), + aDown(0), + aJump(0), + aUpLeft(0), + aUpRight(0), + _allowHeightChange(false) +{ + releaseAllKeys(); + onConfigChanged( createConfig(mc) ); + + Tesselator& t = Tesselator::instance; + const int alpha = 128; + t.color( 0xc0c0c0, alpha); cPressed = t.getColor(); + t.color( 0xffffff, alpha); cReleased = t.getColor(); + t.color( 0xffffff, alpha / 4); cDiscreet = t.getColor(); + t.color( 0xc0c0c0, 80); cPressedPause=t.getColor(); + t.color( 0xffffff, 80); cReleasedPause=t.getColor(); +} + +TouchscreenInput_TestFps::~TouchscreenInput_TestFps() { + clear(); +} + +void TouchscreenInput_TestFps::clear() { + _model.clear(); + + delete aUpLeft; aUpLeft = NULL; // @todo: SAFEDEL + delete aUpRight; aUpRight = NULL; +} + +bool TouchscreenInput_TestFps::isButtonDown(int areaId) { + return _buttons[areaId - AREA_DPAD_FIRST]; +} + + +void TouchscreenInput_TestFps::onConfigChanged(const Config& c) { + clear(); + + const float w = (float)c.width; + const float h = (float)c.height; + + /* + // Code for "Move when touching left side of the screen" + float x0[] = { 0, w * 0.3f, w * 0.3f, 0 }; + float y0[] = { 0, 0, h-32, h-32 }; + + _model.addArea(AREA_MOVE, new RectangleArea(0, 0, w*0.3f, h-32)); + */ + + // Code for "D-pad with jump in center" + float Bw = w * 0.11f;//0.08f; + float Bh = Bw;//0.15f; + + // If too large (like playing on Tablet) + PixelCalc& pc = _minecraft->pixelCalc; + if (pc.pixelsToMillimeters(Bw) > 200) { //14 + Bw = Bh = pc.millimetersToPixels(200); //14 + } + // temp data + float xx; + float yy; + + const float BaseY = -8 + h - 3.0f * Bh; + const float BaseX = _options->getBooleanValue(OPTIONS_IS_LEFT_HANDED)? -8 + w - 3 * Bw + : 8 + 0; + // Setup the bounding rectangle + _boundingRectangle = RectangleArea(BaseX, BaseY, BaseX + 3 * Bw, BaseY + 3 * Bh); + + xx = BaseX + Bw; yy = BaseY; + _model.addArea(AREA_DPAD_N, aUp = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); + xx = BaseX; + aUpLeft = new RectangleArea(xx, yy, xx+Bw, yy+Bh); + xx = BaseX + 2 * Bw; + aUpRight = new RectangleArea(xx, yy, xx+Bw, yy+Bh); + + xx = BaseX + Bw; yy = BaseY + Bh; + _model.addArea(AREA_DPAD_C, aJump = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); + + xx = BaseX + Bw; yy = BaseY + 2 * Bh; + _model.addArea(AREA_DPAD_S, aDown = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); + + xx = BaseX; yy = BaseY + Bh; + _model.addArea(AREA_DPAD_W, aLeft = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); + + xx = BaseX + 2 * Bw; yy = BaseY + Bh; + _model.addArea(AREA_DPAD_E, aRight = new RectangleArea(xx, yy, xx+Bw, yy+Bh)); + + float maxPixels = _minecraft->pixelCalc.millimetersToPixels(10); + // float btnSize = Mth::Min(18 * Gui::GuiScale, maxPixels); + float btnSize = pc.millimetersToPixels(18 * Gui::GuiScale); + _model.addArea(AREA_PAUSE, aPause = new RectangleArea(w - 4 - btnSize, 4, w - 4, 4 + btnSize)); + _model.addArea(AREA_CHAT, aChat = new RectangleArea(w - 8 - btnSize * 2, 4, w - 8 - btnSize, 4 + btnSize)); + + //rebuild(); +} + +void TouchscreenInput_TestFps::setKey(int key, bool state) +{ + #ifdef WIN32 + //LOGI("key: %d, %d\n", key, state); + + int id = -1; + // theres no keyUp etc??? + //if (key == _options->keyUp.key) id = KEY_UP; + //if (key == _options->keyDown.key) id = KEY_DOWN; + //if (key == _options->keyLeft.key) id = KEY_LEFT; + //if (key == _options->keyRight.key) id = KEY_RIGHT; + //if (key == _options->keyJump.key) id = KEY_JUMP; + //if (key == _options->keySneak.key) id = KEY_SNEAK; + //if (key == _options->keyCraft.key) id = KEY_CRAFT; + //if (id >= 0) { + // _keys[id] = state; + //} + + if (key == _options->getIntValue(OPTIONS_KEY_FORWARD)) id = KEY_UP; + if (key == _options->getIntValue(OPTIONS_KEY_BACK)) id = KEY_DOWN; + if (key == _options->getIntValue(OPTIONS_KEY_LEFT)) id = KEY_LEFT; + if (key == _options->getIntValue(OPTIONS_KEY_RIGHT)) id = KEY_RIGHT; + if (key == _options->getIntValue(OPTIONS_KEY_JUMP)) id = KEY_JUMP; + if (key == _options->getIntValue(OPTIONS_KEY_SNEAK)) id = KEY_SNEAK; + //if (key == _options->getIntValue(OPTIONS_KEY_CRAFT)) id = KEY_CRAFT; + #endif +} + +void TouchscreenInput_TestFps::releaseAllKeys() +{ + xa = 0; + ya = 0; + + for (int i = 0; i<8; ++i) + _buttons[i] = false; +#ifdef WIN32 + for (int i = 0; iisInWater()) { + jumping = true; + } + else if (Multitouch::isPressed(p)) { + jumping = true; + } // Or if we are walking forward, jump while going forward! + else if (_forward && !player->abilities.flying) { + areaId = AREA_DPAD_N; + tmpNorthJump = true; + //jumping = true; + ya += 1; + } + } + + if (areaId == AREA_DPAD_N) + { + setButton = true; + if (player->isInWater()) + jumping = true; + else if (!isChangingFlightHeight) + tmpForward = true; + ya += 1; + } + else if (areaId == AREA_DPAD_S && !_forward) + { + setButton = true; + ya -= 1; + /* + if (Multitouch::isReleased(p)) { + float now = getTimeS(); + if (now - _sneakTapTime < 0.4f) { + ya += 1; + sneaking = !sneaking; + player->setSneaking(sneaking); + _sneakTapTime = -1; + } else { + _sneakTapTime = now; + } + } + */ + } + else if (areaId == AREA_DPAD_W && !_forward) + { + setButton = true; + xa += 1; + } + else if (areaId == AREA_DPAD_E && !_forward) + { + setButton = true; + xa -= 1; + } + else if (areaId == AREA_PAUSE) { + if (Multitouch::isReleased(p)) { + _minecraft->soundEngine->playUI("random.click", 1, 1); + _minecraft->screenChooser.setScreen(SCREEN_PAUSE); + } + } + else if (areaId == AREA_CHAT) { + if (Multitouch::isReleased(p)) { + _minecraft->soundEngine->playUI("random.click", 1, 1); + _minecraft->screenChooser.setScreen(SCREEN_CONSOLE); + _minecraft->platform()->showKeyboard(); + } + } + + _buttons[areaId - AREA_DPAD_FIRST] = setButton; + } + + _forward = tmpForward; + + // Only jump once at a time + if (tmpNorthJump) { + if (!_northJump) + jumping = true; + _northJump = true; + } + else _northJump = false; + + isChangingFlightHeight = false; + wantUp = isButtonDown(AREA_DPAD_N) && (_allowHeightChange & (_pressedJump | wantUp)); + wantDown = isButtonDown(AREA_DPAD_S) && (_allowHeightChange & (_pressedJump | wantDown)); + if (player->abilities.flying && (wantUp || wantDown || (heldJump && !_forward))) + { + isChangingFlightHeight = true; + ya = 0; + } + _renderFlightImage = player->abilities.flying; + +#ifdef WIN32 + if (_keys[KEY_UP]) ya++; + if (_keys[KEY_DOWN]) ya--; + if (_keys[KEY_LEFT]) xa++; + if (_keys[KEY_RIGHT]) xa--; + if (_keys[KEY_JUMP]) jumping = true; + //sneaking = _keys[KEY_SNEAK]; + if (_keys[KEY_CRAFT]) + player->startCrafting((int)player->x, (int)player->y, (int)player->z, Recipe::SIZE_2X2); +#endif + + if (sneaking) { + xa *= 0.3f; + ya *= 0.3f; + } + //printf("\n>- %f %f\n", xa, ya); + _pressedJump = heldJump; +} + +static void drawRectangleArea(Tesselator& t, RectangleArea* a, int ux, int vy, float ssz = 64.0f) { + const float pm = 1.0f / 256.0f; + const float sz = ssz * pm; + const float uu = (float)(ux) * pm; + const float vv = (float)(vy) * pm; + const float x0 = a->_x0 * Gui::InvGuiScale; + const float x1 = a->_x1 * Gui::InvGuiScale; + const float y0 = a->_y0 * Gui::InvGuiScale; + const float y1 = a->_y1 * Gui::InvGuiScale; + + t.vertexUV(x0, y1, 0, uu, vv+sz); + t.vertexUV(x1, y1, 0, uu+sz,vv+sz); + t.vertexUV(x1, y0, 0, uu+sz,vv); + t.vertexUV(x0, y0, 0, uu, vv); +} + +static void drawPolygonArea(Tesselator& t, PolygonArea* a, int x, int y) { + float pm = 1.0f / 256.0f; + float sz = 64.0f * pm; + float uu = (float)(x) * pm; + float vv = (float)(y) * pm; + + float uvs[] = {uu, vv, uu+sz, vv, uu+sz, vv+sz, uu, vv+sz}; + const int o = 0; + + for (int j = 0; j < a->_numPoints; ++j) { + t.vertexUV(a->_x[j] * Gui::InvGuiScale, a->_y[j] * Gui::InvGuiScale, 0, uvs[(o+j+j)&7], uvs[(o+j+j+1)&7]); + } +} + +void TouchscreenInput_TestFps::render( float a ) { + //return; + + //static Stopwatch sw; + //sw.start(); + + + //glColor4f2(1, 0, 1, 1.0f); + //glDisable2(GL_CULL_FACE); + glDisable2(GL_ALPHA_TEST); + + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + _minecraft->textures->loadAndBindTexture("gui/gui.png"); + + //glDisable2(GL_TEXTURE_2D); + + rebuild(); + //drawArrayVTC(_bufferId, 5 * 2 * 3, 24); + + glDisable2(GL_BLEND); + //glEnable2(GL_TEXTURE_2D); + //glEnable2(GL_CULL_FACE); + + //sw.stop(); + //sw.printEvery(100, "buttons"); +} + +const RectangleArea& TouchscreenInput_TestFps::getRectangleArea() +{ + return _boundingRectangle; +} +const RectangleArea& TouchscreenInput_TestFps::getPauseRectangleArea() +{ + return *aPause; +} + +void TouchscreenInput_TestFps::rebuild() { + if (_options->getBooleanValue(OPTIONS_HIDEGUI)) + return; + + Tesselator& t = Tesselator::instance; + //LOGI("instance is: %p, %p, %p, %p, %p FOR %d\n", &t, aLeft, aRight, aUp, aDown, aJump, _bufferId); + //t.setAccessMode(Tesselator::ACCESS_DYNAMIC); + t.begin(); + + const int imageU = 0; + const int imageV = 107; + const int imageSize = 26; + + bool northDiagonals = !isChangingFlightHeight && (_northJump || _forward); + + // render left button + if (northDiagonals || isChangingFlightHeight) t.colorABGR(cDiscreet); + else if (isButtonDown(AREA_DPAD_W)) t.colorABGR(cPressed); + else t.colorABGR(cReleased); + drawRectangleArea(t, aLeft, imageU + imageSize, imageV, (float)imageSize); + + // render right button + if (northDiagonals || isChangingFlightHeight) t.colorABGR(cDiscreet); + else if (isButtonDown(AREA_DPAD_E)) t.colorABGR(cPressed); + else t.colorABGR(cReleased); + drawRectangleArea(t, aRight, imageU + imageSize * 3, imageV, (float)imageSize); + + // render forward button + if (isButtonDown(AREA_DPAD_N)) t.colorABGR(cPressed); + else t.colorABGR(cReleased); + if (isChangingFlightHeight) + { + drawRectangleArea(t, aUp, imageU + imageSize * 2, imageV + imageSize, (float)imageSize); + } + else + { + drawRectangleArea(t, aUp, imageU, imageV, (float)imageSize); + } + + // render diagonals, if available + if (northDiagonals) + { + t.colorABGR(cReleased); + drawRectangleArea(t, aUpLeft, imageU, imageV + imageSize, (float)imageSize); + drawRectangleArea(t, aUpRight, imageU + imageSize, imageV + imageSize, (float)imageSize); + } + + // render backwards button + if (northDiagonals) t.colorABGR(cDiscreet); + else if (isButtonDown(AREA_DPAD_S)) t.colorABGR(cPressed); + else t.colorABGR(cReleased); + if (isChangingFlightHeight) + { + drawRectangleArea(t, aDown, imageU + imageSize * 3, imageV + imageSize, (float)imageSize); + } + else + { + drawRectangleArea(t, aDown, imageU + imageSize * 2, imageV, (float)imageSize); + } + + // render jump / flight button + if (_renderFlightImage && northDiagonals) t.colorABGR(cDiscreet); + else if (isButtonDown(AREA_DPAD_C)) t.colorABGR(cPressed); + else t.colorABGR(cReleased); + if (_renderFlightImage) + { + drawRectangleArea(t, aJump, imageU + imageSize * 4, imageV + imageSize, (float)imageSize); + } + else + { + drawRectangleArea(t, aJump, imageU + imageSize * 4, imageV, (float)imageSize); + } + + if (!_minecraft->screen) { + t.colorABGR(0xFFFFFFFF); + // if (isButtonDown(AREA_PAUSE)) t.colorABGR(cPressedPause); + // else t.colorABGR(cReleasedPause); + + drawRectangleArea(t, aPause, 200, 64, 18.0f); + drawRectangleArea(t, aChat, 200, 82, 18.0f); + } +//t.end(true, _bufferId); + //return; + + t.draw(); + //RenderChunk _render = t.end(true, _bufferId); + //t.setAccessMode(Tesselator::ACCESS_STATIC); + //_bufferId = _render.vboId; +} diff --git a/src/client/player/input/touchscreen/TouchscreenInput.h b/src/client/player/input/touchscreen/TouchscreenInput.hpp similarity index 90% rename from src/client/player/input/touchscreen/TouchscreenInput.h rename to src/client/player/input/touchscreen/TouchscreenInput.hpp index 3bd20d3..9d50c4d 100755 --- a/src/client/player/input/touchscreen/TouchscreenInput.h +++ b/src/client/player/input/touchscreen/TouchscreenInput.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.player; -#include "../IMoveInput.h" -#include "../../../gui/GuiComponent.h" -#include "TouchAreaModel.h" -#include "../../../renderer/RenderChunk.h" +#include "client/player/input/IMoveInput.hpp" +#include "client/gui/GuiComponent.hpp" +#include "TouchAreaModel.hpp" +#include "client/renderer/RenderChunk.hpp" class Options; class Player; diff --git a/src/client/renderer/Chunk.cpp b/src/client/renderer/Chunk.cpp index 13ac27c..62c6a6b 100755 --- a/src/client/renderer/Chunk.cpp +++ b/src/client/renderer/Chunk.cpp @@ -1,262 +1,262 @@ -#include "Chunk.h" -#include "Tesselator.h" -#include "TileRenderer.h" -#include "culling/Culler.h" -#include "../../world/entity/Entity.h" -#include "../../world/level/tile/Tile.h" -#include "../../world/level/Region.h" -#include "../../world/level/chunk/LevelChunk.h" -#include "../../util/Mth.h" -//#include "../../platform/time.h" - -/*static*/ int Chunk::updates = 0; -//static Stopwatch swRebuild; -//int* _layerChunks[3] = {0, 0, 0}; //Chunk::NumLayers]; -//int _layerChunkCount[3] = {0, 0, 0}; - -Chunk::Chunk( Level* level_, int x, int y, int z, int size, int lists_, GLuint* ptrBuf/*= NULL*/) -: level(level_), - visible(false), - compiled(false), - _empty(true), - xs(size), ys(size), zs(size), - dirty(false), - occlusion_visible(true), - occlusion_querying(false), - lists(lists_), - vboBuffers(ptrBuf), - bb(0,0,0,1,1,1), - t(Tesselator::instance) -{ - for (int l = 0; l < NumLayers; l++) { - empty[l] = false; - } - - radius = Mth::sqrt((float)(xs * xs + ys * ys + zs * zs)) * 0.5f; - - this->x = -999; - setPos(x, y, z); -} - -void Chunk::setPos( int x, int y, int z ) -{ - if (x == this->x && y == this->y && z == this->z) return; - - reset(); - this->x = x; - this->y = y; - this->z = z; - xm = x + xs / 2; - ym = y + ys / 2; - zm = z + zs / 2; - - const float xzg = 1.0f; - const float yp = 2.0f; - const float yn = 0.0f; - bb.set(x-xzg, y-yn, z-xzg, x + xs+xzg, y + ys+yp, z + zs+xzg); - - //glNewList(lists + 2, GL_COMPILE); - //ItemRenderer.renderFlat(AABB.newTemp(xRenderOffs - g, yRenderOffs - g, zRenderOffs - g, xRenderOffs + xs + g, yRenderOffs + ys + g, zRenderOffs + zs + g)); - //glEndList(); - setDirty(); -} - -void Chunk::translateToPos() -{ - glTranslatef2((float)x, (float)y, (float)z); -} - -void Chunk::rebuild() -{ - if (!dirty) return; - //if (!visible) return; - updates++; - - //if (!_layerChunks[0]) { - // for (int i = 0; i < NumLayers; ++i) - // _layerChunks[i] = new int[xs * ys * zs]; - //} - //for (int i = 0; i < NumLayers; ++i) - // _layerChunkCount[i] = 0; - - //Stopwatch& sw = swRebuild; - //sw.start(); - - int x0 = x; - int y0 = y; - int z0 = z; - int x1 = x + xs; - int y1 = y + ys; - int z1 = z + zs; - for (int l = 0; l < NumLayers; l++) { - empty[l] = true; - } - _empty = true; - - LevelChunk::touchedSky = false; - - int r = 1; - Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r); - TileRenderer tileRenderer(®ion); - - bool doRenderLayer[NumLayers] = {true, false, false}; - for (int l = 0; l < NumLayers; l++) { - if (!doRenderLayer[l]) continue; - bool renderNextLayer = false; - bool rendered = false; - - bool started = false; - int cindex = -1; - - for (int y = y0; y < y1; y++) { - for (int z = z0; z < z1; z++) { - for (int x = x0; x < x1; x++) { - ++cindex; - //if (l > 0 && cindex != _layerChunks[_layerChunkCount[l]]) - int tileId = region.getTile(x, y, z); - if (tileId > 0) { - if (!started) { - started = true; - -#ifndef USE_VBO - glNewList(lists + l, GL_COMPILE); - glPushMatrix2(); - translateToPos(); - float ss = 1.000001f; - glTranslatef2(-zs / 2.0f, -ys / 2.0f, -zs / 2.0f); - glScalef2(ss, ss, ss); - glTranslatef2(zs / 2.0f, ys / 2.0f, zs / 2.0f); -#endif - t.begin(); - //printf("."); - //printf("Tesselator::offset : %d, %d, %d\n", this->x, this->y, this->z); - t.offset((float)(-this->x), (float)(-this->y), (float)(-this->z)); - //printf("Tesselator::offset : %f, %f, %f\n", this->x, this->y, this->z); - } - - Tile* tile = Tile::tiles[tileId]; - int renderLayer = tile->getRenderLayer(); - - if (renderLayer > l) { - renderNextLayer = true; - doRenderLayer[renderLayer] = true; - } else if (renderLayer == l) { - rendered |= tileRenderer.tesselateInWorld(tile, x, y, z); - } - } - } - } - } - - if (started) { - -#ifdef USE_VBO - renderChunk[l] = t.end(true, vboBuffers[l]); - renderChunk[l].pos.x = (float)this->x; - renderChunk[l].pos.y = (float)this->y; - renderChunk[l].pos.z = (float)this->z; -#else - t.end(false, -1); - glPopMatrix2(); - glEndList(); -#endif - t.offset(0, 0, 0); - } else { - rendered = false; - } - if (rendered) { - empty[l] = false; - _empty = false; - } - if (!renderNextLayer) break; - } - - //sw.stop(); - //sw.printEvery(1, "rebuild-"); - skyLit = LevelChunk::touchedSky; - compiled = true; - return; -} - -float Chunk::distanceToSqr( const Entity* player ) const -{ - float xd = (float) (player->x - xm); - float yd = (float) (player->y - ym); - float zd = (float) (player->z - zm); - return xd * xd + yd * yd + zd * zd; -} - -float Chunk::squishedDistanceToSqr( const Entity* player ) const -{ - float xd = (float) (player->x - xm); - float yd = (float) (player->y - ym) * 2; - float zd = (float) (player->z - zm); - return xd * xd + yd * yd + zd * zd; -} - -void Chunk::reset() -{ - for (int i = 0; i < NumLayers; i++) { - empty[i] = true; - } - visible = false; - compiled = false; - _empty = true; -} - -int Chunk::getList( int layer ) -{ - if (!visible) return -1; - if (!empty[layer]) return lists + layer; - return -1; -} - -RenderChunk& Chunk::getRenderChunk( int layer ) -{ - return renderChunk[layer]; -} - -int Chunk::getAllLists( int displayLists[], int p, int layer ) -{ - if (!visible) return p; - if (!empty[layer]) displayLists[p++] = (lists + layer); - return p; -} - -void Chunk::cull( Culler* culler ) -{ - visible = culler->isVisible(bb); -} - -void Chunk::renderBB() -{ - //glCallList(lists + 2); -} - -bool Chunk::isEmpty() -{ - return compiled && _empty;//empty[0] && empty[1] && empty[2]; -// if (!compiled) return false; -// return empty[0] && empty[1]; -} - -void Chunk::setDirty() -{ - dirty = true; -} - -void Chunk::setClean() -{ - dirty = false; -} - -bool Chunk::isDirty() -{ - return dirty; -} - -void Chunk::resetUpdates() -{ - updates = 0; - //swRebuild.reset(); -} +#include "Chunk.hpp" +#include "Tesselator.hpp" +#include "TileRenderer.hpp" +#include "culling/Culler.hpp" +#include "world/entity/Entity.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/Region.hpp" +#include "world/level/chunk/LevelChunk.hpp" +#include "util/Mth.hpp" +//#include "platform/time.hpp" + +/*static*/ int Chunk::updates = 0; +//static Stopwatch swRebuild; +//int* _layerChunks[3] = {0, 0, 0}; //Chunk::NumLayers]; +//int _layerChunkCount[3] = {0, 0, 0}; + +Chunk::Chunk( Level* level_, int x, int y, int z, int size, int lists_, GLuint* ptrBuf/*= NULL*/) +: level(level_), + visible(false), + compiled(false), + _empty(true), + xs(size), ys(size), zs(size), + dirty(false), + occlusion_visible(true), + occlusion_querying(false), + lists(lists_), + vboBuffers(ptrBuf), + bb(0,0,0,1,1,1), + t(Tesselator::instance) +{ + for (int l = 0; l < NumLayers; l++) { + empty[l] = false; + } + + radius = Mth::sqrt((float)(xs * xs + ys * ys + zs * zs)) * 0.5f; + + this->x = -999; + setPos(x, y, z); +} + +void Chunk::setPos( int x, int y, int z ) +{ + if (x == this->x && y == this->y && z == this->z) return; + + reset(); + this->x = x; + this->y = y; + this->z = z; + xm = x + xs / 2; + ym = y + ys / 2; + zm = z + zs / 2; + + const float xzg = 1.0f; + const float yp = 2.0f; + const float yn = 0.0f; + bb.set(x-xzg, y-yn, z-xzg, x + xs+xzg, y + ys+yp, z + zs+xzg); + + //glNewList(lists + 2, GL_COMPILE); + //ItemRenderer.renderFlat(AABB.newTemp(xRenderOffs - g, yRenderOffs - g, zRenderOffs - g, xRenderOffs + xs + g, yRenderOffs + ys + g, zRenderOffs + zs + g)); + //glEndList(); + setDirty(); +} + +void Chunk::translateToPos() +{ + glTranslatef2((float)x, (float)y, (float)z); +} + +void Chunk::rebuild() +{ + if (!dirty) return; + //if (!visible) return; + updates++; + + //if (!_layerChunks[0]) { + // for (int i = 0; i < NumLayers; ++i) + // _layerChunks[i] = new int[xs * ys * zs]; + //} + //for (int i = 0; i < NumLayers; ++i) + // _layerChunkCount[i] = 0; + + //Stopwatch& sw = swRebuild; + //sw.start(); + + int x0 = x; + int y0 = y; + int z0 = z; + int x1 = x + xs; + int y1 = y + ys; + int z1 = z + zs; + for (int l = 0; l < NumLayers; l++) { + empty[l] = true; + } + _empty = true; + + LevelChunk::touchedSky = false; + + int r = 1; + Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r); + TileRenderer tileRenderer(®ion); + + bool doRenderLayer[NumLayers] = {true, false, false}; + for (int l = 0; l < NumLayers; l++) { + if (!doRenderLayer[l]) continue; + bool renderNextLayer = false; + bool rendered = false; + + bool started = false; + int cindex = -1; + + for (int y = y0; y < y1; y++) { + for (int z = z0; z < z1; z++) { + for (int x = x0; x < x1; x++) { + ++cindex; + //if (l > 0 && cindex != _layerChunks[_layerChunkCount[l]]) + int tileId = region.getTile(x, y, z); + if (tileId > 0) { + if (!started) { + started = true; + +#ifndef USE_VBO + glNewList(lists + l, GL_COMPILE); + glPushMatrix2(); + translateToPos(); + float ss = 1.000001f; + glTranslatef2(-zs / 2.0f, -ys / 2.0f, -zs / 2.0f); + glScalef2(ss, ss, ss); + glTranslatef2(zs / 2.0f, ys / 2.0f, zs / 2.0f); +#endif + t.begin(); + //printf("."); + //printf("Tesselator::offset : %d, %d, %d\n", this->x, this->y, this->z); + t.offset((float)(-this->x), (float)(-this->y), (float)(-this->z)); + //printf("Tesselator::offset : %f, %f, %f\n", this->x, this->y, this->z); + } + + Tile* tile = Tile::tiles[tileId]; + int renderLayer = tile->getRenderLayer(); + + if (renderLayer > l) { + renderNextLayer = true; + doRenderLayer[renderLayer] = true; + } else if (renderLayer == l) { + rendered |= tileRenderer.tesselateInWorld(tile, x, y, z); + } + } + } + } + } + + if (started) { + +#ifdef USE_VBO + renderChunk[l] = t.end(true, vboBuffers[l]); + renderChunk[l].pos.x = (float)this->x; + renderChunk[l].pos.y = (float)this->y; + renderChunk[l].pos.z = (float)this->z; +#else + t.end(false, -1); + glPopMatrix2(); + glEndList(); +#endif + t.offset(0, 0, 0); + } else { + rendered = false; + } + if (rendered) { + empty[l] = false; + _empty = false; + } + if (!renderNextLayer) break; + } + + //sw.stop(); + //sw.printEvery(1, "rebuild-"); + skyLit = LevelChunk::touchedSky; + compiled = true; + return; +} + +float Chunk::distanceToSqr( const Entity* player ) const +{ + float xd = (float) (player->x - xm); + float yd = (float) (player->y - ym); + float zd = (float) (player->z - zm); + return xd * xd + yd * yd + zd * zd; +} + +float Chunk::squishedDistanceToSqr( const Entity* player ) const +{ + float xd = (float) (player->x - xm); + float yd = (float) (player->y - ym) * 2; + float zd = (float) (player->z - zm); + return xd * xd + yd * yd + zd * zd; +} + +void Chunk::reset() +{ + for (int i = 0; i < NumLayers; i++) { + empty[i] = true; + } + visible = false; + compiled = false; + _empty = true; +} + +int Chunk::getList( int layer ) +{ + if (!visible) return -1; + if (!empty[layer]) return lists + layer; + return -1; +} + +RenderChunk& Chunk::getRenderChunk( int layer ) +{ + return renderChunk[layer]; +} + +int Chunk::getAllLists( int displayLists[], int p, int layer ) +{ + if (!visible) return p; + if (!empty[layer]) displayLists[p++] = (lists + layer); + return p; +} + +void Chunk::cull( Culler* culler ) +{ + visible = culler->isVisible(bb); +} + +void Chunk::renderBB() +{ + //glCallList(lists + 2); +} + +bool Chunk::isEmpty() +{ + return compiled && _empty;//empty[0] && empty[1] && empty[2]; +// if (!compiled) return false; +// return empty[0] && empty[1]; +} + +void Chunk::setDirty() +{ + dirty = true; +} + +void Chunk::setClean() +{ + dirty = false; +} + +bool Chunk::isDirty() +{ + return dirty; +} + +void Chunk::resetUpdates() +{ + updates = 0; + //swRebuild.reset(); +} diff --git a/src/client/renderer/Chunk.h b/src/client/renderer/Chunk.hpp similarity index 95% rename from src/client/renderer/Chunk.h rename to src/client/renderer/Chunk.hpp index a532da6..0ab854a 100755 --- a/src/client/renderer/Chunk.h +++ b/src/client/renderer/Chunk.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer; -#include "RenderChunk.h" -#include "../../world/phys/AABB.h" +#include "RenderChunk.hpp" +#include "world/phys/AABB.hpp" class Level; class Entity; diff --git a/src/client/renderer/ChunkRenderer.h b/src/client/renderer/ChunkRenderer.hpp similarity index 76% rename from src/client/renderer/ChunkRenderer.h rename to src/client/renderer/ChunkRenderer.hpp index 91b2b8b..a2ee9a9 100755 --- a/src/client/renderer/ChunkRenderer.h +++ b/src/client/renderer/ChunkRenderer.hpp @@ -1,7 +1,7 @@ #pragma once -#include "gles.h" -#include "../../world/level/Region.h" +#include "gles.hpp" +#include "world/level/Region.hpp" class ChunkRenderer { public: diff --git a/src/client/renderer/Color4.h b/src/client/renderer/Color4.hpp similarity index 100% rename from src/client/renderer/Color4.h rename to src/client/renderer/Color4.hpp diff --git a/src/client/renderer/DirtyChunkSorter.h b/src/client/renderer/DirtyChunkSorter.hpp similarity index 92% rename from src/client/renderer/DirtyChunkSorter.h rename to src/client/renderer/DirtyChunkSorter.hpp index 9f2e1d4..ed23726 100755 --- a/src/client/renderer/DirtyChunkSorter.h +++ b/src/client/renderer/DirtyChunkSorter.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer; -#include "../../world/entity/Entity.h" -#include "Chunk.h" +#include "world/entity/Entity.hpp" +#include "Chunk.hpp" class DirtyChunkSorter { diff --git a/src/client/renderer/DistanceChunkSorter.h b/src/client/renderer/DistanceChunkSorter.hpp similarity index 89% rename from src/client/renderer/DistanceChunkSorter.h rename to src/client/renderer/DistanceChunkSorter.hpp index 5ab4158..d98652b 100755 --- a/src/client/renderer/DistanceChunkSorter.h +++ b/src/client/renderer/DistanceChunkSorter.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer; -#include "../../world/entity/Entity.h" -#include "Chunk.h" +#include "world/entity/Entity.hpp" +#include "Chunk.hpp" class DistanceChunkSorter { diff --git a/src/client/renderer/EntityTileRenderer.cpp b/src/client/renderer/EntityTileRenderer.cpp index d94f5d0..1950a61 100755 --- a/src/client/renderer/EntityTileRenderer.cpp +++ b/src/client/renderer/EntityTileRenderer.cpp @@ -1,8 +1,8 @@ -#include "EntityTileRenderer.h" - -EntityTileRenderer* EntityTileRenderer::instance = new EntityTileRenderer(); - -void EntityTileRenderer::render( Tile* tile, int data, float brightness ) -{ - TileEntityRenderDispatcher::getInstance()->render(&chest, 0, 0, 0, 0); -} +#include "EntityTileRenderer.hpp" + +EntityTileRenderer* EntityTileRenderer::instance = new EntityTileRenderer(); + +void EntityTileRenderer::render( Tile* tile, int data, float brightness ) +{ + TileEntityRenderDispatcher::getInstance()->render(&chest, 0, 0, 0, 0); +} diff --git a/src/client/renderer/EntityTileRenderer.h b/src/client/renderer/EntityTileRenderer.hpp similarity index 68% rename from src/client/renderer/EntityTileRenderer.h rename to src/client/renderer/EntityTileRenderer.hpp index 1fb28dc..1ceb2b7 100755 --- a/src/client/renderer/EntityTileRenderer.h +++ b/src/client/renderer/EntityTileRenderer.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer; -#include "../../world/level/tile/entity/ChestTileEntity.h" -#include "tileentity/TileEntityRenderDispatcher.h" +#include "world/level/tile/entity/ChestTileEntity.hpp" +#include "tileentity/TileEntityRenderDispatcher.hpp" class Tile; diff --git a/src/client/renderer/GameRenderer.cpp b/src/client/renderer/GameRenderer.cpp index 8dd147a..ee71628 100755 --- a/src/client/renderer/GameRenderer.cpp +++ b/src/client/renderer/GameRenderer.cpp @@ -1,957 +1,957 @@ -#include "GameRenderer.h" -#include "client/Options.h" -#include "gles.h" - -#include "../../util/PerfTimer.h" - -#include "LevelRenderer.h" -#include "ItemInHandRenderer.h" -#include "culling/AllowAllCuller.h" -#include "culling/FrustumCuller.h" -#include "entity/EntityRenderDispatcher.h" -#include -#include "../gamemode/GameMode.h" -#include "../particle/ParticleEngine.h" -#include "../player/LocalPlayer.h" -#include "../gui/Screen.h" -#include "../../world/level/Level.h" -#include "../../world/entity/Mob.h" -#include "../../world/level/chunk/ChunkCache.h" -#include "../../world/level/material/Material.h" -#include "../../world/Facing.h" -#include "../../platform/input/Controller.h" -#include "../../platform/input/Mouse.h" -#include "../../platform/input/Multitouch.h" -#include "../../NinecraftApp.h" -#include "../../world/level/tile/Tile.h" -#include "../player/input/IInputHolder.h" -#include "Textures.h" -#include "../gui/components/ImageButton.h" -#include "Tesselator.h" - -static int _shTicks = -1; - -GameRenderer::GameRenderer( Minecraft* mc ) -: mc(mc), - renderDistance(0), - _tick(0), - _lastTickT(0), - fovOffset(0), - fovOffsetO(0), - fov(1), oFov(1), - _setupCameraFov(0), - zoom(1), zoom_x(0), zoom_y(0), - cameraRoll(0), cameraRollO(0), - pickDirection(1, 0, 0), - - thirdDistance(4), thirdDistanceO(4), - thirdRotation(0), thirdRotationO(0), - thirdTilt(0), thirdTiltO(0), - - fogBr(0), fogBrO(0), - - fr(0), fg(0), fb(0), - _rotX(0), _rotY(0), - _rotXlast(0), _rotYlast(0), - useScreenScissor(false) -{ - saveMatrices(); - - itemInHandRenderer = new ItemInHandRenderer(mc); - - EntityRenderDispatcher* e = EntityRenderDispatcher::getInstance(); - e->itemInHandRenderer = itemInHandRenderer; - e->textures = mc->textures; -} - -GameRenderer::~GameRenderer() { - delete itemInHandRenderer; -} - -void renderCursor(float x, float y, Minecraft* minecraft) { - Tesselator& t = Tesselator::instance; - - minecraft->textures->loadAndBindTexture("gui/cursor.png"); - glEnable(GL_BLEND); - - const float s = 32; - const float width = 16; - const float height = 16; - t.begin(); - t.color(0xffffffff); - t.vertexUV(x, y + (float)height, 0, 0, 1); - t.vertexUV(x + (float)width, y + (float)height, 0, 1, 1); - t.vertexUV(x + (float)width, y, 0, 1, 0); - t.vertexUV(x, y, 0, 0, 0); - t.draw(); - - glDisable(GL_BLEND); -} - -/*private*/ -void GameRenderer::setupCamera(float a, int eye) { - renderDistance = (float) (16 * 16 >> (mc->options.getIntValue(OPTIONS_VIEW_DISTANCE))); -#if defined(ANDROID) - if (mc->isPowerVR() && mc->options.getIntValue(OPTIONS_VIEW_DISTANCE) <= 2) - renderDistance *= 0.8f; -#endif - - glMatrixMode(GL_PROJECTION); - glLoadIdentity2(); - - float stereoScale = 0.07f; - if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2(-(eye * 2 - 1) * stereoScale, 0, 0); - if (zoom != 1) { - glTranslatef2((float) zoom_x, (float) -zoom_y, 0); - glScalef2(zoom, zoom, 1); - gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 0.05f, renderDistance); - } else { - gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 0.05f, renderDistance); - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity2(); - if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2((eye * 2 - 1) * 0.10f, 0, 0); - - bobHurt(a); - if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a); - - moveCameraToPlayer(a); -} - -extern int _t_keepPic; - -/*public*/ -void GameRenderer::render(float a) { - TIMER_PUSH("mouse"); - if (mc->player && mc->mouseGrabbed) { - mc->mouseHandler.poll(); - //printf("Controller.x,y : %f,%f\n", Controller::getX(0), Controller::getY(0)); - - float ss = mc->options.getProgressValue(OPTIONS_SENSITIVITY) * 0.6f + 0.2f; - float sens = (ss * ss * ss) * 8; - float xo = mc->mouseHandler.xd * sens * 4.f; - float yo = mc->mouseHandler.yd * sens * 4.f; - - const float now = _tick + a; - float deltaT = now - _lastTickT; - if (deltaT > 3.0f) deltaT = 3.0f; - _lastTickT = now; - - _rotX += xo; - _rotY += yo; - - int yAxis = -1; - if (mc->options.getBooleanValue(OPTIONS_INVERT_Y_MOUSE)) yAxis = 1; - - bool screenCovering = mc->screen && !mc->screen->passEvents; - if (!screenCovering) - { - mc->player->turn(deltaT * _rotXlast, deltaT * _rotYlast * yAxis); - } - } - - int xMouse = (int)(Mouse::getX() * Gui::InvGuiScale); - int yMouse = (int)(Mouse::getY() * Gui::InvGuiScale); - - if (mc->useTouchscreen()) { - const int pid = Multitouch::getFirstActivePointerIdExThisUpdate(); - if (pid >= 0) { - xMouse = (int)(Multitouch::getX(pid) * Gui::InvGuiScale); - yMouse = (int)(Multitouch::getY(pid) * Gui::InvGuiScale); - } else { - xMouse = -9999; - yMouse = -9999; - } - } - TIMER_POP(); - - bool hasClearedColorBuffer = false; - bool hasSetupGuiScreen = false; - useScreenScissor = false; - if (mc->isLevelGenerated()) { - - TIMER_PUSH("level"); - if (_t_keepPic < 0) { - if (!(mc->screen && !mc->screen->renderGameBehind())) { - - if (mc->screen && mc->screen->hasClippingArea(screenScissorArea)) - useScreenScissor = true; - - renderLevel(a); - hasClearedColorBuffer = true; - - if (!mc->options.getBooleanValue(OPTIONS_HIDEGUI)) { - TIMER_POP_PUSH("gui"); - setupGuiScreen(false); - hasSetupGuiScreen = true; - mc->gui.render(a, mc->screen != NULL, xMouse, yMouse); - } - }} - TIMER_POP(); - - } else { - glViewport(0, 0, mc->width, mc->height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity2(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity2(); - setupGuiScreen(true); - hasSetupGuiScreen = true; - hasClearedColorBuffer = true; - } - //@todo - if (!hasSetupGuiScreen) - setupGuiScreen(!hasClearedColorBuffer); - - if (mc->player && mc->screen == NULL) { - if (mc->inputHolder) mc->inputHolder->render(a); - if (mc->player->input) mc->player->input->render(a); - } - - if (mc->screen != NULL) { - if (useScreenScissor) - glDisable2(GL_SCISSOR_TEST); - - mc->screen->render(xMouse, yMouse, a); - - mc->platform()->hideCursor(!mc->options.getBooleanValue(OPTIONS_RPI_CURSOR)); - if (mc->options.getBooleanValue(OPTIONS_RPI_CURSOR)) - renderCursor(xMouse, yMouse, mc); - - // Screen might have been removed, so check it again - if (mc->screen && !mc->screen->isInGameScreen()) - sleepMs(15); - } -} - -/*public*/ -void GameRenderer::renderLevel(float a) { - - if (mc->cameraTargetPlayer == NULL) { - if (mc->player) - { - mc->cameraTargetPlayer = mc->player; - } - else - { - return; - } - } - - TIMER_PUSH("pick"); - pick(a); - - Mob* cameraEntity = mc->cameraTargetPlayer; - LevelRenderer* levelRenderer = mc->levelRenderer; - ParticleEngine* particleEngine = mc->particleEngine; - float xOff = cameraEntity->xOld + (cameraEntity->x - cameraEntity->xOld) * a; - float yOff = cameraEntity->yOld + (cameraEntity->y - cameraEntity->yOld) * a; - float zOff = cameraEntity->zOld + (cameraEntity->z - cameraEntity->zOld) * a; - - for (int i = 0; i < 2; i++) { - if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { - if (i == 0) glColorMask(false, true, true, false); - else glColorMask(true, false, false, false); - } - - TIMER_POP_PUSH("clear"); - glViewport(0, 0, mc->width, mc->height); - setupClearColor(a); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glEnable2(GL_CULL_FACE); - - TIMER_POP_PUSH("camera"); - setupCamera(a, i); - saveMatrices(); - - if (useScreenScissor) { - glEnable2(GL_SCISSOR_TEST); - glScissor( screenScissorArea.x, screenScissorArea.y, - screenScissorArea.w, screenScissorArea.h); - } - - if(mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS)) { - setupFog(-1); - TIMER_POP_PUSH("sky"); - glFogf(GL_FOG_START, renderDistance * 0.2f); - glFogf(GL_FOG_END, renderDistance *0.75); - levelRenderer->renderSky(a); - glFogf(GL_FOG_START, renderDistance * 0.6f); - glFogf(GL_FOG_END, renderDistance); - } - glEnable2(GL_FOG); - setupFog(1); - - if (mc->options.getBooleanValue(OPTIONS_AMBIENT_OCCLUSION)) { - glShadeModel2(GL_SMOOTH); - } - - TIMER_POP_PUSH("frustrum"); - FrustumCuller frustum; - frustum.prepare(xOff, yOff, zOff); - - TIMER_POP_PUSH("culling"); - mc->levelRenderer->cull(&frustum, a); - mc->levelRenderer->updateDirtyChunks(cameraEntity, false); - - if(mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS)) { - prepareAndRenderClouds(levelRenderer, a); - } - - setupFog(0); - glEnable2(GL_FOG); - - mc->textures->loadAndBindTexture("terrain.png"); - glDisable2(GL_ALPHA_TEST); - glDisable2(GL_BLEND); - glEnable2(GL_CULL_FACE); - TIMER_POP_PUSH("terrain-0"); - levelRenderer->render(cameraEntity, 0, a); - - TIMER_POP_PUSH("terrain-1"); - glEnable2(GL_ALPHA_TEST); - levelRenderer->render(cameraEntity, 1, a); - - glShadeModel2(GL_FLAT); - TIMER_POP_PUSH("entities"); - mc->levelRenderer->renderEntities(cameraEntity->getPos(a), &frustum, a); -// setupFog(0); - TIMER_POP_PUSH("particles"); - particleEngine->render(cameraEntity, a); - - glDisable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - setupFog(0); - glEnable2(GL_BLEND); - glDisable2(GL_CULL_FACE); - glDepthMask(GL_FALSE); - glDisable2(GL_ALPHA_TEST); - mc->textures->loadAndBindTexture("terrain.png"); - //if (mc->options.fancyGraphics) { - // glColorMask(false, false, false, false); - // int visibleWaterChunks = levelRenderer->render(cameraEntity, 1, a); - // glColorMask(true, true, true, true); - // if (mc->options.anaglyph3d) { - // if (i == 0) glColorMask(false, true, true, false); - // else glColorMask(true, false, false, false); - // } - // if (visibleWaterChunks > 0) { - // levelRenderer->renderSameAsLast(1, a); - // } - //} else - { - //glDepthRangef(0.1f, 1.0f); - //glDepthMask(GL_FALSE); - TIMER_POP_PUSH("terrain-water"); - glEnable2(GL_DEPTH_TEST); - levelRenderer->render(cameraEntity, 2, a); - //glDepthRangef(0, 1); - - } - - glDepthMask(GL_TRUE); - glEnable2(GL_CULL_FACE); - glDisable2(GL_BLEND); - glEnable2(GL_ALPHA_TEST); - - if (/*!Minecraft::FLYBY_MODE &&*/ zoom == 1 && cameraEntity->isPlayer()) { - if (mc->hitResult.isHit() && !cameraEntity->isUnderLiquid(Material::water)) { - TIMER_POP_PUSH("select"); - Player* player = (Player*) cameraEntity; - // if (mc->useTouchscreen()) { - levelRenderer->renderHitSelect(player, mc->hitResult, 0, NULL, a); //player.inventory->getSelected(), a); - // } - levelRenderer->renderHit(player, mc->hitResult, 0, NULL, a);//player->inventory.getSelected(), a); - } - } - - glDisable2(GL_FOG); -// -// setupFog(0); -// glEnable2(GL_FOG); -//// levelRenderer->renderClouds(a); -// glDisable2(GL_FOG); - setupFog(1); - - if (zoom == 1 && !mc->options.getBooleanValue(OPTIONS_HIDEGUI)) { - TIMER_POP_PUSH("hand"); - glClear(GL_DEPTH_BUFFER_BIT); - renderItemInHand(a, i); - } - - if (!mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { - TIMER_POP(); - return; - } - } - glColorMask(true, true, true, false); - TIMER_POP(); -} - -void GameRenderer::tickFov() { - if (mc->cameraTargetPlayer != mc->player) - return; - - oFov = fov; - fov += (mc->player->getFieldOfViewModifier() - fov) * 0.5f; -} - -/*private*/ -float GameRenderer::getFov(float a, bool applyEffects) { - Mob* player = mc->cameraTargetPlayer; - float fov = 70; - - if (applyEffects) - fov *= this->oFov + (this->fov - this->oFov) * a; - - if (player->isUnderLiquid(Material::water)) fov = 60; - if (player->health <= 0) { - float duration = player->deathTime + a; - - fov /= ((1 - 500 / (duration + 500)) * 2.0f + 1); - } - return fov + fovOffsetO + (fovOffset - fovOffsetO) * a; -} - -/*private*/ -void GameRenderer::moveCameraToPlayer(float a) { - Entity* player = mc->cameraTargetPlayer; - - float heightOffset = player->heightOffset - 1.62f; - - float x = player->xo + (player->x - player->xo) * a; - float y = player->yo + (player->y - player->yo) * a - heightOffset; - //printf("camera y: %f\n", y); - float z = player->zo + (player->z - player->zo) * a; - - //printf("rot: %f %f\n", cameraRollO, cameraRoll); - glRotatef2(cameraRollO + (cameraRoll - cameraRollO) * a, 0, 0, 1); - - //LOGI("player. alive, removed: %d, %d\n", player->isAlive(), player->removed); - if(player->isPlayer() && ((Player*)player)->isSleeping()) { - heightOffset += 1.0; - glTranslatef(0.0f, 0.3f, 0); - if (!mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) { - int t = mc->level->getTile(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); - if (t == Tile::bed->id) { - int data = mc->level->getData(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); - - int direction = data & 3; - glRotatef(float(direction * 90), 0, 1, 0); - } - glRotatef(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, -1, 0); - glRotatef(player->xRotO + (player->xRot - player->xRotO) * a, -1, 0, 0); - } - } else if (mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW)/* || (player->isPlayer() && !player->isAlive())*/) { - float cameraDist = thirdDistanceO + (thirdDistance - thirdDistanceO) * a; - - if (mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) { - - float rotationY = thirdRotationO + (thirdRotation - thirdRotationO) * a; - float xRot = thirdTiltO + (thirdTilt - thirdTiltO) * a; - - glTranslatef2(0, 0, (float) -cameraDist); - glRotatef2(xRot, 1, 0, 0); - glRotatef2(rotationY, 0, 1, 0); - } else { - float yRot = player->yRot; - float xRot = player->xRot/* + 180.0f*/; - float xd = -Mth::sin(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * cameraDist; - float zd = Mth::cos(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * cameraDist; - float yd = -Mth::sin(xRot / 180 * Mth::PI) * cameraDist; - - for (int i = 0; i < 8; i++) { - float xo = (float)((i & 1) * 2 - 1); - float yo = (float)(((i >> 1) & 1) * 2 - 1); - float zo = (float)(((i >> 2) & 1) * 2 - 1); - - xo *= 0.1f; - yo *= 0.1f; - zo *= 0.1f; - - HitResult hr = mc->level->clip(Vec3(x + xo, y + yo, z + zo), Vec3(x - xd + xo + zo, y - yd + yo, z - zd + zo)); // newTemp - if (hr.type != NO_HIT) { - float dist = hr.pos.distanceTo(Vec3(x, y, z)); // newTemp - if (dist < cameraDist) cameraDist = dist; - } - } - - //glRotatef2(180, 0, 1, 0); - - glRotatef2(player->xRot - xRot, 1, 0, 0); - glRotatef2(player->yRot - yRot, 0, 1, 0); - glTranslatef2(0, 0, (float) -cameraDist); - glRotatef2(yRot - player->yRot, 0, 1, 0); - glRotatef2(xRot - player->xRot, 1, 0, 0); - } - } else { - glTranslatef2(0, 0, -0.1f); - } - - if (!mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) { - glRotatef2(player->xRotO + (player->xRot - player->xRotO) * a, 1.0f, 0.0f, 0.0f); - glRotatef2(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, 1, 0); - //if (_t_keepPic > 0) - } - glTranslatef2(0, heightOffset, 0); -} - -/*private*/ -void GameRenderer::bobHurt(float a) { - Mob* player = mc->cameraTargetPlayer; - - float hurt = player->hurtTime - a; - - if (player->health <= 0) { - float duration = player->deathTime + a; - glRotatef2(40 - (40 * 200) / (duration + 200), 0, 0, 1); - } - - if (player->hurtTime <= 0) return; - - hurt /= player->hurtDuration; - hurt = (float) Mth::sin(hurt * hurt * hurt * hurt * Mth::PI); - - float rr = player->hurtDir; - - glRotatef2(-rr, 0, 1, 0); - glRotatef2(-hurt * 14, 0, 0, 1); - glRotatef2(+rr, 0, 1, 0); -} - -/*private*/ -void GameRenderer::bobView(float a) { - //if (mc->options.thirdPersonView) return; - if (!(mc->cameraTargetPlayer->isPlayer())) { - return; - } - Player* player = (Player*) mc->cameraTargetPlayer; - - float wda = player->walkDist - player->walkDistO; - float b = -(player->walkDist + wda * a); - float bob = player->oBob + (player->bob - player->oBob) * a; - float tilt = player->oTilt + (player->tilt - player->oTilt) * a; - glTranslatef2((float) Mth::sin(b * Mth::PI) * bob * 0.5f, -(float) std::abs(Mth::cos(b * Mth::PI) * bob), 0); - glRotatef2((float) Mth::sin(b * Mth::PI) * bob * 3, 0, 0, 1); - glRotatef2((float) std::abs(Mth::cos(b * Mth::PI - 0.2f) * bob) * 5, 1, 0, 0); - glRotatef2((float) tilt, 1, 0, 0); -} - -/*private*/ -void GameRenderer::setupFog(int i) { - Mob* player = mc->cameraTargetPlayer; - float fogBuffer[4] = {fr, fg, fb, 1}; - - glFogfv(GL_FOG_COLOR, (GLfloat*)fogBuffer); - glColor4f2(1, 1, 1, 1); - - if (player->isUnderLiquid(Material::water)) { - glFogx(GL_FOG_MODE, GL_EXP); - glFogf(GL_FOG_DENSITY, 0.1f); // was 0.06 - -// float rr = 0.4f; -// float gg = 0.4f; -// float bb = 0.9f; -// -// if (mc->options.anaglyph3d) { -// float rrr = (rr * 30 + gg * 59 + bb * 11) / 100; -// float ggg = (rr * 30 + gg * 70) / (100); -// float bbb = (rr * 30 + bb * 70) / (100); -// -// rr = rrr; -// gg = ggg; -// bb = bbb; -// } - } else if (player->isUnderLiquid(Material::lava)) { - glFogx(GL_FOG_MODE, GL_EXP); - glFogf(GL_FOG_DENSITY, 2.f); // was 0.06 -// float rr = 0.4f; -// float gg = 0.3f; -// float bb = 0.3f; -// -// if (mc->options.anaglyph3d) { -// float rrr = (rr * 30 + gg * 59 + bb * 11) / 100; -// float ggg = (rr * 30 + gg * 70) / (100); -// float bbb = (rr * 30 + bb * 70) / (100); -// -// rr = rrr; -// gg = ggg; -// bb = bbb; -// } - } else { - glFogx(GL_FOG_MODE, GL_LINEAR); - glFogf(GL_FOG_START, renderDistance * 0.6f); - glFogf(GL_FOG_END, renderDistance); - if (i < 0) { - glFogf(GL_FOG_START, 0); - glFogf(GL_FOG_END, renderDistance * 1.0f); - } - - if (mc->level->dimension->foggy) { - glFogf(GL_FOG_START, 0); - } - } - - glEnable2(GL_COLOR_MATERIAL); - //glColorMaterial(GL_FRONT, GL_AMBIENT); -} - -void GameRenderer::updateAllChunks() { - mc->levelRenderer->updateDirtyChunks(mc->cameraTargetPlayer, true); -} - -bool GameRenderer::updateFreeformPickDirection(float a, Vec3& outDir) { - - if (!mc->inputHolder->allowPicking()) { - _shTicks = 1; - return false; - } - - Vec3 c = mc->cameraTargetPlayer->getPos(a); - - bool firstPerson = !mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW); - const float PickingDistance = firstPerson? 6.0f : 12.0f; - - _shTicks = -1; - - int vp[4] = {0, 0, mc->width, mc->height}; - float pt[3]; - float x = mc->inputHolder->mousex; - float y = mc->height - mc->inputHolder->mousey; - - //sw.start(); - - if (!glhUnProjectf(x, y, 1, lastModelMatrix, lastProjMatrix, vp, pt)) { - return false; - } - Vec3 p1(pt[0] + c.x, pt[1] + c.y, pt[2] + c.z); - - glhUnProjectf(x, y, 0, lastModelMatrix, lastProjMatrix, vp, pt); - Vec3 p0(pt[0] + c.x, pt[1] + c.y, pt[2] + c.z); - - outDir = (p1 - p0).normalized(); - p1 = p0 + outDir * PickingDistance; - - //sw.stop(); - //sw.printEvery(30, "unproject "); - - const HitResult& hit = mc->hitResult = mc->level->clip(p0, p1, false); - - // If in 3rd person view - verify that the hit target is within range - if (!firstPerson && hit.isHit()) { - const float MaxSqrDist = PickingDistance*PickingDistance; - if (mc->cameraTargetPlayer->distanceToSqr((float)hit.x, (float)hit.y, (float)hit.z) > MaxSqrDist) - mc->hitResult.type = NO_HIT; - } - return true; -} - -/*public*/ -void GameRenderer::pick(float a) { - if (mc->level == NULL) return; - if (mc->cameraTargetPlayer == NULL) return; - if (!mc->cameraTargetPlayer->isAlive()) return; - - float range = mc->gameMode->getPickRange(); - bool isPicking = true; - - bool freeform = mc->useTouchscreen(); //&& !mc->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA); - - if (freeform) { - isPicking = updateFreeformPickDirection(a, pickDirection); - } else { - mc->hitResult = mc->cameraTargetPlayer->pick(range, a); - pickDirection = mc->cameraTargetPlayer->getViewVector(a); - } - - Vec3 from = mc->cameraTargetPlayer->getPos(a); - float dist = range; - if (mc->hitResult.isHit()) { - dist = mc->hitResult.pos.distanceTo(from); - } - - if (mc->gameMode->isCreativeType()) { - /*dist =*/ range = 12; - } else { - if (dist > 3) dist = 3; - range = dist; - } - - Vec3 pv = (pickDirection * range); - Vec3 to = from + pv; - mc->cameraTargetPlayer->aimDirection = pickDirection; - - Entity* hovered = NULL; - const float g = 1; - AABB aabb = mc->cameraTargetPlayer->bb.expand(pv.x, pv.y, pv.z).grow(g, g, g); - EntityList& objects = mc->level->getEntities(mc->cameraTargetPlayer, aabb); - float nearest = 0; - for (unsigned int i = 0; i < objects.size(); i++) { - Entity* e = objects[i]; - if (!e->isPickable()) continue; - - float rr = e->getPickRadius(); - AABB bb = e->bb.grow(rr, rr, rr); - HitResult p = bb.clip(from, to); - //printf("Clip Hitresult %d (%d)\n", p.type, p.isHit()); - - if (bb.contains(from)) { - //@todo: hovered = e; break; ? - if (nearest >= 0) { - hovered = e; - nearest = 0; - } - } else if (p.isHit()) { - float dd = from.distanceTo(p.pos); - if (dd < nearest || nearest == 0) { - hovered = e; - nearest = dd; - } - } - } - - if (hovered != NULL) { - if(nearest < dist) { - mc->hitResult = HitResult(hovered); - } - } - else if (isPicking && !mc->hitResult.isHit()) { - // if we don't have a hit result, attempt to hit the edge of the block we are standing on - // (this is an pocket edition simplification to help building floors) - //LOGI("hovered : %d (%f)\n", mc->hitResult.type, viewVec.y); - if (pickDirection.y < -.7f) { - // looking down by more than roughly 45 degrees, fetch a hit to the block standing on - Vec3 to = from.add(0, -2.0f, 0); - - HitResult downHitResult = mc->level->clip(from, to); - if (downHitResult.isHit()) { - mc->hitResult = downHitResult; - mc->hitResult.indirectHit = true; - // change face (not up) - if (std::abs(pickDirection.x) > std::abs(pickDirection.z)) { - mc->hitResult.f = (pickDirection.x < 0)? 4 : 5; - } else { - mc->hitResult.f = (pickDirection.z < 0)? 2 : 3; - } - } - } - } -} -/*public*/ -void GameRenderer::tick(int nTick, int maxTick) { - --_t_keepPic; - - if (!mc->player) - { - return; - } - - if (--_shTicks == 0) - mc->hitResult.type = NO_HIT; - - //_rotXlast = _rotX; - //_rotYlast = _rotY; - - //LOGI("x: %f\n", _rotX); - - if (nTick == maxTick) { - const float tickMult = 1.0f / (float)(1 + maxTick); - _rotXlast = 0.4f * std::pow(std::abs(_rotX), 1.2f) * tickMult; - if (_rotX < 0) _rotXlast = -_rotXlast; - - _rotYlast = 0.4f * std::pow(std::abs(_rotY), 1.2f) * tickMult; - if (_rotY < 0) _rotYlast = -_rotYlast; - - _rotX = 0; - _rotY = 0; - } - - fogBrO = fogBr; - thirdDistanceO = thirdDistance; - thirdRotationO = thirdRotation; - thirdTiltO = thirdTilt; - fovOffsetO = fovOffset; - cameraRollO = cameraRoll; - - if (mc->cameraTargetPlayer == NULL) { - mc->cameraTargetPlayer = mc->player; - } - - tickFov(); - - float brr = mc->level->getBrightness( Mth::floor(mc->cameraTargetPlayer->x), - Mth::floor(mc->cameraTargetPlayer->y), - Mth::floor(mc->cameraTargetPlayer->z)); - - float whiteness = (3 - mc->options.getIntValue(OPTIONS_VIEW_DISTANCE)) / 3.0f; - float fogBrT = brr * (1 - whiteness) + whiteness; - fogBr += (fogBrT - fogBr) * 0.1f; - - _tick++; - - itemInHandRenderer->tick(); -// if (mc->isRaining) tickRain(); -} - -/*private*/ -void GameRenderer::setupClearColor(float a) { - Level* level = mc->level; - Mob* player = mc->cameraTargetPlayer; - - float whiteness = 1.0f / (4 - mc->options.getIntValue(OPTIONS_VIEW_DISTANCE)); - whiteness = 1 - (float) pow(whiteness, 0.25f); - - Vec3 skyColor = level->getSkyColor(mc->cameraTargetPlayer, a); - float sr = (float) skyColor.x; - float sg = (float) skyColor.y; - float sb = (float) skyColor.z; - - Vec3 fogColor = level->getFogColor(a); - fr = (float) fogColor.x; - fg = (float) fogColor.y; - fb = (float) fogColor.z; - - fr += (sr - fr) * whiteness; - fg += (sg - fg) * whiteness; - fb += (sb - fb) * whiteness; - - if (player->isUnderLiquid(Material::water)) { - fr = 0.02f; - fg = 0.02f; - fb = 0.2f; - } else if (player->isUnderLiquid(Material::lava)) { - fr = 0.6f; - fg = 0.1f; - fb = 0.00f; - } - - float brr = fogBrO + (fogBr - fogBrO) * a; - fr *= brr; - fg *= brr; - fb *= brr; - - if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { - float frr = (fr * 30 + fg * 59 + fb * 11) / 100; - float fgg = (fr * 30 + fg * 70) / (100); - float fbb = (fr * 30 + fb * 70) / (100); - - fr = frr; - fg = fgg; - fb = fbb; - } - - glClearColor(fr, fg, fb, 1.0f); -} - -void GameRenderer::zoomRegion( float zoom, float xa, float ya ) -{ - this->zoom = zoom; - this->zoom_x = xa; - this->zoom_y = ya; -} - -void GameRenderer::unZoomRegion() -{ - zoom = 1; -} - -void GameRenderer::setupGuiScreen( bool clearColorBuffer ) -{ - int screenWidth = (int)(mc->width * Gui::InvGuiScale); - int screenHeight = (int)(mc->height * Gui::InvGuiScale); - - // Setup GUI render mode - GLbitfield clearBits = clearColorBuffer? - GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT - : GL_DEPTH_BUFFER_BIT; - glClear(clearBits); - glMatrixMode(GL_PROJECTION); - glLoadIdentity2(); - glOrthof(0, (GLfloat)screenWidth, (GLfloat)screenHeight, 0, 2000, 3000); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity2(); - glTranslatef2(0, 0, -2000); -} - -/*private*/ -void GameRenderer::renderItemInHand(float a, int eye) { - glLoadIdentity2(); - if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2((eye * 2 - 1) * 0.10f, 0, 0); - - glPushMatrix2(); - bobHurt(a); - if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a); - - if (!mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW) && (mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping())) { - if (!mc->options.getBooleanValue(OPTIONS_HIDEGUI)) { - float fov = getFov(a, false); - if (fov != _setupCameraFov) { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(fov, mc->width / (float) mc->height, 0.05f, renderDistance); - glMatrixMode(GL_MODELVIEW); - } - itemInHandRenderer->render(a); - } - } - - glPopMatrix2(); - if (!mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW) && (mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping())) { - itemInHandRenderer->renderScreenEffect(a); - bobHurt(a); - } - if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a); -} - -void GameRenderer::onGraphicsReset() -{ - if (itemInHandRenderer) itemInHandRenderer->onGraphicsReset(); -} - -void GameRenderer::saveMatrices() -{ - #if defined(RPI) - return; - #endif - - static bool saved = false; - //if (saved) return; - - saved = true; - - glGetFloatv(GL_PROJECTION_MATRIX, lastProjMatrix); - glGetFloatv(GL_MODELVIEW_MATRIX, lastModelMatrix); -} - -void GameRenderer::prepareAndRenderClouds( LevelRenderer* levelRenderer, float a ) { - //if(mc->options.isCloudsOn()) { - TIMER_PUSH("clouds"); - glMatrixMode(GL_PROJECTION); - glPushMatrix2(); - glLoadIdentity2(); - gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 2, renderDistance * 512); - glMatrixMode(GL_MODELVIEW); - glPushMatrix2(); - setupFog(0); - glDepthMask(false); - glEnable2(GL_FOG); - glFogf(GL_FOG_START, renderDistance * 0.2f); - glFogf(GL_FOG_END, renderDistance * 0.75f); - levelRenderer->renderSky(a); - glFogf(GL_FOG_START, renderDistance * 4.2f * 0.6f); - glFogf(GL_FOG_END, renderDistance * 4.2f); - levelRenderer->renderClouds(a); - glFogf(GL_FOG_START, renderDistance * 0.6f); - glFogf(GL_FOG_END, renderDistance); - glDisable2(GL_FOG); - glDepthMask(true); - setupFog(1); - glPopMatrix2(); - glMatrixMode(GL_PROJECTION); - glPopMatrix2(); - glMatrixMode(GL_MODELVIEW); - TIMER_POP(); - //} -} +#include "GameRenderer.hpp" +#include "client/Options.hpp" +#include "gles.hpp" + +#include "util/PerfTimer.hpp" + +#include "LevelRenderer.hpp" +#include "ItemInHandRenderer.hpp" +#include "culling/AllowAllCuller.hpp" +#include "culling/FrustumCuller.hpp" +#include "entity/EntityRenderDispatcher.hpp" +#include +#include "client/gamemode/GameMode.hpp" +#include "client/particle/ParticleEngine.hpp" +#include "client/player/LocalPlayer.hpp" +#include "client/gui/Screen.hpp" +#include "world/level/Level.hpp" +#include "world/entity/Mob.hpp" +#include "world/level/chunk/ChunkCache.hpp" +#include "world/level/material/Material.hpp" +#include "world/Facing.hpp" +#include "platform/input/Controller.hpp" +#include "platform/input/Mouse.hpp" +#include "platform/input/Multitouch.hpp" +#include "NinecraftApp.hpp" +#include "world/level/tile/Tile.hpp" +#include "client/player/input/IInputHolder.hpp" +#include "Textures.hpp" +#include "client/gui/components/ImageButton.hpp" +#include "Tesselator.hpp" + +static int _shTicks = -1; + +GameRenderer::GameRenderer( Minecraft* mc ) +: mc(mc), + renderDistance(0), + _tick(0), + _lastTickT(0), + fovOffset(0), + fovOffsetO(0), + fov(1), oFov(1), + _setupCameraFov(0), + zoom(1), zoom_x(0), zoom_y(0), + cameraRoll(0), cameraRollO(0), + pickDirection(1, 0, 0), + + thirdDistance(4), thirdDistanceO(4), + thirdRotation(0), thirdRotationO(0), + thirdTilt(0), thirdTiltO(0), + + fogBr(0), fogBrO(0), + + fr(0), fg(0), fb(0), + _rotX(0), _rotY(0), + _rotXlast(0), _rotYlast(0), + useScreenScissor(false) +{ + saveMatrices(); + + itemInHandRenderer = new ItemInHandRenderer(mc); + + EntityRenderDispatcher* e = EntityRenderDispatcher::getInstance(); + e->itemInHandRenderer = itemInHandRenderer; + e->textures = mc->textures; +} + +GameRenderer::~GameRenderer() { + delete itemInHandRenderer; +} + +void renderCursor(float x, float y, Minecraft* minecraft) { + Tesselator& t = Tesselator::instance; + + minecraft->textures->loadAndBindTexture("gui/cursor.png"); + glEnable(GL_BLEND); + + const float s = 32; + const float width = 16; + const float height = 16; + t.begin(); + t.color(0xffffffff); + t.vertexUV(x, y + (float)height, 0, 0, 1); + t.vertexUV(x + (float)width, y + (float)height, 0, 1, 1); + t.vertexUV(x + (float)width, y, 0, 1, 0); + t.vertexUV(x, y, 0, 0, 0); + t.draw(); + + glDisable(GL_BLEND); +} + +/*private*/ +void GameRenderer::setupCamera(float a, int eye) { + renderDistance = (float) (16 * 16 >> (mc->options.getIntValue(OPTIONS_VIEW_DISTANCE))); +#if defined(ANDROID) + if (mc->isPowerVR() && mc->options.getIntValue(OPTIONS_VIEW_DISTANCE) <= 2) + renderDistance *= 0.8f; +#endif + + glMatrixMode(GL_PROJECTION); + glLoadIdentity2(); + + float stereoScale = 0.07f; + if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2(-(eye * 2 - 1) * stereoScale, 0, 0); + if (zoom != 1) { + glTranslatef2((float) zoom_x, (float) -zoom_y, 0); + glScalef2(zoom, zoom, 1); + gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 0.05f, renderDistance); + } else { + gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 0.05f, renderDistance); + } + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity2(); + if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2((eye * 2 - 1) * 0.10f, 0, 0); + + bobHurt(a); + if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a); + + moveCameraToPlayer(a); +} + +extern int _t_keepPic; + +/*public*/ +void GameRenderer::render(float a) { + TIMER_PUSH("mouse"); + if (mc->player && mc->mouseGrabbed) { + mc->mouseHandler.poll(); + //printf("Controller.x,y : %f,%f\n", Controller::getX(0), Controller::getY(0)); + + float ss = mc->options.getProgressValue(OPTIONS_SENSITIVITY) * 0.6f + 0.2f; + float sens = (ss * ss * ss) * 8; + float xo = mc->mouseHandler.xd * sens * 4.f; + float yo = mc->mouseHandler.yd * sens * 4.f; + + const float now = _tick + a; + float deltaT = now - _lastTickT; + if (deltaT > 3.0f) deltaT = 3.0f; + _lastTickT = now; + + _rotX += xo; + _rotY += yo; + + int yAxis = -1; + if (mc->options.getBooleanValue(OPTIONS_INVERT_Y_MOUSE)) yAxis = 1; + + bool screenCovering = mc->screen && !mc->screen->passEvents; + if (!screenCovering) + { + mc->player->turn(deltaT * _rotXlast, deltaT * _rotYlast * yAxis); + } + } + + int xMouse = (int)(Mouse::getX() * Gui::InvGuiScale); + int yMouse = (int)(Mouse::getY() * Gui::InvGuiScale); + + if (mc->useTouchscreen()) { + const int pid = Multitouch::getFirstActivePointerIdExThisUpdate(); + if (pid >= 0) { + xMouse = (int)(Multitouch::getX(pid) * Gui::InvGuiScale); + yMouse = (int)(Multitouch::getY(pid) * Gui::InvGuiScale); + } else { + xMouse = -9999; + yMouse = -9999; + } + } + TIMER_POP(); + + bool hasClearedColorBuffer = false; + bool hasSetupGuiScreen = false; + useScreenScissor = false; + if (mc->isLevelGenerated()) { + + TIMER_PUSH("level"); + if (_t_keepPic < 0) { + if (!(mc->screen && !mc->screen->renderGameBehind())) { + + if (mc->screen && mc->screen->hasClippingArea(screenScissorArea)) + useScreenScissor = true; + + renderLevel(a); + hasClearedColorBuffer = true; + + if (!mc->options.getBooleanValue(OPTIONS_HIDEGUI)) { + TIMER_POP_PUSH("gui"); + setupGuiScreen(false); + hasSetupGuiScreen = true; + mc->gui.render(a, mc->screen != NULL, xMouse, yMouse); + } + }} + TIMER_POP(); + + } else { + glViewport(0, 0, mc->width, mc->height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity2(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity2(); + setupGuiScreen(true); + hasSetupGuiScreen = true; + hasClearedColorBuffer = true; + } + //@todo + if (!hasSetupGuiScreen) + setupGuiScreen(!hasClearedColorBuffer); + + if (mc->player && mc->screen == NULL) { + if (mc->inputHolder) mc->inputHolder->render(a); + if (mc->player->input) mc->player->input->render(a); + } + + if (mc->screen != NULL) { + if (useScreenScissor) + glDisable2(GL_SCISSOR_TEST); + + mc->screen->render(xMouse, yMouse, a); + + mc->platform()->hideCursor(!mc->options.getBooleanValue(OPTIONS_RPI_CURSOR)); + if (mc->options.getBooleanValue(OPTIONS_RPI_CURSOR)) + renderCursor(xMouse, yMouse, mc); + + // Screen might have been removed, so check it again + if (mc->screen && !mc->screen->isInGameScreen()) + sleepMs(15); + } +} + +/*public*/ +void GameRenderer::renderLevel(float a) { + + if (mc->cameraTargetPlayer == NULL) { + if (mc->player) + { + mc->cameraTargetPlayer = mc->player; + } + else + { + return; + } + } + + TIMER_PUSH("pick"); + pick(a); + + Mob* cameraEntity = mc->cameraTargetPlayer; + LevelRenderer* levelRenderer = mc->levelRenderer; + ParticleEngine* particleEngine = mc->particleEngine; + float xOff = cameraEntity->xOld + (cameraEntity->x - cameraEntity->xOld) * a; + float yOff = cameraEntity->yOld + (cameraEntity->y - cameraEntity->yOld) * a; + float zOff = cameraEntity->zOld + (cameraEntity->z - cameraEntity->zOld) * a; + + for (int i = 0; i < 2; i++) { + if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { + if (i == 0) glColorMask(false, true, true, false); + else glColorMask(true, false, false, false); + } + + TIMER_POP_PUSH("clear"); + glViewport(0, 0, mc->width, mc->height); + setupClearColor(a); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable2(GL_CULL_FACE); + + TIMER_POP_PUSH("camera"); + setupCamera(a, i); + saveMatrices(); + + if (useScreenScissor) { + glEnable2(GL_SCISSOR_TEST); + glScissor( screenScissorArea.x, screenScissorArea.y, + screenScissorArea.w, screenScissorArea.h); + } + + if(mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS)) { + setupFog(-1); + TIMER_POP_PUSH("sky"); + glFogf(GL_FOG_START, renderDistance * 0.2f); + glFogf(GL_FOG_END, renderDistance *0.75); + levelRenderer->renderSky(a); + glFogf(GL_FOG_START, renderDistance * 0.6f); + glFogf(GL_FOG_END, renderDistance); + } + glEnable2(GL_FOG); + setupFog(1); + + if (mc->options.getBooleanValue(OPTIONS_AMBIENT_OCCLUSION)) { + glShadeModel2(GL_SMOOTH); + } + + TIMER_POP_PUSH("frustrum"); + FrustumCuller frustum; + frustum.prepare(xOff, yOff, zOff); + + TIMER_POP_PUSH("culling"); + mc->levelRenderer->cull(&frustum, a); + mc->levelRenderer->updateDirtyChunks(cameraEntity, false); + + if(mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS)) { + prepareAndRenderClouds(levelRenderer, a); + } + + setupFog(0); + glEnable2(GL_FOG); + + mc->textures->loadAndBindTexture("terrain.png"); + glDisable2(GL_ALPHA_TEST); + glDisable2(GL_BLEND); + glEnable2(GL_CULL_FACE); + TIMER_POP_PUSH("terrain-0"); + levelRenderer->render(cameraEntity, 0, a); + + TIMER_POP_PUSH("terrain-1"); + glEnable2(GL_ALPHA_TEST); + levelRenderer->render(cameraEntity, 1, a); + + glShadeModel2(GL_FLAT); + TIMER_POP_PUSH("entities"); + mc->levelRenderer->renderEntities(cameraEntity->getPos(a), &frustum, a); +// setupFog(0); + TIMER_POP_PUSH("particles"); + particleEngine->render(cameraEntity, a); + + glDisable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + setupFog(0); + glEnable2(GL_BLEND); + glDisable2(GL_CULL_FACE); + glDepthMask(GL_FALSE); + glDisable2(GL_ALPHA_TEST); + mc->textures->loadAndBindTexture("terrain.png"); + //if (mc->options.fancyGraphics) { + // glColorMask(false, false, false, false); + // int visibleWaterChunks = levelRenderer->render(cameraEntity, 1, a); + // glColorMask(true, true, true, true); + // if (mc->options.anaglyph3d) { + // if (i == 0) glColorMask(false, true, true, false); + // else glColorMask(true, false, false, false); + // } + // if (visibleWaterChunks > 0) { + // levelRenderer->renderSameAsLast(1, a); + // } + //} else + { + //glDepthRangef(0.1f, 1.0f); + //glDepthMask(GL_FALSE); + TIMER_POP_PUSH("terrain-water"); + glEnable2(GL_DEPTH_TEST); + levelRenderer->render(cameraEntity, 2, a); + //glDepthRangef(0, 1); + + } + + glDepthMask(GL_TRUE); + glEnable2(GL_CULL_FACE); + glDisable2(GL_BLEND); + glEnable2(GL_ALPHA_TEST); + + if (/*!Minecraft::FLYBY_MODE &&*/ zoom == 1 && cameraEntity->isPlayer()) { + if (mc->hitResult.isHit() && !cameraEntity->isUnderLiquid(Material::water)) { + TIMER_POP_PUSH("select"); + Player* player = (Player*) cameraEntity; + // if (mc->useTouchscreen()) { + levelRenderer->renderHitSelect(player, mc->hitResult, 0, NULL, a); //player.inventory->getSelected(), a); + // } + levelRenderer->renderHit(player, mc->hitResult, 0, NULL, a);//player->inventory.getSelected(), a); + } + } + + glDisable2(GL_FOG); +// +// setupFog(0); +// glEnable2(GL_FOG); +//// levelRenderer->renderClouds(a); +// glDisable2(GL_FOG); + setupFog(1); + + if (zoom == 1 && !mc->options.getBooleanValue(OPTIONS_HIDEGUI)) { + TIMER_POP_PUSH("hand"); + glClear(GL_DEPTH_BUFFER_BIT); + renderItemInHand(a, i); + } + + if (!mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { + TIMER_POP(); + return; + } + } + glColorMask(true, true, true, false); + TIMER_POP(); +} + +void GameRenderer::tickFov() { + if (mc->cameraTargetPlayer != mc->player) + return; + + oFov = fov; + fov += (mc->player->getFieldOfViewModifier() - fov) * 0.5f; +} + +/*private*/ +float GameRenderer::getFov(float a, bool applyEffects) { + Mob* player = mc->cameraTargetPlayer; + float fov = 70; + + if (applyEffects) + fov *= this->oFov + (this->fov - this->oFov) * a; + + if (player->isUnderLiquid(Material::water)) fov = 60; + if (player->health <= 0) { + float duration = player->deathTime + a; + + fov /= ((1 - 500 / (duration + 500)) * 2.0f + 1); + } + return fov + fovOffsetO + (fovOffset - fovOffsetO) * a; +} + +/*private*/ +void GameRenderer::moveCameraToPlayer(float a) { + Entity* player = mc->cameraTargetPlayer; + + float heightOffset = player->heightOffset - 1.62f; + + float x = player->xo + (player->x - player->xo) * a; + float y = player->yo + (player->y - player->yo) * a - heightOffset; + //printf("camera y: %f\n", y); + float z = player->zo + (player->z - player->zo) * a; + + //printf("rot: %f %f\n", cameraRollO, cameraRoll); + glRotatef2(cameraRollO + (cameraRoll - cameraRollO) * a, 0, 0, 1); + + //LOGI("player. alive, removed: %d, %d\n", player->isAlive(), player->removed); + if(player->isPlayer() && ((Player*)player)->isSleeping()) { + heightOffset += 1.0; + glTranslatef(0.0f, 0.3f, 0); + if (!mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) { + int t = mc->level->getTile(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); + if (t == Tile::bed->id) { + int data = mc->level->getData(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); + + int direction = data & 3; + glRotatef(float(direction * 90), 0, 1, 0); + } + glRotatef(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, -1, 0); + glRotatef(player->xRotO + (player->xRot - player->xRotO) * a, -1, 0, 0); + } + } else if (mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW)/* || (player->isPlayer() && !player->isAlive())*/) { + float cameraDist = thirdDistanceO + (thirdDistance - thirdDistanceO) * a; + + if (mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) { + + float rotationY = thirdRotationO + (thirdRotation - thirdRotationO) * a; + float xRot = thirdTiltO + (thirdTilt - thirdTiltO) * a; + + glTranslatef2(0, 0, (float) -cameraDist); + glRotatef2(xRot, 1, 0, 0); + glRotatef2(rotationY, 0, 1, 0); + } else { + float yRot = player->yRot; + float xRot = player->xRot/* + 180.0f*/; + float xd = -Mth::sin(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * cameraDist; + float zd = Mth::cos(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * cameraDist; + float yd = -Mth::sin(xRot / 180 * Mth::PI) * cameraDist; + + for (int i = 0; i < 8; i++) { + float xo = (float)((i & 1) * 2 - 1); + float yo = (float)(((i >> 1) & 1) * 2 - 1); + float zo = (float)(((i >> 2) & 1) * 2 - 1); + + xo *= 0.1f; + yo *= 0.1f; + zo *= 0.1f; + + HitResult hr = mc->level->clip(Vec3(x + xo, y + yo, z + zo), Vec3(x - xd + xo + zo, y - yd + yo, z - zd + zo)); // newTemp + if (hr.type != NO_HIT) { + float dist = hr.pos.distanceTo(Vec3(x, y, z)); // newTemp + if (dist < cameraDist) cameraDist = dist; + } + } + + //glRotatef2(180, 0, 1, 0); + + glRotatef2(player->xRot - xRot, 1, 0, 0); + glRotatef2(player->yRot - yRot, 0, 1, 0); + glTranslatef2(0, 0, (float) -cameraDist); + glRotatef2(yRot - player->yRot, 0, 1, 0); + glRotatef2(xRot - player->xRot, 1, 0, 0); + } + } else { + glTranslatef2(0, 0, -0.1f); + } + + if (!mc->options.getBooleanValue(OPTIONS_FIXED_CAMERA)) { + glRotatef2(player->xRotO + (player->xRot - player->xRotO) * a, 1.0f, 0.0f, 0.0f); + glRotatef2(player->yRotO + (player->yRot - player->yRotO) * a + 180, 0, 1, 0); + //if (_t_keepPic > 0) + } + glTranslatef2(0, heightOffset, 0); +} + +/*private*/ +void GameRenderer::bobHurt(float a) { + Mob* player = mc->cameraTargetPlayer; + + float hurt = player->hurtTime - a; + + if (player->health <= 0) { + float duration = player->deathTime + a; + glRotatef2(40 - (40 * 200) / (duration + 200), 0, 0, 1); + } + + if (player->hurtTime <= 0) return; + + hurt /= player->hurtDuration; + hurt = (float) Mth::sin(hurt * hurt * hurt * hurt * Mth::PI); + + float rr = player->hurtDir; + + glRotatef2(-rr, 0, 1, 0); + glRotatef2(-hurt * 14, 0, 0, 1); + glRotatef2(+rr, 0, 1, 0); +} + +/*private*/ +void GameRenderer::bobView(float a) { + //if (mc->options.thirdPersonView) return; + if (!(mc->cameraTargetPlayer->isPlayer())) { + return; + } + Player* player = (Player*) mc->cameraTargetPlayer; + + float wda = player->walkDist - player->walkDistO; + float b = -(player->walkDist + wda * a); + float bob = player->oBob + (player->bob - player->oBob) * a; + float tilt = player->oTilt + (player->tilt - player->oTilt) * a; + glTranslatef2((float) Mth::sin(b * Mth::PI) * bob * 0.5f, -(float) std::abs(Mth::cos(b * Mth::PI) * bob), 0); + glRotatef2((float) Mth::sin(b * Mth::PI) * bob * 3, 0, 0, 1); + glRotatef2((float) std::abs(Mth::cos(b * Mth::PI - 0.2f) * bob) * 5, 1, 0, 0); + glRotatef2((float) tilt, 1, 0, 0); +} + +/*private*/ +void GameRenderer::setupFog(int i) { + Mob* player = mc->cameraTargetPlayer; + float fogBuffer[4] = {fr, fg, fb, 1}; + + glFogfv(GL_FOG_COLOR, (GLfloat*)fogBuffer); + glColor4f2(1, 1, 1, 1); + + if (player->isUnderLiquid(Material::water)) { + glFogx(GL_FOG_MODE, GL_EXP); + glFogf(GL_FOG_DENSITY, 0.1f); // was 0.06 + +// float rr = 0.4f; +// float gg = 0.4f; +// float bb = 0.9f; +// +// if (mc->options.anaglyph3d) { +// float rrr = (rr * 30 + gg * 59 + bb * 11) / 100; +// float ggg = (rr * 30 + gg * 70) / (100); +// float bbb = (rr * 30 + bb * 70) / (100); +// +// rr = rrr; +// gg = ggg; +// bb = bbb; +// } + } else if (player->isUnderLiquid(Material::lava)) { + glFogx(GL_FOG_MODE, GL_EXP); + glFogf(GL_FOG_DENSITY, 2.f); // was 0.06 +// float rr = 0.4f; +// float gg = 0.3f; +// float bb = 0.3f; +// +// if (mc->options.anaglyph3d) { +// float rrr = (rr * 30 + gg * 59 + bb * 11) / 100; +// float ggg = (rr * 30 + gg * 70) / (100); +// float bbb = (rr * 30 + bb * 70) / (100); +// +// rr = rrr; +// gg = ggg; +// bb = bbb; +// } + } else { + glFogx(GL_FOG_MODE, GL_LINEAR); + glFogf(GL_FOG_START, renderDistance * 0.6f); + glFogf(GL_FOG_END, renderDistance); + if (i < 0) { + glFogf(GL_FOG_START, 0); + glFogf(GL_FOG_END, renderDistance * 1.0f); + } + + if (mc->level->dimension->foggy) { + glFogf(GL_FOG_START, 0); + } + } + + glEnable2(GL_COLOR_MATERIAL); + //glColorMaterial(GL_FRONT, GL_AMBIENT); +} + +void GameRenderer::updateAllChunks() { + mc->levelRenderer->updateDirtyChunks(mc->cameraTargetPlayer, true); +} + +bool GameRenderer::updateFreeformPickDirection(float a, Vec3& outDir) { + + if (!mc->inputHolder->allowPicking()) { + _shTicks = 1; + return false; + } + + Vec3 c = mc->cameraTargetPlayer->getPos(a); + + bool firstPerson = !mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW); + const float PickingDistance = firstPerson? 6.0f : 12.0f; + + _shTicks = -1; + + int vp[4] = {0, 0, mc->width, mc->height}; + float pt[3]; + float x = mc->inputHolder->mousex; + float y = mc->height - mc->inputHolder->mousey; + + //sw.start(); + + if (!glhUnProjectf(x, y, 1, lastModelMatrix, lastProjMatrix, vp, pt)) { + return false; + } + Vec3 p1(pt[0] + c.x, pt[1] + c.y, pt[2] + c.z); + + glhUnProjectf(x, y, 0, lastModelMatrix, lastProjMatrix, vp, pt); + Vec3 p0(pt[0] + c.x, pt[1] + c.y, pt[2] + c.z); + + outDir = (p1 - p0).normalized(); + p1 = p0 + outDir * PickingDistance; + + //sw.stop(); + //sw.printEvery(30, "unproject "); + + const HitResult& hit = mc->hitResult = mc->level->clip(p0, p1, false); + + // If in 3rd person view - verify that the hit target is within range + if (!firstPerson && hit.isHit()) { + const float MaxSqrDist = PickingDistance*PickingDistance; + if (mc->cameraTargetPlayer->distanceToSqr((float)hit.x, (float)hit.y, (float)hit.z) > MaxSqrDist) + mc->hitResult.type = NO_HIT; + } + return true; +} + +/*public*/ +void GameRenderer::pick(float a) { + if (mc->level == NULL) return; + if (mc->cameraTargetPlayer == NULL) return; + if (!mc->cameraTargetPlayer->isAlive()) return; + + float range = mc->gameMode->getPickRange(); + bool isPicking = true; + + bool freeform = mc->useTouchscreen(); //&& !mc->options.getBooleanValue(OPTIONS_IS_JOY_TOUCH_AREA); + + if (freeform) { + isPicking = updateFreeformPickDirection(a, pickDirection); + } else { + mc->hitResult = mc->cameraTargetPlayer->pick(range, a); + pickDirection = mc->cameraTargetPlayer->getViewVector(a); + } + + Vec3 from = mc->cameraTargetPlayer->getPos(a); + float dist = range; + if (mc->hitResult.isHit()) { + dist = mc->hitResult.pos.distanceTo(from); + } + + if (mc->gameMode->isCreativeType()) { + /*dist =*/ range = 12; + } else { + if (dist > 3) dist = 3; + range = dist; + } + + Vec3 pv = (pickDirection * range); + Vec3 to = from + pv; + mc->cameraTargetPlayer->aimDirection = pickDirection; + + Entity* hovered = NULL; + const float g = 1; + AABB aabb = mc->cameraTargetPlayer->bb.expand(pv.x, pv.y, pv.z).grow(g, g, g); + EntityList& objects = mc->level->getEntities(mc->cameraTargetPlayer, aabb); + float nearest = 0; + for (unsigned int i = 0; i < objects.size(); i++) { + Entity* e = objects[i]; + if (!e->isPickable()) continue; + + float rr = e->getPickRadius(); + AABB bb = e->bb.grow(rr, rr, rr); + HitResult p = bb.clip(from, to); + //printf("Clip Hitresult %d (%d)\n", p.type, p.isHit()); + + if (bb.contains(from)) { + //@todo: hovered = e; break; ? + if (nearest >= 0) { + hovered = e; + nearest = 0; + } + } else if (p.isHit()) { + float dd = from.distanceTo(p.pos); + if (dd < nearest || nearest == 0) { + hovered = e; + nearest = dd; + } + } + } + + if (hovered != NULL) { + if(nearest < dist) { + mc->hitResult = HitResult(hovered); + } + } + else if (isPicking && !mc->hitResult.isHit()) { + // if we don't have a hit result, attempt to hit the edge of the block we are standing on + // (this is an pocket edition simplification to help building floors) + //LOGI("hovered : %d (%f)\n", mc->hitResult.type, viewVec.y); + if (pickDirection.y < -.7f) { + // looking down by more than roughly 45 degrees, fetch a hit to the block standing on + Vec3 to = from.add(0, -2.0f, 0); + + HitResult downHitResult = mc->level->clip(from, to); + if (downHitResult.isHit()) { + mc->hitResult = downHitResult; + mc->hitResult.indirectHit = true; + // change face (not up) + if (std::abs(pickDirection.x) > std::abs(pickDirection.z)) { + mc->hitResult.f = (pickDirection.x < 0)? 4 : 5; + } else { + mc->hitResult.f = (pickDirection.z < 0)? 2 : 3; + } + } + } + } +} +/*public*/ +void GameRenderer::tick(int nTick, int maxTick) { + --_t_keepPic; + + if (!mc->player) + { + return; + } + + if (--_shTicks == 0) + mc->hitResult.type = NO_HIT; + + //_rotXlast = _rotX; + //_rotYlast = _rotY; + + //LOGI("x: %f\n", _rotX); + + if (nTick == maxTick) { + const float tickMult = 1.0f / (float)(1 + maxTick); + _rotXlast = 0.4f * std::pow(std::abs(_rotX), 1.2f) * tickMult; + if (_rotX < 0) _rotXlast = -_rotXlast; + + _rotYlast = 0.4f * std::pow(std::abs(_rotY), 1.2f) * tickMult; + if (_rotY < 0) _rotYlast = -_rotYlast; + + _rotX = 0; + _rotY = 0; + } + + fogBrO = fogBr; + thirdDistanceO = thirdDistance; + thirdRotationO = thirdRotation; + thirdTiltO = thirdTilt; + fovOffsetO = fovOffset; + cameraRollO = cameraRoll; + + if (mc->cameraTargetPlayer == NULL) { + mc->cameraTargetPlayer = mc->player; + } + + tickFov(); + + float brr = mc->level->getBrightness( Mth::floor(mc->cameraTargetPlayer->x), + Mth::floor(mc->cameraTargetPlayer->y), + Mth::floor(mc->cameraTargetPlayer->z)); + + float whiteness = (3 - mc->options.getIntValue(OPTIONS_VIEW_DISTANCE)) / 3.0f; + float fogBrT = brr * (1 - whiteness) + whiteness; + fogBr += (fogBrT - fogBr) * 0.1f; + + _tick++; + + itemInHandRenderer->tick(); +// if (mc->isRaining) tickRain(); +} + +/*private*/ +void GameRenderer::setupClearColor(float a) { + Level* level = mc->level; + Mob* player = mc->cameraTargetPlayer; + + float whiteness = 1.0f / (4 - mc->options.getIntValue(OPTIONS_VIEW_DISTANCE)); + whiteness = 1 - (float) pow(whiteness, 0.25f); + + Vec3 skyColor = level->getSkyColor(mc->cameraTargetPlayer, a); + float sr = (float) skyColor.x; + float sg = (float) skyColor.y; + float sb = (float) skyColor.z; + + Vec3 fogColor = level->getFogColor(a); + fr = (float) fogColor.x; + fg = (float) fogColor.y; + fb = (float) fogColor.z; + + fr += (sr - fr) * whiteness; + fg += (sg - fg) * whiteness; + fb += (sb - fb) * whiteness; + + if (player->isUnderLiquid(Material::water)) { + fr = 0.02f; + fg = 0.02f; + fb = 0.2f; + } else if (player->isUnderLiquid(Material::lava)) { + fr = 0.6f; + fg = 0.1f; + fb = 0.00f; + } + + float brr = fogBrO + (fogBr - fogBrO) * a; + fr *= brr; + fg *= brr; + fb *= brr; + + if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { + float frr = (fr * 30 + fg * 59 + fb * 11) / 100; + float fgg = (fr * 30 + fg * 70) / (100); + float fbb = (fr * 30 + fb * 70) / (100); + + fr = frr; + fg = fgg; + fb = fbb; + } + + glClearColor(fr, fg, fb, 1.0f); +} + +void GameRenderer::zoomRegion( float zoom, float xa, float ya ) +{ + this->zoom = zoom; + this->zoom_x = xa; + this->zoom_y = ya; +} + +void GameRenderer::unZoomRegion() +{ + zoom = 1; +} + +void GameRenderer::setupGuiScreen( bool clearColorBuffer ) +{ + int screenWidth = (int)(mc->width * Gui::InvGuiScale); + int screenHeight = (int)(mc->height * Gui::InvGuiScale); + + // Setup GUI render mode + GLbitfield clearBits = clearColorBuffer? + GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT + : GL_DEPTH_BUFFER_BIT; + glClear(clearBits); + glMatrixMode(GL_PROJECTION); + glLoadIdentity2(); + glOrthof(0, (GLfloat)screenWidth, (GLfloat)screenHeight, 0, 2000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity2(); + glTranslatef2(0, 0, -2000); +} + +/*private*/ +void GameRenderer::renderItemInHand(float a, int eye) { + glLoadIdentity2(); + if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) glTranslatef2((eye * 2 - 1) * 0.10f, 0, 0); + + glPushMatrix2(); + bobHurt(a); + if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a); + + if (!mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW) && (mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping())) { + if (!mc->options.getBooleanValue(OPTIONS_HIDEGUI)) { + float fov = getFov(a, false); + if (fov != _setupCameraFov) { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(fov, mc->width / (float) mc->height, 0.05f, renderDistance); + glMatrixMode(GL_MODELVIEW); + } + itemInHandRenderer->render(a); + } + } + + glPopMatrix2(); + if (!mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW) && (mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping())) { + itemInHandRenderer->renderScreenEffect(a); + bobHurt(a); + } + if (mc->options.getBooleanValue(OPTIONS_VIEW_BOBBING)) bobView(a); +} + +void GameRenderer::onGraphicsReset() +{ + if (itemInHandRenderer) itemInHandRenderer->onGraphicsReset(); +} + +void GameRenderer::saveMatrices() +{ + #if defined(RPI) + return; + #endif + + static bool saved = false; + //if (saved) return; + + saved = true; + + glGetFloatv(GL_PROJECTION_MATRIX, lastProjMatrix); + glGetFloatv(GL_MODELVIEW_MATRIX, lastModelMatrix); +} + +void GameRenderer::prepareAndRenderClouds( LevelRenderer* levelRenderer, float a ) { + //if(mc->options.isCloudsOn()) { + TIMER_PUSH("clouds"); + glMatrixMode(GL_PROJECTION); + glPushMatrix2(); + glLoadIdentity2(); + gluPerspective(_setupCameraFov = getFov(a, true), mc->width / (float) mc->height, 2, renderDistance * 512); + glMatrixMode(GL_MODELVIEW); + glPushMatrix2(); + setupFog(0); + glDepthMask(false); + glEnable2(GL_FOG); + glFogf(GL_FOG_START, renderDistance * 0.2f); + glFogf(GL_FOG_END, renderDistance * 0.75f); + levelRenderer->renderSky(a); + glFogf(GL_FOG_START, renderDistance * 4.2f * 0.6f); + glFogf(GL_FOG_END, renderDistance * 4.2f); + levelRenderer->renderClouds(a); + glFogf(GL_FOG_START, renderDistance * 0.6f); + glFogf(GL_FOG_END, renderDistance); + glDisable2(GL_FOG); + glDepthMask(true); + setupFog(1); + glPopMatrix2(); + glMatrixMode(GL_PROJECTION); + glPopMatrix2(); + glMatrixMode(GL_MODELVIEW); + TIMER_POP(); + //} +} diff --git a/src/client/renderer/GameRenderer.h b/src/client/renderer/GameRenderer.hpp similarity index 94% rename from src/client/renderer/GameRenderer.h rename to src/client/renderer/GameRenderer.hpp index 775d6c1..1757352 100755 --- a/src/client/renderer/GameRenderer.h +++ b/src/client/renderer/GameRenderer.hpp @@ -2,11 +2,11 @@ //package net.minecraft.client.renderer; -#include "gles.h" +#include "gles.hpp" #include -#include "../../util/SmoothFloat.h" -#include "../../world/phys/Vec3.h" -#include "../gui/components/ImageButton.h" +#include "util/SmoothFloat.hpp" +#include "world/phys/Vec3.hpp" +#include "client/gui/components/ImageButton.hpp" class Minecraft; class Entity; diff --git a/src/client/renderer/ItemInHandRenderer.cpp b/src/client/renderer/ItemInHandRenderer.cpp index 8fd4959..cb6754e 100755 --- a/src/client/renderer/ItemInHandRenderer.cpp +++ b/src/client/renderer/ItemInHandRenderer.cpp @@ -1,533 +1,533 @@ -#include "ItemInHandRenderer.h" - -#include "gles.h" -#include "Tesselator.h" -#include "entity/EntityRenderDispatcher.h" -#include "entity/EntityRenderer.h" -#include "entity/MobRenderer.h" -#include -#include "../player/LocalPlayer.h" -#include "../../world/entity/player/Player.h" -#include "../../world/item/Item.h" -#include "../../world/level/material/Material.h" -#include "../../world/level/tile/Tile.h" -#include "../../world/level/Level.h" -#include "../../util/Mth.h" -#include "../../world/entity/player/Inventory.h" - -#include "../../platform/time.h" -#include "Textures.h" -#include "../../world/item/UseAnim.h" -#include "../../world/item/BowItem.h" -#include "../../world/level/tile/LeafTile.h" -#include "entity/HumanoidMobRenderer.h" - -//static StopwatchHandler handler; - -ItemInHandRenderer::ItemInHandRenderer( Minecraft* mc ) -: mc(mc), - lastSlot(-1), - height(0), - oHeight(0), - lastIconRendered(0), - lastItemRendered(0), - //selectedItem(NULL), - item(0, 1, 0) -{ - GLuint ids[MaxNumRenderObjects]; - glGenBuffers2(MaxNumRenderObjects, ids); - - for (int i = 0; i < MaxNumRenderObjects; ++i) { - renderObjects[i].itemId = -1; - renderObjects[i].chunk.vboId = ids[i]; - //LOGI("IDS: %d\n", ids[i]); - } - - //LOGI("SizeOf :%d (256 * %d)\n", sizeof(renderObjects), sizeof(RenderCall)); -} - -void ItemInHandRenderer::tick() -{ - oHeight = height; - item.id = 0; - - ItemInstance* itemInHand = mc->player->inventory->getSelected(); - if (itemInHand && itemInHand->count > 0) { - item.id = itemInHand->id; - item.setAuxValue(itemInHand->getAuxValue()); - } - - float max = 0.4f; - float tHeight = 1;//matches ? 1 : 0; - float dd = tHeight - height; - if (dd < -max) dd = -max; - if (dd > max) dd = max; - - height += dd; -} - -void ItemInHandRenderer::renderItem(Mob* mob, ItemInstance* item ) -{ - //Stopwatch& w = handler.get("item:" + Tile::tiles[item->id]->getDescriptionId()); - //w.start(); - - int itemId = item->id; - // Ugly hack, but what the heck, I don't have time at the moment - // Use spare slots between 200 and 255 (for now) for items with different - // graphics per data. @note: Check Tile.cpp for needed IDs to override - if (itemId == Tile::cloth->id) { - itemId = 200 + item->getAuxValue(); // 200 to 215 - } else if (itemId == Tile::treeTrunk->id) { - itemId = 216 + item->getAuxValue(); // 216 to 219 @treeTrunk - } else if (itemId == Tile::sapling->id) { - itemId = 220 + item->getAuxValue(); // 220 to 223 @sapling - } else if (itemId == Tile::stoneSlabHalf->id) { - itemId = 224 + item->getAuxValue(); // 224 to 231 @stoneslab - } else if (itemId == ((Tile*)Tile::leaves)->id) { - itemId = 232 + (item->getAuxValue() & LeafTile::LEAF_TYPE_MASK); // 232 to 235 @leaves - } - - RenderCall& renderObject = renderObjects[itemId]; - int itemIcon = item->getIcon(); - if(mob != NULL) { - itemIcon = mob->getItemInHandIcon(item, 0); - } - - bool reTesselate(false); - if(itemIcon != lastIconRendered && lastItemRendered == itemId) - reTesselate = true; - lastItemRendered = itemId; - lastIconRendered = itemIcon; - //const int aux = item->getAuxValue(); - - if (renderObject.itemId == -1 || reTesselate) { - if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) { - Tesselator& t = Tesselator::instance; - t.beginOverride(); - - int renderedItemId = item->id; - if (renderedItemId == ((Tile*)Tile::leaves)->id) - renderedItemId = ((Tile*)Tile::leaves_carried)->id; - if (renderedItemId == Tile::grass->id) - renderedItemId = Tile::grass_carried->id; - tileRenderer.renderTile(Tile::tiles[renderedItemId], item->getAuxValue()); - renderObject.chunk = t.endOverride(renderObject.chunk.vboId); - - renderObject.texture = "terrain.png"; - renderObject.itemId = itemId; - renderObject.isFlat = false; - } else { - renderObject.itemId = itemId; - renderObject.isFlat = true; - - if (item->id < 256) { - renderObject.texture = "terrain.png"; - //mc->textures->loadAndBindTexture("terrain.png"); - } else { - renderObject.texture = "gui/items.png"; - //mc->textures->loadAndBindTexture("gui/items.png"); - } - // glDisable2(GL_LIGHTING); - Tesselator& t = Tesselator::instance; - t.beginOverride(); - t.color(0xff, 0xff, 0xff); - const int up = itemIcon & 15; - const int vp = itemIcon >> 4; - float u1 = (up * 16 + 0.00f) / 256.0f; - float u0 = (up * 16 + 15.99f) / 256.0f; - float v0 = (vp * 16 + 0.00f) / 256.0f; - float v1 = (vp * 16 + 15.99f) / 256.0f; - - float r = 1.0f; -// float xo = 0.0f; -// float yo = 0.3f; -/* - //glEnable2(GL_RESCALE_NORMAL); - glTranslatef2(-xo, -yo, 0); - float s = 1.5f; - glScalef2(s, s, s); - - glRotatef2(50, 0, 1, 0); - glRotatef2(45 + 290, 0, 0, 1); - glTranslatef2(-15 / 16.0f, -1 / 16.0f, 0); -*/ - float dd = 1 / 16.0f; - - t.vertexUV(0, 0, 0, u0, v1); - t.vertexUV(r, 0, 0, u1, v1); - t.vertexUV(r, 1, 0, u1, v0); - t.vertexUV(0, 1, 0, u0, v0); - - t.vertexUV(0, 1, 0 - dd, u0, v0); - t.vertexUV(r, 1, 0 - dd, u1, v0); - t.vertexUV(r, 0, 0 - dd, u1, v1); - t.vertexUV(0, 0, 0 - dd, u0, v1); - - for (int i = 0; i < 16; i++) { - float p = i / 16.0f; - float uu = u0 + (u1 - u0) * p - 0.5f / 256.0f; - float xx = r * p; - t.vertexUV(xx, 0, 0 - dd, uu, v1); - t.vertexUV(xx, 0, 0, uu, v1); - t.vertexUV(xx, 1, 0, uu, v0); - t.vertexUV(xx, 1, 0 - dd, uu, v0); - } - for (int i = 0; i < 16; i++) { - float p = i / 16.0f; - float uu = u0 + (u1 - u0) * p - 0.5f / 256.0f; - float xx = r * p + 1 / 16.0f; - t.vertexUV(xx, 1, 0 - dd, uu, v0); - t.vertexUV(xx, 1, 0, uu, v0); - t.vertexUV(xx, 0, 0, uu, v1); - t.vertexUV(xx, 0, 0 - dd, uu, v1); - } - for (int i = 0; i < 16; i++) { - float p = i / 16.0f; - float vv = v1 + (v0 - v1) * p - 0.5f / 256.0f; - float yy = r * p + 1 / 16.0f; - t.vertexUV(0, yy, 0, u0, vv); - t.vertexUV(r, yy, 0, u1, vv); - t.vertexUV(r, yy, 0 - dd, u1, vv); - t.vertexUV(0, yy, 0 - dd, u0, vv); - } - for (int i = 0; i < 16; i++) { - float p = i / 16.0f; - float vv = v1 + (v0 - v1) * p - 0.5f / 256.0f; - float yy = r * p; - t.vertexUV(r, yy, 0, u1, vv); - t.vertexUV(0, yy, 0, u0, vv); - t.vertexUV(0, yy, 0 - dd, u0, vv); - t.vertexUV(r, yy, 0 - dd, u1, vv); - } - renderObject.chunk = t.endOverride(renderObject.chunk.vboId); - } - } - - if (renderObject.itemId >= 0) { - if (renderObject.isFlat) { - float xo = 0.0f; - float yo = 0.3f; - - glPushMatrix2(); - glTranslatef2(-xo, -yo, 0); - float s = 1.5f; - glScalef2(s, s, s); - - glRotatef2(50, 0, 1, 0); - glRotatef2(45 + 290, 0, 0, 1); - glTranslatef2(-15 / 16.0f, -1 / 16.0f, 0); - } - mc->textures->loadAndBindTexture(renderObject.texture); - - drawArrayVT_NoState(renderObject.chunk.vboId, renderObject.chunk.vertexCount); - if (renderObject.isFlat) - glPopMatrix2(); - } - //w.stop(); - //handler.printEvery(100); -} - -void ItemInHandRenderer::render( float a ) -{ - //return; - - //Stopwatch& w = handler.get("render"); - //w.start(); - - float h = oHeight + (height - oHeight) * a; - Player* player = mc->player; - // if (selectedTile==NULL) return; - - glPushMatrix2(); - glRotatef2(player->xRotO + (player->xRot - player->xRotO) * a, 1, 0, 0); - glRotatef2(player->yRotO + (player->yRot - player->yRotO) * a, 0, 1, 0); - glPopMatrix2(); - - float br = mc->level->getBrightness(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); - - ItemInstance* item;// = selectedItem; - //if (player.fishing != NULL) { - // item = /*new*/ ItemInstance(Item.stick); - //} - - if (this->item.id > 0) - item = &this->item; - else - item = NULL; - - if (item != NULL) { - glColor4f2(br, br, br, 1); - bool isUsing = player->getUseItemDuration() > 0; - bool isBow = item->id == Item::bow->id; - bool noSwingAnimation = isUsing && (isBow || (item->getUseAnimation() != UseAnim::none)); - const float swing = noSwingAnimation ? 0 : player->getAttackAnim(a); - const float sqrtSwing = Mth::sqrt(swing); - const float swing3 = Mth::sin(swing * swing * Mth::PI); - const float swing1 = Mth::sin(swing * Mth::PI); - const float swing2 = Mth::sin(sqrtSwing * Mth::PI); - const float d = 0.8f; - glPushMatrix2(); - - if (isUsing) { - UseAnim::UseAnimation anim = item->getUseAnimation(); - if (anim == UseAnim::eat || anim == UseAnim::drink) { - float t = (player->getUseItemDuration() - a + 1); - float useProgress = 1 - (t / item->getUseDuration()); - - float swing = useProgress; - float is = 1 - swing; - is = is * is * is; - is = is * is * is; - is = is * is * is; - float iss = 1 - is; - glTranslatef(0, Mth::abs(Mth::cos(t / 4 * Mth::PI) * 0.1f) * (swing > 0.2 ? 1 : 0), 0); - glTranslatef(iss * 0.6f, -iss * 0.5f, 0); - glRotatef(iss * 90, 0, 1, 0); - glRotatef(iss * 10, 1, 0, 0); - glRotatef(iss * 30, 0, 0, 1); - } - } else { - glTranslatef2(-swing2 * 0.4f, (float) Mth::sin(sqrtSwing * Mth::PI * 2) * 0.2f, -swing1 * 0.2f); - } - - glTranslatef2(0.7f * d, -0.65f * d - (1 - h) * 0.6f, -0.9f * d); - - glRotatef2(45, 0, 1, 0); - //glEnable2(GL_RESCALE_NORMAL); - glRotatef2(-swing3 * 20, 0, 1, 0); - glRotatef2(-swing2 * 20, 0, 0, 1); - glRotatef2(-swing2 * 80, 1, 0, 0); - float ss = 0.4f; - glScalef2(ss, ss, ss); - if (player->getUseItemDuration() > 0) { - UseAnim::UseAnimation anim = item->getUseAnimation(); - if(anim == UseAnim::bow) { - glRotatef(-18, 0, 0, 1); - glRotatef(-12, 0, 1, 0); - glRotatef(-8, 1, 0, 0); - glTranslatef(-0.9f, 0.2f, 0.0f); - float timeHeld = (item->getUseDuration() - (player->getUseItemDuration() - a + 1)); - float pow = timeHeld / (float) (BowItem::MAX_DRAW_DURATION); - pow = ((pow * pow) + pow * 2) / 3; - if (pow > 1) pow = 1; - if (pow > 0.1f) { - glTranslatef(0, Mth::sin((timeHeld - 0.1f) * 1.3f) * 0.01f * (pow - 0.1f), 0); - } - glTranslatef(0, 0, pow * 0.1f); - - glRotatef(-45 - 290, 0, 0, 1); - glRotatef(-50, 0, 1, 0); - glTranslatef(0, 0.5f, 0); - float ys = 1 + pow * 0.2f; - glScalef(1, 1, ys); - glTranslatef(0, -0.5f, 0); - glRotatef(50, 0, 1, 0); - glRotatef(45 + 290, 0, 0, 1); - } - } - if (item->getItem()->isMirroredArt()) { - glRotatef2(180, 0, 1, 0); - } - glEnableClientState2(GL_VERTEX_ARRAY); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - renderItem(player, item); - glDisableClientState2(GL_VERTEX_ARRAY); - glDisableClientState2(GL_TEXTURE_COORD_ARRAY); - glPopMatrix2(); - } else { - glColor4f2(br, br, br, 1); - - glPushMatrix2(); - float d = 0.8f; - const float swing = player->getAttackAnim(a); - const float sqrtSwing = Mth::sqrt(swing); - const float swing3 = Mth::sin(swing * swing * Mth::PI); - const float swing1 = Mth::sin(swing * Mth::PI); - const float swing2 = Mth::sin(sqrtSwing * Mth::PI); - - glTranslatef2(-swing2 * 0.3f, (float) Mth::sin(Mth::sqrt(swing) * Mth::PI * 2) * 0.4f, -swing1 * 0.4f); - glTranslatef2(0.8f * d, -0.75f * d - (1 - h) * 0.6f, -0.9f * d); - - glRotatef2(45, 0, 1, 0); - //glEnable2(GL_RESCALE_NORMAL); - glRotatef2(swing2 * 70, 0, 1, 0); - glRotatef2(-swing3 * 20, 0, 0, 1); - // glRotatef2(-swing2 * 80, 1, 0, 0); - - mc->textures->loadAndBindTexture(player->getTexture()); - glTranslatef2(-1.0f, +3.6f, +3.5f); - glRotatef2(120, 0, 0, 1); - glRotatef2(180 + 20, 1, 0, 0); - glRotatef2(-90 - 45, 0, 1, 0); - glScalef2(1.5f / 24.0f * 16, 1.5f / 24.0f * 16, 1.5f / 24.0f * 16); - glTranslatef2(5.6f, 0, 0); - - EntityRenderer* er = EntityRenderDispatcher::getInstance()->getRenderer(mc->player); - HumanoidMobRenderer* playerRenderer = (HumanoidMobRenderer*) er; - float ss = 1; - glScalef2(ss, ss, ss); - playerRenderer->renderHand(); - glPopMatrix2(); - } - //glDisable2(GL_RESCALE_NORMAL); - //Lighting.turnOff(); - //w.stop(); -} - -void ItemInHandRenderer::renderScreenEffect( float a ) -{ - glDisable2(GL_ALPHA_TEST); - if (mc->player->isOnFire()) { - mc->textures->loadAndBindTexture("terrain.png"); - renderFire(a); - } - - if (mc->player->isInWall()) // Inside a tile - { - int x = Mth::floor(mc->player->x); - int y = Mth::floor(mc->player->y); - int z = Mth::floor(mc->player->z); - - mc->textures->loadAndBindTexture("terrain.png"); - int tile = mc->level->getTile(x, y, z); - if (Tile::tiles[tile] != NULL) { - renderTex(a, Tile::tiles[tile]->getTexture(2)); - } - } - - // if (mc->player->isUnderLiquid(Material::water)) { - //mc->textures->loadAndBindTexture("misc/water.png"); - // renderWater(a); - // } - glEnable2(GL_ALPHA_TEST); -} - -void ItemInHandRenderer::itemPlaced() -{ - height = 0; -} - -void ItemInHandRenderer::itemUsed() -{ - height = 0; -} - -void ItemInHandRenderer::renderTex( float a, int tex ) -{ - Tesselator& t = Tesselator::instance; - - float br;// = mc->player->getBrightness(a); - br = 0.1f; - glColor4f2(br, br, br, 0.5f); - - glPushMatrix2(); - - float x0 = -1; - float x1 = +1; - float y0 = -1; - float y1 = +1; - float z0 = -0.5f; - - float r = 2 / 256.0f; - float u0 = (tex % 16) / 256.0f - r; - float u1 = (tex % 16 + 15.99f) / 256.0f + r; - float v0 = (tex / 16) / 256.0f - r; - float v1 = (tex / 16 + 15.99f) / 256.0f + r; - - t.begin(); - t.vertexUV(x0, y0, z0, u1, v1); - t.vertexUV(x1, y0, z0, u0, v1); - t.vertexUV(x1, y1, z0, u0, v0); - t.vertexUV(x0, y1, z0, u1, v0); - //t.end(); - t.draw(); - glPopMatrix2(); - - glColor4f2(1, 1, 1, 1); -} - -void ItemInHandRenderer::renderWater( float a ) -{ - Tesselator& t = Tesselator::instance; - - float br = mc->player->getBrightness(a); - glColor4f2(br, br, br, 0.5f); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - glPushMatrix2(); - - float size = 4; - - float x0 = -1; - float x1 = +1; - float y0 = -1; - float y1 = +1; - float z0 = -0.5f; - - float uo = -mc->player->yRot / 64.0f; - float vo = +mc->player->xRot / 64.0f; - - t.begin(); - t.vertexUV(x0, y0, z0, size + uo, size + vo); - t.vertexUV(x1, y0, z0, 0 + uo, size + vo); - t.vertexUV(x1, y1, z0, 0 + uo, 0 + vo); - t.vertexUV(x0, y1, z0, size + uo, 0 + vo); - //t.end(); - t.draw(); - glPopMatrix2(); - - glColor4f2(1, 1, 1, 1); - glDisable2(GL_BLEND); -} - -void ItemInHandRenderer::renderFire( float a ) -{ - Tesselator& t = Tesselator::instance; - glColor4f2(1, 1, 1, 0.9f); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - float size = 1; - for (int i = 0; i < 2; i++) { - glPushMatrix2(); - int tex = ((Tile*)Tile::fire)->tex + i * 16; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt) / 256.0f; - float u1 = (xt + 15.99f) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 15.99f) / 256.0f; - - float x0 = (0 - size) / 2; - float x1 = x0 + size; - float y0 = 0 - size / 2; - float y1 = y0 + size; - float z0 = -0.5f; - glTranslatef2(-(i * 2 - 1) * 0.24f, -0.3f, 0); - glRotatef2((i * 2 - 1) * 10.f, 0, 1, 0); - - t.begin(); - t.vertexUV(x0, y0, z0, u1, v1); - t.vertexUV(x1, y0, z0, u0, v1); - t.vertexUV(x1, y1, z0, u0, v0); - t.vertexUV(x0, y1, z0, u1, v0); - //t.end(); - t.draw(); - glPopMatrix2(); - } - glColor4f2(1, 1, 1, 1); - glDisable2(GL_BLEND); -} - -void ItemInHandRenderer::onGraphicsReset() -{ - GLuint ids[MaxNumRenderObjects]; - glGenBuffers2(MaxNumRenderObjects, ids); - - for (int i = 0; i < MaxNumRenderObjects; ++i) { - renderObjects[i].itemId = -1; - renderObjects[i].chunk.vboId = ids[i]; - } -} +#include "ItemInHandRenderer.hpp" + +#include "gles.hpp" +#include "Tesselator.hpp" +#include "entity/EntityRenderDispatcher.hpp" +#include "entity/EntityRenderer.hpp" +#include "entity/MobRenderer.hpp" +#include +#include "client/player/LocalPlayer.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/Item.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/Level.hpp" +#include "util/Mth.hpp" +#include "world/entity/player/Inventory.hpp" + +#include "platform/time.hpp" +#include "Textures.hpp" +#include "world/item/UseAnim.hpp" +#include "world/item/BowItem.hpp" +#include "world/level/tile/LeafTile.hpp" +#include "entity/HumanoidMobRenderer.hpp" + +//static StopwatchHandler handler; + +ItemInHandRenderer::ItemInHandRenderer( Minecraft* mc ) +: mc(mc), + lastSlot(-1), + height(0), + oHeight(0), + lastIconRendered(0), + lastItemRendered(0), + //selectedItem(NULL), + item(0, 1, 0) +{ + GLuint ids[MaxNumRenderObjects]; + glGenBuffers2(MaxNumRenderObjects, ids); + + for (int i = 0; i < MaxNumRenderObjects; ++i) { + renderObjects[i].itemId = -1; + renderObjects[i].chunk.vboId = ids[i]; + //LOGI("IDS: %d\n", ids[i]); + } + + //LOGI("SizeOf :%d (256 * %d)\n", sizeof(renderObjects), sizeof(RenderCall)); +} + +void ItemInHandRenderer::tick() +{ + oHeight = height; + item.id = 0; + + ItemInstance* itemInHand = mc->player->inventory->getSelected(); + if (itemInHand && itemInHand->count > 0) { + item.id = itemInHand->id; + item.setAuxValue(itemInHand->getAuxValue()); + } + + float max = 0.4f; + float tHeight = 1;//matches ? 1 : 0; + float dd = tHeight - height; + if (dd < -max) dd = -max; + if (dd > max) dd = max; + + height += dd; +} + +void ItemInHandRenderer::renderItem(Mob* mob, ItemInstance* item ) +{ + //Stopwatch& w = handler.get("item:" + Tile::tiles[item->id]->getDescriptionId()); + //w.start(); + + int itemId = item->id; + // Ugly hack, but what the heck, I don't have time at the moment + // Use spare slots between 200 and 255 (for now) for items with different + // graphics per data. @note: Check Tile.cpp for needed IDs to override + if (itemId == Tile::cloth->id) { + itemId = 200 + item->getAuxValue(); // 200 to 215 + } else if (itemId == Tile::treeTrunk->id) { + itemId = 216 + item->getAuxValue(); // 216 to 219 @treeTrunk + } else if (itemId == Tile::sapling->id) { + itemId = 220 + item->getAuxValue(); // 220 to 223 @sapling + } else if (itemId == Tile::stoneSlabHalf->id) { + itemId = 224 + item->getAuxValue(); // 224 to 231 @stoneslab + } else if (itemId == ((Tile*)Tile::leaves)->id) { + itemId = 232 + (item->getAuxValue() & LeafTile::LEAF_TYPE_MASK); // 232 to 235 @leaves + } + + RenderCall& renderObject = renderObjects[itemId]; + int itemIcon = item->getIcon(); + if(mob != NULL) { + itemIcon = mob->getItemInHandIcon(item, 0); + } + + bool reTesselate(false); + if(itemIcon != lastIconRendered && lastItemRendered == itemId) + reTesselate = true; + lastItemRendered = itemId; + lastIconRendered = itemIcon; + //const int aux = item->getAuxValue(); + + if (renderObject.itemId == -1 || reTesselate) { + if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) { + Tesselator& t = Tesselator::instance; + t.beginOverride(); + + int renderedItemId = item->id; + if (renderedItemId == ((Tile*)Tile::leaves)->id) + renderedItemId = ((Tile*)Tile::leaves_carried)->id; + if (renderedItemId == Tile::grass->id) + renderedItemId = Tile::grass_carried->id; + tileRenderer.renderTile(Tile::tiles[renderedItemId], item->getAuxValue()); + renderObject.chunk = t.endOverride(renderObject.chunk.vboId); + + renderObject.texture = "terrain.png"; + renderObject.itemId = itemId; + renderObject.isFlat = false; + } else { + renderObject.itemId = itemId; + renderObject.isFlat = true; + + if (item->id < 256) { + renderObject.texture = "terrain.png"; + //mc->textures->loadAndBindTexture("terrain.png"); + } else { + renderObject.texture = "gui/items.png"; + //mc->textures->loadAndBindTexture("gui/items.png"); + } + // glDisable2(GL_LIGHTING); + Tesselator& t = Tesselator::instance; + t.beginOverride(); + t.color(0xff, 0xff, 0xff); + const int up = itemIcon & 15; + const int vp = itemIcon >> 4; + float u1 = (up * 16 + 0.00f) / 256.0f; + float u0 = (up * 16 + 15.99f) / 256.0f; + float v0 = (vp * 16 + 0.00f) / 256.0f; + float v1 = (vp * 16 + 15.99f) / 256.0f; + + float r = 1.0f; +// float xo = 0.0f; +// float yo = 0.3f; +/* + //glEnable2(GL_RESCALE_NORMAL); + glTranslatef2(-xo, -yo, 0); + float s = 1.5f; + glScalef2(s, s, s); + + glRotatef2(50, 0, 1, 0); + glRotatef2(45 + 290, 0, 0, 1); + glTranslatef2(-15 / 16.0f, -1 / 16.0f, 0); +*/ + float dd = 1 / 16.0f; + + t.vertexUV(0, 0, 0, u0, v1); + t.vertexUV(r, 0, 0, u1, v1); + t.vertexUV(r, 1, 0, u1, v0); + t.vertexUV(0, 1, 0, u0, v0); + + t.vertexUV(0, 1, 0 - dd, u0, v0); + t.vertexUV(r, 1, 0 - dd, u1, v0); + t.vertexUV(r, 0, 0 - dd, u1, v1); + t.vertexUV(0, 0, 0 - dd, u0, v1); + + for (int i = 0; i < 16; i++) { + float p = i / 16.0f; + float uu = u0 + (u1 - u0) * p - 0.5f / 256.0f; + float xx = r * p; + t.vertexUV(xx, 0, 0 - dd, uu, v1); + t.vertexUV(xx, 0, 0, uu, v1); + t.vertexUV(xx, 1, 0, uu, v0); + t.vertexUV(xx, 1, 0 - dd, uu, v0); + } + for (int i = 0; i < 16; i++) { + float p = i / 16.0f; + float uu = u0 + (u1 - u0) * p - 0.5f / 256.0f; + float xx = r * p + 1 / 16.0f; + t.vertexUV(xx, 1, 0 - dd, uu, v0); + t.vertexUV(xx, 1, 0, uu, v0); + t.vertexUV(xx, 0, 0, uu, v1); + t.vertexUV(xx, 0, 0 - dd, uu, v1); + } + for (int i = 0; i < 16; i++) { + float p = i / 16.0f; + float vv = v1 + (v0 - v1) * p - 0.5f / 256.0f; + float yy = r * p + 1 / 16.0f; + t.vertexUV(0, yy, 0, u0, vv); + t.vertexUV(r, yy, 0, u1, vv); + t.vertexUV(r, yy, 0 - dd, u1, vv); + t.vertexUV(0, yy, 0 - dd, u0, vv); + } + for (int i = 0; i < 16; i++) { + float p = i / 16.0f; + float vv = v1 + (v0 - v1) * p - 0.5f / 256.0f; + float yy = r * p; + t.vertexUV(r, yy, 0, u1, vv); + t.vertexUV(0, yy, 0, u0, vv); + t.vertexUV(0, yy, 0 - dd, u0, vv); + t.vertexUV(r, yy, 0 - dd, u1, vv); + } + renderObject.chunk = t.endOverride(renderObject.chunk.vboId); + } + } + + if (renderObject.itemId >= 0) { + if (renderObject.isFlat) { + float xo = 0.0f; + float yo = 0.3f; + + glPushMatrix2(); + glTranslatef2(-xo, -yo, 0); + float s = 1.5f; + glScalef2(s, s, s); + + glRotatef2(50, 0, 1, 0); + glRotatef2(45 + 290, 0, 0, 1); + glTranslatef2(-15 / 16.0f, -1 / 16.0f, 0); + } + mc->textures->loadAndBindTexture(renderObject.texture); + + drawArrayVT_NoState(renderObject.chunk.vboId, renderObject.chunk.vertexCount); + if (renderObject.isFlat) + glPopMatrix2(); + } + //w.stop(); + //handler.printEvery(100); +} + +void ItemInHandRenderer::render( float a ) +{ + //return; + + //Stopwatch& w = handler.get("render"); + //w.start(); + + float h = oHeight + (height - oHeight) * a; + Player* player = mc->player; + // if (selectedTile==NULL) return; + + glPushMatrix2(); + glRotatef2(player->xRotO + (player->xRot - player->xRotO) * a, 1, 0, 0); + glRotatef2(player->yRotO + (player->yRot - player->yRotO) * a, 0, 1, 0); + glPopMatrix2(); + + float br = mc->level->getBrightness(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); + + ItemInstance* item;// = selectedItem; + //if (player.fishing != NULL) { + // item = /*new*/ ItemInstance(Item.stick); + //} + + if (this->item.id > 0) + item = &this->item; + else + item = NULL; + + if (item != NULL) { + glColor4f2(br, br, br, 1); + bool isUsing = player->getUseItemDuration() > 0; + bool isBow = item->id == Item::bow->id; + bool noSwingAnimation = isUsing && (isBow || (item->getUseAnimation() != UseAnim::none)); + const float swing = noSwingAnimation ? 0 : player->getAttackAnim(a); + const float sqrtSwing = Mth::sqrt(swing); + const float swing3 = Mth::sin(swing * swing * Mth::PI); + const float swing1 = Mth::sin(swing * Mth::PI); + const float swing2 = Mth::sin(sqrtSwing * Mth::PI); + const float d = 0.8f; + glPushMatrix2(); + + if (isUsing) { + UseAnim::UseAnimation anim = item->getUseAnimation(); + if (anim == UseAnim::eat || anim == UseAnim::drink) { + float t = (player->getUseItemDuration() - a + 1); + float useProgress = 1 - (t / item->getUseDuration()); + + float swing = useProgress; + float is = 1 - swing; + is = is * is * is; + is = is * is * is; + is = is * is * is; + float iss = 1 - is; + glTranslatef(0, Mth::abs(Mth::cos(t / 4 * Mth::PI) * 0.1f) * (swing > 0.2 ? 1 : 0), 0); + glTranslatef(iss * 0.6f, -iss * 0.5f, 0); + glRotatef(iss * 90, 0, 1, 0); + glRotatef(iss * 10, 1, 0, 0); + glRotatef(iss * 30, 0, 0, 1); + } + } else { + glTranslatef2(-swing2 * 0.4f, (float) Mth::sin(sqrtSwing * Mth::PI * 2) * 0.2f, -swing1 * 0.2f); + } + + glTranslatef2(0.7f * d, -0.65f * d - (1 - h) * 0.6f, -0.9f * d); + + glRotatef2(45, 0, 1, 0); + //glEnable2(GL_RESCALE_NORMAL); + glRotatef2(-swing3 * 20, 0, 1, 0); + glRotatef2(-swing2 * 20, 0, 0, 1); + glRotatef2(-swing2 * 80, 1, 0, 0); + float ss = 0.4f; + glScalef2(ss, ss, ss); + if (player->getUseItemDuration() > 0) { + UseAnim::UseAnimation anim = item->getUseAnimation(); + if(anim == UseAnim::bow) { + glRotatef(-18, 0, 0, 1); + glRotatef(-12, 0, 1, 0); + glRotatef(-8, 1, 0, 0); + glTranslatef(-0.9f, 0.2f, 0.0f); + float timeHeld = (item->getUseDuration() - (player->getUseItemDuration() - a + 1)); + float pow = timeHeld / (float) (BowItem::MAX_DRAW_DURATION); + pow = ((pow * pow) + pow * 2) / 3; + if (pow > 1) pow = 1; + if (pow > 0.1f) { + glTranslatef(0, Mth::sin((timeHeld - 0.1f) * 1.3f) * 0.01f * (pow - 0.1f), 0); + } + glTranslatef(0, 0, pow * 0.1f); + + glRotatef(-45 - 290, 0, 0, 1); + glRotatef(-50, 0, 1, 0); + glTranslatef(0, 0.5f, 0); + float ys = 1 + pow * 0.2f; + glScalef(1, 1, ys); + glTranslatef(0, -0.5f, 0); + glRotatef(50, 0, 1, 0); + glRotatef(45 + 290, 0, 0, 1); + } + } + if (item->getItem()->isMirroredArt()) { + glRotatef2(180, 0, 1, 0); + } + glEnableClientState2(GL_VERTEX_ARRAY); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + renderItem(player, item); + glDisableClientState2(GL_VERTEX_ARRAY); + glDisableClientState2(GL_TEXTURE_COORD_ARRAY); + glPopMatrix2(); + } else { + glColor4f2(br, br, br, 1); + + glPushMatrix2(); + float d = 0.8f; + const float swing = player->getAttackAnim(a); + const float sqrtSwing = Mth::sqrt(swing); + const float swing3 = Mth::sin(swing * swing * Mth::PI); + const float swing1 = Mth::sin(swing * Mth::PI); + const float swing2 = Mth::sin(sqrtSwing * Mth::PI); + + glTranslatef2(-swing2 * 0.3f, (float) Mth::sin(Mth::sqrt(swing) * Mth::PI * 2) * 0.4f, -swing1 * 0.4f); + glTranslatef2(0.8f * d, -0.75f * d - (1 - h) * 0.6f, -0.9f * d); + + glRotatef2(45, 0, 1, 0); + //glEnable2(GL_RESCALE_NORMAL); + glRotatef2(swing2 * 70, 0, 1, 0); + glRotatef2(-swing3 * 20, 0, 0, 1); + // glRotatef2(-swing2 * 80, 1, 0, 0); + + mc->textures->loadAndBindTexture(player->getTexture()); + glTranslatef2(-1.0f, +3.6f, +3.5f); + glRotatef2(120, 0, 0, 1); + glRotatef2(180 + 20, 1, 0, 0); + glRotatef2(-90 - 45, 0, 1, 0); + glScalef2(1.5f / 24.0f * 16, 1.5f / 24.0f * 16, 1.5f / 24.0f * 16); + glTranslatef2(5.6f, 0, 0); + + EntityRenderer* er = EntityRenderDispatcher::getInstance()->getRenderer(mc->player); + HumanoidMobRenderer* playerRenderer = (HumanoidMobRenderer*) er; + float ss = 1; + glScalef2(ss, ss, ss); + playerRenderer->renderHand(); + glPopMatrix2(); + } + //glDisable2(GL_RESCALE_NORMAL); + //Lighting.turnOff(); + //w.stop(); +} + +void ItemInHandRenderer::renderScreenEffect( float a ) +{ + glDisable2(GL_ALPHA_TEST); + if (mc->player->isOnFire()) { + mc->textures->loadAndBindTexture("terrain.png"); + renderFire(a); + } + + if (mc->player->isInWall()) // Inside a tile + { + int x = Mth::floor(mc->player->x); + int y = Mth::floor(mc->player->y); + int z = Mth::floor(mc->player->z); + + mc->textures->loadAndBindTexture("terrain.png"); + int tile = mc->level->getTile(x, y, z); + if (Tile::tiles[tile] != NULL) { + renderTex(a, Tile::tiles[tile]->getTexture(2)); + } + } + + // if (mc->player->isUnderLiquid(Material::water)) { + //mc->textures->loadAndBindTexture("misc/water.png"); + // renderWater(a); + // } + glEnable2(GL_ALPHA_TEST); +} + +void ItemInHandRenderer::itemPlaced() +{ + height = 0; +} + +void ItemInHandRenderer::itemUsed() +{ + height = 0; +} + +void ItemInHandRenderer::renderTex( float a, int tex ) +{ + Tesselator& t = Tesselator::instance; + + float br;// = mc->player->getBrightness(a); + br = 0.1f; + glColor4f2(br, br, br, 0.5f); + + glPushMatrix2(); + + float x0 = -1; + float x1 = +1; + float y0 = -1; + float y1 = +1; + float z0 = -0.5f; + + float r = 2 / 256.0f; + float u0 = (tex % 16) / 256.0f - r; + float u1 = (tex % 16 + 15.99f) / 256.0f + r; + float v0 = (tex / 16) / 256.0f - r; + float v1 = (tex / 16 + 15.99f) / 256.0f + r; + + t.begin(); + t.vertexUV(x0, y0, z0, u1, v1); + t.vertexUV(x1, y0, z0, u0, v1); + t.vertexUV(x1, y1, z0, u0, v0); + t.vertexUV(x0, y1, z0, u1, v0); + //t.end(); + t.draw(); + glPopMatrix2(); + + glColor4f2(1, 1, 1, 1); +} + +void ItemInHandRenderer::renderWater( float a ) +{ + Tesselator& t = Tesselator::instance; + + float br = mc->player->getBrightness(a); + glColor4f2(br, br, br, 0.5f); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glPushMatrix2(); + + float size = 4; + + float x0 = -1; + float x1 = +1; + float y0 = -1; + float y1 = +1; + float z0 = -0.5f; + + float uo = -mc->player->yRot / 64.0f; + float vo = +mc->player->xRot / 64.0f; + + t.begin(); + t.vertexUV(x0, y0, z0, size + uo, size + vo); + t.vertexUV(x1, y0, z0, 0 + uo, size + vo); + t.vertexUV(x1, y1, z0, 0 + uo, 0 + vo); + t.vertexUV(x0, y1, z0, size + uo, 0 + vo); + //t.end(); + t.draw(); + glPopMatrix2(); + + glColor4f2(1, 1, 1, 1); + glDisable2(GL_BLEND); +} + +void ItemInHandRenderer::renderFire( float a ) +{ + Tesselator& t = Tesselator::instance; + glColor4f2(1, 1, 1, 0.9f); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + float size = 1; + for (int i = 0; i < 2; i++) { + glPushMatrix2(); + int tex = ((Tile*)Tile::fire)->tex + i * 16; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt) / 256.0f; + float u1 = (xt + 15.99f) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 15.99f) / 256.0f; + + float x0 = (0 - size) / 2; + float x1 = x0 + size; + float y0 = 0 - size / 2; + float y1 = y0 + size; + float z0 = -0.5f; + glTranslatef2(-(i * 2 - 1) * 0.24f, -0.3f, 0); + glRotatef2((i * 2 - 1) * 10.f, 0, 1, 0); + + t.begin(); + t.vertexUV(x0, y0, z0, u1, v1); + t.vertexUV(x1, y0, z0, u0, v1); + t.vertexUV(x1, y1, z0, u0, v0); + t.vertexUV(x0, y1, z0, u1, v0); + //t.end(); + t.draw(); + glPopMatrix2(); + } + glColor4f2(1, 1, 1, 1); + glDisable2(GL_BLEND); +} + +void ItemInHandRenderer::onGraphicsReset() +{ + GLuint ids[MaxNumRenderObjects]; + glGenBuffers2(MaxNumRenderObjects, ids); + + for (int i = 0; i < MaxNumRenderObjects; ++i) { + renderObjects[i].itemId = -1; + renderObjects[i].chunk.vboId = ids[i]; + } +} diff --git a/src/client/renderer/ItemInHandRenderer.h b/src/client/renderer/ItemInHandRenderer.hpp similarity index 88% rename from src/client/renderer/ItemInHandRenderer.h rename to src/client/renderer/ItemInHandRenderer.hpp index 65e7033..eefab5c 100755 --- a/src/client/renderer/ItemInHandRenderer.h +++ b/src/client/renderer/ItemInHandRenderer.hpp @@ -2,9 +2,9 @@ //package net.minecraft.client.renderer; -#include "TileRenderer.h" -#include "../renderer/RenderChunk.h" -#include "../../world/item/ItemInstance.h" +#include "TileRenderer.hpp" +#include "client/renderer/RenderChunk.hpp" +#include "world/item/ItemInstance.hpp" class Minecraft; diff --git a/src/client/renderer/LevelRenderer.cpp b/src/client/renderer/LevelRenderer.cpp index 0ffd7e0..ad6dc4a 100755 --- a/src/client/renderer/LevelRenderer.cpp +++ b/src/client/renderer/LevelRenderer.cpp @@ -1,1299 +1,1299 @@ -#include "LevelRenderer.h" - -#include "DirtyChunkSorter.h" -#include "DistanceChunkSorter.h" -#include "Chunk.h" -#include "TileRenderer.h" -#include -#include "../../util/Mth.h" -#include "../../world/entity/player/Player.h" -#include "../../world/level/tile/LevelEvent.h" -#include "../../world/level/tile/LeafTile.h" -#include "../../client/particle/ParticleEngine.h" -#include "../../client/particle/ParticleInclude.h" -#include "../sound/SoundEngine.h" -#include "culling/Culler.h" -#include "entity/EntityRenderDispatcher.h" -#include "../model/HumanoidModel.h" - -#include "GameRenderer.h" -#include "../../AppPlatform.h" -#include "../../util/PerfTimer.h" -#include "Textures.h" -#include "tileentity/TileEntityRenderDispatcher.h" -#include "../particle/BreakingItemParticle.h" - -#include "../../client/player/LocalPlayer.h" - -#ifdef GFX_SMALLER_CHUNKS -/* static */ const int LevelRenderer::CHUNK_SIZE = 8; -#else -/* static */ const int LevelRenderer::CHUNK_SIZE = 16; -#endif - -LevelRenderer::LevelRenderer( Minecraft* mc) -: mc(mc), - textures(mc->textures), - level(NULL), - cullStep(0), - - chunkLists(0), - xChunks(0), yChunks(0), zChunks(0), - - chunks(NULL), - sortedChunks(NULL), - - xMinChunk(0), yMinChunk(0), zMinChunk(0), - xMaxChunk(0), yMaxChunk(0), zMaxChunk(0), - - lastViewDistance(-1), - - noEntityRenderFrames(2), - totalEntities(0), - renderedEntities(0), - culledEntities(0), - - occlusionCheck(false), - totalChunks(0), offscreenChunks(0), renderedChunks(0), occludedChunks(0), emptyChunks(0), - - chunkFixOffs(0), - xOld(-9999), yOld(-9999), zOld(-9999), - - ticks(0), - skyList(0), starList(0), darkList(0), - tileRenderer(NULL), - destroyProgress(0) -{ -#ifdef OPENGL_ES - int maxChunksWidth = 2 * LEVEL_WIDTH / CHUNK_SIZE + 1; - numListsOrBuffers = maxChunksWidth * maxChunksWidth * (128/CHUNK_SIZE) * 3; - chunkBuffers = new GLuint[numListsOrBuffers]; - glGenBuffers2(numListsOrBuffers, chunkBuffers); - LOGI("numBuffers: %d\n", numListsOrBuffers); - //for (int i = 0; i < numListsOrBuffers; ++i) printf("bufId %d: %d\t", i, chunkBuffers[i]); - - glGenBuffers2(1, &skyBuffer); - generateSky(); -#else - int maxChunksWidth = 1024 / CHUNK_SIZE; - numListsOrBuffers = maxChunksWidth * maxChunksWidth * maxChunksWidth * 3; - chunkLists = glGenLists(numListsOrBuffers); -#endif -} - -LevelRenderer::~LevelRenderer() -{ - delete tileRenderer; - tileRenderer = NULL; - - deleteChunks(); - -#ifdef OPENGL_ES - glDeleteBuffers(numListsOrBuffers, chunkBuffers); - glDeleteBuffers(1, &skyBuffer); - delete[] chunkBuffers; -#else - glDeleteLists(numListsOrBuffers, chunkLists); -#endif -} - -void LevelRenderer::generateSky() { - Tesselator& t = Tesselator::instance; - float yy; - int s = 128; - int d = (256 / s) + 2; - yy = (float) (16); - t.begin(); - - skyVertexCount = 0; - for (int xx = -s * d; xx <= s * d; xx += s) { - for (int zz = -s * d; zz <= s * d; zz += s) { - t.vertex((float) xx + 0, yy, (float) zz + 0); - t.vertex((float)(xx + s), yy, (float) zz + 0); - t.vertex((float)(xx + s), yy, (float)(zz + s)); - t.vertex((float) xx + 0, yy, (float)(zz + s)); - //LOGI("x, z: %d, %d\n", xx, zz); - skyVertexCount += 4; - } - } - - t.end(true, skyBuffer); - //LOGI("skyvertexcount: %d\n", skyVertexCount); - //glEndList(); -} - -void LevelRenderer::setLevel( Level* level ) -{ - if (this->level != NULL) { - this->level->removeListener(this); - } - - xOld = -9999; - yOld = -9999; - zOld = -9999; - - EntityRenderDispatcher::getInstance()->setLevel(level); - EntityRenderDispatcher::getInstance()->setMinecraft(mc); - this->level = level; - - delete tileRenderer; - tileRenderer = new TileRenderer(level); - - if (level != NULL) { - level->addListener(this); - allChanged(); - } -} - -void LevelRenderer::allChanged() -{ - deleteChunks(); - - bool fancy = mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS); - - Tile::leaves->setFancy(fancy); - Tile::leaves_carried->setFancy(fancy); - lastViewDistance = mc->options.getIntValue(OPTIONS_VIEW_DISTANCE); - - int dist = (512 >> 3) << (3 - lastViewDistance); - if (lastViewDistance <= 2 && mc->isPowerVR()) - dist = (int)((float)dist * 0.8f); - LOGI("last: %d, power: %d\n", lastViewDistance, mc->isPowerVR()); - - #if defined(RPI) - dist *= 0.6f; - #endif - - if (dist > 400) dist = 400; - /* - * if (Minecraft.FLYBY_MODE) { dist = 512 - CHUNK_SIZE * 2; } - */ - xChunks = (dist / LevelRenderer::CHUNK_SIZE) + 1; - yChunks = (128 / LevelRenderer::CHUNK_SIZE); - zChunks = (dist / LevelRenderer::CHUNK_SIZE) + 1; - chunksLength = xChunks * yChunks * zChunks; - LOGI("chunksLength: %d. Distance: %d\n", chunksLength, dist); - - chunks = new Chunk*[chunksLength]; - sortedChunks = new Chunk*[chunksLength]; - - int id = 0; - int count = 0; - - xMinChunk = 0; - yMinChunk = 0; - zMinChunk = 0; - xMaxChunk = xChunks; - yMaxChunk = yChunks; - zMaxChunk = zChunks; - dirtyChunks.clear(); - //renderableTileEntities.clear(); - - for (int x = 0; x < xChunks; x++) { - for (int y = 0; y < yChunks; y++) { - for (int z = 0; z < zChunks; z++) { - const int c = getLinearCoord(x, y, z); - Chunk* chunk = new Chunk(level, x * CHUNK_SIZE, y * CHUNK_SIZE, z * CHUNK_SIZE, CHUNK_SIZE, chunkLists + id, &chunkBuffers[id]); - - if (occlusionCheck) { - chunk->occlusion_id = 0;//occlusionCheckIds.get(count); - } - chunk->occlusion_querying = false; - chunk->occlusion_visible = true; - chunk->visible = true; - chunk->id = count++; - chunk->setDirty(); - - chunks[c] = chunk; - sortedChunks[c] = chunk; - dirtyChunks.push_back(chunk); - - id += 3; - } - } - } - - if (level != NULL) { - Entity* player = mc->cameraTargetPlayer; - if (player != NULL) { - this->resortChunks(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); - DistanceChunkSorter distanceSorter(player); - std::sort(sortedChunks, sortedChunks + chunksLength, distanceSorter); - } - } - noEntityRenderFrames = 2; -} - -void LevelRenderer::deleteChunks() -{ - for (int z = 0; z < zChunks; ++z) - for (int y = 0; y < yChunks; ++y) - for (int x = 0; x < xChunks; ++x) { - int c = getLinearCoord(x, y, z); - delete chunks[c]; - } - - delete[] chunks; - chunks = NULL; - - delete[] sortedChunks; - sortedChunks = NULL; -} - -void LevelRenderer::resortChunks( int xc, int yc, int zc ) -{ - xc -= CHUNK_SIZE / 2; - //yc -= CHUNK_SIZE / 2; - zc -= CHUNK_SIZE / 2; - xMinChunk = INT_MAX; - yMinChunk = INT_MAX; - zMinChunk = INT_MAX; - xMaxChunk = INT_MIN; - yMaxChunk = INT_MIN; - zMaxChunk = INT_MIN; - - int dirty = 0; - - int s2 = xChunks * CHUNK_SIZE; - int s1 = s2 / 2; - - for (int x = 0; x < xChunks; x++) { - int xx = x * CHUNK_SIZE; - - int xOff = (xx + s1 - xc); - if (xOff < 0) xOff -= (s2 - 1); - xOff /= s2; - xx -= xOff * s2; - - if (xx < xMinChunk) xMinChunk = xx; - if (xx > xMaxChunk) xMaxChunk = xx; - - for (int z = 0; z < zChunks; z++) { - int zz = z * CHUNK_SIZE; - int zOff = (zz + s1 - zc); - if (zOff < 0) zOff -= (s2 - 1); - zOff /= s2; - zz -= zOff * s2; - - if (zz < zMinChunk) zMinChunk = zz; - if (zz > zMaxChunk) zMaxChunk = zz; - - for (int y = 0; y < yChunks; y++) { - int yy = y * CHUNK_SIZE; - if (yy < yMinChunk) yMinChunk = yy; - if (yy > yMaxChunk) yMaxChunk = yy; - - Chunk* chunk = chunks[(z * yChunks + y) * xChunks + x]; - bool wasDirty = chunk->isDirty(); - chunk->setPos(xx, yy, zz); - if (!wasDirty && chunk->isDirty()) { - dirtyChunks.push_back(chunk); - ++dirty; - } - } - } - } -} - -int LevelRenderer::render( Mob* player, int layer, float alpha ) -{ - if (mc->options.getIntValue(OPTIONS_VIEW_DISTANCE) != lastViewDistance) { - allChanged(); - } - - TIMER_PUSH("sortchunks"); - for (int i = 0; i < 10; i++) { - chunkFixOffs = (chunkFixOffs + 1) % chunksLength; - Chunk* c = chunks[chunkFixOffs]; - if (c->isDirty() && std::find(dirtyChunks.begin(), dirtyChunks.end(), c) == dirtyChunks.end()) { - dirtyChunks.push_back(c); - } - } - - if (layer == 0) { - totalChunks = 0; - offscreenChunks = 0; - occludedChunks = 0; - renderedChunks = 0; - emptyChunks = 0; - } - - float xOff = player->xOld + (player->x - player->xOld) * alpha; - float yOff = player->yOld + (player->y - player->yOld) * alpha; - float zOff = player->zOld + (player->z - player->zOld) * alpha; - - float xd = player->x - xOld; - float yd = player->y - yOld; - float zd = player->z - zOld; - if (xd * xd + yd * yd + zd * zd > 4 * 4) { - xOld = player->x; - yOld = player->y; - zOld = player->z; - - resortChunks(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); - DistanceChunkSorter distanceSorter(player); - std::sort(sortedChunks, sortedChunks + chunksLength, distanceSorter); - } - - int count = 0; - if (occlusionCheck && !mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D) && layer == 0) { - int from = 0; - int to = 16; - //checkQueryResults(from, to); - for (int i = from; i < to; i++) { - sortedChunks[i]->occlusion_visible = true; - } - - count += renderChunks(from, to, layer, alpha); - - do { - from = to; - to = to * 2; - if (to > chunksLength) to = chunksLength; - - glDisable2(GL_TEXTURE_2D); - glDisable2(GL_LIGHTING); - glDisable2(GL_ALPHA_TEST); - glDisable2(GL_FOG); - - glColorMask(false, false, false, false); - glDepthMask(false); - //checkQueryResults(from, to); - glPushMatrix2(); - float xo = 0; - float yo = 0; - float zo = 0; - for (int i = from; i < to; i++) { - if (sortedChunks[i]->isEmpty()) { - sortedChunks[i]->visible = false; - continue; - } - if (!sortedChunks[i]->visible) { - sortedChunks[i]->occlusion_visible = true; - } - - if (sortedChunks[i]->visible && !sortedChunks[i]->occlusion_querying) { - float dist = Mth::sqrt(sortedChunks[i]->distanceToSqr(player)); - - int frequency = (int) (1 + dist / 128); - - if (ticks % frequency == i % frequency) { - Chunk* chunk = sortedChunks[i]; - float xt = (float) (chunk->x - xOff); - float yt = (float) (chunk->y - yOff); - float zt = (float) (chunk->z - zOff); - float xdd = xt - xo; - float ydd = yt - yo; - float zdd = zt - zo; - - if (xdd != 0 || ydd != 0 || zdd != 0) { - glTranslatef2(xdd, ydd, zdd); - xo += xdd; - yo += ydd; - zo += zdd; - } - - sortedChunks[i]->renderBB(); - sortedChunks[i]->occlusion_querying = true; - } - } - } - glPopMatrix2(); - glColorMask(true, true, true, true); - glDepthMask(true); - glEnable2(GL_TEXTURE_2D); - glEnable2(GL_ALPHA_TEST); - glEnable2(GL_FOG); - - count += renderChunks(from, to, layer, alpha); - - } while (to < chunksLength); - - } else { - TIMER_POP_PUSH("render"); - count += renderChunks(0, chunksLength, layer, alpha); - } - - TIMER_POP(); - return count; -} - -void LevelRenderer::renderDebug(const AABB& b, float a) const { - float x0 = b.x0; - float x1 = b.x1; - float y0 = b.y0; - float y1 = b.y1; - float z0 = b.z0; - float z1 = b.z1; - float u0 = 0, v0 = 0; - float u1 = 1, v1 = 1; - - glEnable2(GL_BLEND); - glBlendFunc2(GL_DST_COLOR, GL_SRC_COLOR); - glDisable2(GL_TEXTURE_2D); - glColor4f2(1, 1, 1, 1); - - textures->loadAndBindTexture("terrain.png"); - - Tesselator& t = Tesselator::instance; - t.begin(); - t.color(255, 255, 255, 255); - - t.offset(((Mob*)mc->player)->getPos(a).negated()); - - // up - t.vertexUV(x0, y0, z1, u0, v1); - t.vertexUV(x0, y0, z0, u0, v0); - t.vertexUV(x1, y0, z0, u1, v0); - t.vertexUV(x1, y0, z1, u1, v1); - - // down - t.vertexUV(x1, y1, z1, u1, v1); - t.vertexUV(x1, y1, z0, u1, v0); - t.vertexUV(x0, y1, z0, u0, v0); - t.vertexUV(x0, y1, z1, u0, v1); - - // north - t.vertexUV(x0, y1, z0, u1, v0); - t.vertexUV(x1, y1, z0, u0, v0); - t.vertexUV(x1, y0, z0, u0, v1); - t.vertexUV(x0, y0, z0, u1, v1); - - // south - t.vertexUV(x0, y1, z1, u0, v0); - t.vertexUV(x0, y0, z1, u0, v1); - t.vertexUV(x1, y0, z1, u1, v1); - t.vertexUV(x1, y1, z1, u1, v0); - - // west - t.vertexUV(x0, y1, z1, u1, v0); - t.vertexUV(x0, y1, z0, u0, v0); - t.vertexUV(x0, y0, z0, u0, v1); - t.vertexUV(x0, y0, z1, u1, v1); - - // east - t.vertexUV(x1, y0, z1, u0, v1); - t.vertexUV(x1, y0, z0, u1, v1); - t.vertexUV(x1, y1, z0, u1, v0); - t.vertexUV(x1, y1, z1, u0, v0); - - t.offset(0, 0, 0); - t.draw(); - - glEnable2(GL_TEXTURE_2D); - glDisable2(GL_BLEND); -} - -void LevelRenderer::render(const AABB& b) const -{ - Tesselator& t = Tesselator::instance; - - glColor4f2(1, 1, 1, 1); - - textures->loadAndBindTexture("terrain.png"); - - //t.begin(); - t.color(255, 255, 255, 255); - - t.offset(((Mob*)mc->player)->getPos(0).negated()); - - t.begin(GL_LINE_STRIP); - t.vertex(b.x0, b.y0, b.z0); - t.vertex(b.x1, b.y0, b.z0); - t.vertex(b.x1, b.y0, b.z1); - t.vertex(b.x0, b.y0, b.z1); - t.vertex(b.x0, b.y0, b.z0); - t.draw(); - - t.begin(GL_LINE_STRIP); - t.vertex(b.x0, b.y1, b.z0); - t.vertex(b.x1, b.y1, b.z0); - t.vertex(b.x1, b.y1, b.z1); - t.vertex(b.x0, b.y1, b.z1); - t.vertex(b.x0, b.y1, b.z0); - t.draw(); - - t.begin(GL_LINES); - t.vertex(b.x0, b.y0, b.z0); - t.vertex(b.x0, b.y1, b.z0); - t.vertex(b.x1, b.y0, b.z0); - t.vertex(b.x1, b.y1, b.z0); - t.vertex(b.x1, b.y0, b.z1); - t.vertex(b.x1, b.y1, b.z1); - t.vertex(b.x0, b.y0, b.z1); - t.vertex(b.x0, b.y1, b.z1); - - t.offset(0, 0, 0); - t.draw(); -} - -//void LevelRenderer::checkQueryResults( int from, int to ) -//{ -// for (int i = from; i < to; i++) { -// if (sortedChunks[i]->occlusion_querying) { -// // I wanna do a fast occusion culler here. -// } -// } -//} - -int LevelRenderer::renderChunks( int from, int to, int layer, float alpha ) -{ - _renderChunks.clear(); - int count = 0; - for (int i = from; i < to; i++) { - if (layer == 0) { - totalChunks++; - if (sortedChunks[i]->empty[layer]) emptyChunks++; - else if (!sortedChunks[i]->visible) offscreenChunks++; - else if (occlusionCheck && !sortedChunks[i]->occlusion_visible) occludedChunks++; - else renderedChunks++; - } - - if (!sortedChunks[i]->empty[layer] && sortedChunks[i]->visible && sortedChunks[i]->occlusion_visible) { - int list = sortedChunks[i]->getList(layer); - if (list >= 0) { - _renderChunks.push_back(sortedChunks[i]); - count++; - } - } - } - - Mob* player = mc->cameraTargetPlayer; - float xOff = player->xOld + (player->x - player->xOld) * alpha; - float yOff = player->yOld + (player->y - player->yOld) * alpha; - float zOff = player->zOld + (player->z - player->zOld) * alpha; - - //int lists = 0; - renderList.clear(); - renderList.init(xOff, yOff, zOff); - - for (unsigned int i = 0; i < _renderChunks.size(); ++i) { - Chunk* chunk = _renderChunks[i]; - #ifdef USE_VBO - renderList.addR(chunk->getRenderChunk(layer)); - #else - renderList.add(chunk->getList(layer)); - #endif - renderList.next(); - } - - renderSameAsLast(layer, alpha); - - return count; -} - -void LevelRenderer::renderSameAsLast( int layer, float alpha ) -{ - renderList.render(); -} - -void LevelRenderer::tick() -{ - ticks++; -} - -bool LevelRenderer::updateDirtyChunks( Mob* player, bool force ) -{ - bool slow = false; - - if (slow) { - DirtyChunkSorter dirtySorter(player); - std::sort(dirtyChunks.begin(), dirtyChunks.end(), dirtySorter); - int s = dirtyChunks.size() - 1; - int amount = dirtyChunks.size(); - for (int i = 0; i < amount; i++) { - Chunk* chunk = dirtyChunks[s-i]; - if (!force) { - if (chunk->distanceToSqr(player) > 16 * 16) { - if (chunk->visible) { - if (i >= MAX_VISIBLE_REBUILDS_PER_FRAME) return false; - } else { - if (i >= MAX_INVISIBLE_REBUILDS_PER_FRAME) return false; - } - } - } else { - if (!chunk->visible) continue; - } - chunk->rebuild(); - - dirtyChunks.erase( std::find(dirtyChunks.begin(), dirtyChunks.end(), chunk) ); // @q: s-i? - chunk->setClean(); - } - - return dirtyChunks.size() == 0; - } else { - const int count = 3; - - DirtyChunkSorter dirtyChunkSorter(player); - Chunk* toAdd[count] = {NULL}; - std::vector* nearChunks = NULL; - - int pendingChunkSize = dirtyChunks.size(); - int pendingChunkRemoved = 0; - - for (int i = 0; i < pendingChunkSize; i++) { - Chunk* chunk = dirtyChunks[i]; - - if (!force) { - if (chunk->distanceToSqr(player) > 1024.0f) { - int index; - - // is this chunk in the closest ? - for (index = 0; index < count; index++) { - if (toAdd[index] != NULL && dirtyChunkSorter(toAdd[index], chunk) == false) { - break; - } - } - - index--; - - if (index > 0) { - int x = index; - while (--x != 0) { - toAdd[x - 1] = toAdd[x]; - } - toAdd[index] = chunk; - } - - continue; - } - } else if (!chunk->visible) { - continue; - } - - // chunk is very close -- always render - - if (nearChunks == NULL) { - nearChunks = new std::vector(); - } - - pendingChunkRemoved++; - nearChunks->push_back(chunk); - dirtyChunks[i] = NULL; - } - - // if there are nearby chunks that need to be prepared for - // rendering, sort them and then process them - static const float MaxFrameTime = 1.0f / 100.0f; - Stopwatch chunkWatch; - chunkWatch.start(); - - if (nearChunks != NULL) { - if (nearChunks->size() > 1) { - std::sort(nearChunks->begin(), nearChunks->end(), dirtyChunkSorter); - } - - for (int i = nearChunks->size() - 1; i >= 0; i--) { - Chunk* chunk = (*nearChunks)[i]; - chunk->rebuild(); - chunk->setClean(); - } - delete nearChunks; - } - - // render the nearest chunks (farther than 1024 units away) - int secondaryRemoved = 0; - - for (int i = count - 1; i >= 0; i--) { - Chunk* chunk = toAdd[i]; - if (chunk != NULL) { - - float ttt = chunkWatch.stopContinue(); - if (ttt >= MaxFrameTime) { - //LOGI("Too much work, I quit2!\n"); - break; - } - - if (!chunk->visible && i != count - 1) { - // escape early if chunks aren't ready - toAdd[i] = NULL; - toAdd[0] = NULL; - break; - } - toAdd[i]->rebuild(); - toAdd[i]->setClean(); - secondaryRemoved++; - } - } - - // compact by removing nulls - int cursor = 0; - int target = 0; - int arraySize = dirtyChunks.size(); - while (cursor != arraySize) { - Chunk* chunk = dirtyChunks[cursor]; - if (chunk != NULL) { - bool remove = false; - for (int i = 0; i < count && !remove; i++) - if (chunk == toAdd[i]) { - remove = true; - } - - if (!remove) { - //if (chunk == toAdd[0] || chunk == toAdd[1] || chunk == toAdd[2]) { - // ; // this chunk was rendered and should be removed - //} else { - if (target != cursor) { - dirtyChunks[target] = chunk; - } - target++; - } - } - cursor++; - } - - // trim - if (cursor > target) - dirtyChunks.erase(dirtyChunks.begin() + target, dirtyChunks.end()); - - return pendingChunkSize == (pendingChunkRemoved + secondaryRemoved); - } -} - -void LevelRenderer::renderHit( Player* player, const HitResult& h, int mode, /*ItemInstance*/void* inventoryItem, float a ) -{ - if (mode == 0) { - if (destroyProgress > 0) { - Tesselator& t = Tesselator::instance; - glEnable2(GL_BLEND); - glBlendFunc2(GL_DST_COLOR, GL_SRC_COLOR); - - textures->loadAndBindTexture("terrain.png"); - glPushMatrix2(); - - int tileId = level->getTile(h.x, h.y, h.z); - Tile* tile = tileId > 0 ? Tile::tiles[tileId] : NULL; - //glDisable2(GL_ALPHA_TEST); - - glPolygonOffset(-3.0f, -3.0f); - glEnable2(GL_POLYGON_OFFSET_FILL); - t.begin(); - t.color(1.0f, 1.0f, 1.0f, 0.5f); - t.noColor(); - float xo = player->xOld + (player->x - player->xOld) * a; - float yo = player->yOld + (player->y - player->yOld) * a; - float zo = player->zOld + (player->z - player->zOld) * a; - - t.offset(-xo, -yo, -zo); - //t.noColor(); - - if (tile == NULL) tile = Tile::rock; - const int progress = (int) (destroyProgress * 10); - tileRenderer->tesselateInWorld(tile, h.x, h.y, h.z, 15 * 16 + progress); - - t.draw(); - t.offset(0, 0, 0); - glPolygonOffset(0.0f, 0.0f); - glDisable2(GL_POLYGON_OFFSET_FILL); - //glDisable2(GL_ALPHA_TEST); - glDisable2(GL_BLEND); - - glDepthMask(true); - glPopMatrix2(); - } - } - //else if (inventoryItem != NULL) { - // glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // float br = ((float) (util.Mth::sin(System.currentTimeMillis() / 100.0f)) * 0.2f + 0.8f); - // glColor4f2(br, br, br, ((float) (util.Mth::sin(System.currentTimeMillis() / 200.0f)) * 0.2f + 0.5f)); - - // int id = textures.loadTexture("terrain.png"); - // glBindTexture2(GL_TEXTURE_2D, id); - // int x = h.x; - // int y = h.y; - // int z = h.z; - // if (h.f == 0) y--; - // if (h.f == 1) y++; - // if (h.f == 2) z--; - // if (h.f == 3) z++; - // if (h.f == 4) x--; - // if (h.f == 5) x++; - // /* - // * t.begin(); t.noColor(); Tile.tiles[tileType].tesselate(level, x, - // * y, z, t); t.end(); - // */ - // } -} - -void LevelRenderer::renderHitOutline( Player* player, const HitResult& h, int mode, /*ItemInstance*/void* inventoryItem, float a ) -{ - if (mode == 0 && h.type == TILE) { - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4f2(0, 0, 0, 0.4f); - glLineWidth(1.0f); - glDisable2(GL_TEXTURE_2D); - glDepthMask(false); - float ss = 0.002f; - int tileId = level->getTile(h.x, h.y, h.z); - - if (tileId > 0) { - Tile::tiles[tileId]->updateShape(level, h.x, h.y, h.z); - float xo = player->xOld + (player->x - player->xOld) * a; - float yo = player->yOld + (player->y - player->yOld) * a; - float zo = player->zOld + (player->z - player->zOld) * a; - render(Tile::tiles[tileId]->getTileAABB(level, h.x, h.y, h.z).grow(ss, ss, ss).cloneMove(-xo, -yo, -zo)); - } - glDepthMask(true); - glEnable2(GL_TEXTURE_2D); - glDisable2(GL_BLEND); - } -} - -void LevelRenderer::setDirty( int x0, int y0, int z0, int x1, int y1, int z1 ) -{ - int _x0 = Mth::intFloorDiv(x0, CHUNK_SIZE); - int _y0 = Mth::intFloorDiv(y0, CHUNK_SIZE); - int _z0 = Mth::intFloorDiv(z0, CHUNK_SIZE); - int _x1 = Mth::intFloorDiv(x1, CHUNK_SIZE); - int _y1 = Mth::intFloorDiv(y1, CHUNK_SIZE); - int _z1 = Mth::intFloorDiv(z1, CHUNK_SIZE); - - for (int x = _x0; x <= _x1; x++) { - int xx = x % xChunks; - if (xx < 0) xx += xChunks; - for (int y = _y0; y <= _y1; y++) { - int yy = y % yChunks; - if (yy < 0) yy += yChunks; - for (int z = _z0; z <= _z1; z++) { - int zz = z % zChunks; - if (zz < 0) zz += zChunks; - - int p = ((zz) * yChunks + (yy)) * xChunks + (xx); - Chunk* chunk = chunks[p]; - if (!chunk->isDirty()) { - dirtyChunks.push_back(chunk); - chunk->setDirty(); - } - } - } - } -} - -void LevelRenderer::tileChanged( int x, int y, int z) -{ - setDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1); -} - - -void LevelRenderer::setTilesDirty( int x0, int y0, int z0, int x1, int y1, int z1 ) -{ - setDirty(x0 - 1, y0 - 1, z0 - 1, x1 + 1, y1 + 1, z1 + 1); -} - - -void LevelRenderer::cull( Culler* culler, float a ) -{ - for (int i = 0; i < chunksLength; i++) { - if (!chunks[i]->isEmpty()) { - if (!chunks[i]->visible || ((i + cullStep) & 15) == 0) { - chunks[i]->cull(culler); - } - } - } - cullStep++; -} - -void LevelRenderer::skyColorChanged() -{ - for (int i = 0; i < chunksLength; i++) { - if (chunks[i]->skyLit) { - if (!chunks[i]->isDirty()) { - dirtyChunks.push_back(chunks[i]); - chunks[i]->setDirty(); - } - } - } -} - -bool entityRenderPredicate(const Entity* a, const Entity* b) { - return a->entityRendererId < b->entityRendererId; -} - -void LevelRenderer::renderEntities(Vec3 cam, Culler* culler, float a) { - if (noEntityRenderFrames > 0) { - noEntityRenderFrames--; - return; - } - - TIMER_PUSH("prepare"); - TileEntityRenderDispatcher::getInstance()->prepare(level, textures, mc->font, mc->cameraTargetPlayer, a); - EntityRenderDispatcher::getInstance()->prepare(level, mc->font, mc->cameraTargetPlayer, &mc->options, a); - - totalEntities = 0; - renderedEntities = 0; - culledEntities = 0; - - Entity* player = mc->cameraTargetPlayer; - EntityRenderDispatcher::xOff = TileEntityRenderDispatcher::xOff = (player->xOld + (player->x - player->xOld) * a); - EntityRenderDispatcher::yOff = TileEntityRenderDispatcher::yOff = (player->yOld + (player->y - player->yOld) * a); - EntityRenderDispatcher::zOff = TileEntityRenderDispatcher::zOff = (player->zOld + (player->z - player->zOld) * a); - - glEnableClientState2(GL_VERTEX_ARRAY); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - - TIMER_POP_PUSH("entities"); - const EntityList& entities = level->getAllEntities(); - totalEntities = entities.size(); - if (totalEntities > 0) { - Entity** toRender = new Entity*[totalEntities]; - for (int i = 0; i < totalEntities; i++) { - Entity* entity = entities[i]; - - bool thirdPerson = mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW); - - if (entity->shouldRender(cam) && culler->isVisible(entity->bb)) - { - if (entity == mc->cameraTargetPlayer && thirdPerson == 0 && mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping()) continue; - if (entity == mc->cameraTargetPlayer && !thirdPerson) - continue; - if (!level->hasChunkAt(Mth::floor(entity->x), Mth::floor(entity->y), Mth::floor(entity->z))) - continue; - - toRender[renderedEntities++] = entity; - //EntityRenderDispatcher::getInstance()->render(entity, a); - } - } - - if (renderedEntities > 0) { - std::sort(&toRender[0], &toRender[renderedEntities], entityRenderPredicate); - for (int i = 0; i < renderedEntities; ++i) { - EntityRenderDispatcher* disp = EntityRenderDispatcher::getInstance(); - disp->render(toRender[i], a); - } - } - - delete[] toRender; - } - - TIMER_POP_PUSH("tileentities"); - for (unsigned int i = 0; i < level->tileEntities.size(); i++) { - TileEntityRenderDispatcher::getInstance()->render(level->tileEntities[i], a); - } - - glDisableClientState2(GL_VERTEX_ARRAY); - glDisableClientState2(GL_TEXTURE_COORD_ARRAY); - - TIMER_POP(); -} - -std::string LevelRenderer::gatherStats1() { - std::stringstream ss; - ss << "C: " << renderedChunks << "/" << totalChunks << ". F: " << offscreenChunks << ", O: " << occludedChunks << ", E: " << emptyChunks << "\n"; - return ss.str(); -} - -// -// /*public*/ std::string gatherStats2() { -// return "E: " + renderedEntities + "/" + totalEntities + ". B: " + culledEntities + ", I: " + ((totalEntities - culledEntities) - renderedEntities); -// } -// -// int[] toRender = new int[50000]; -// IntBuffer resultBuffer = MemoryTracker.createIntBuffer(64); - -void LevelRenderer::renderSky(float alpha) { - if (mc->level->dimension->foggy) return; - - glDisable2(GL_TEXTURE_2D); - Vec3 sc = level->getSkyColor(mc->cameraTargetPlayer, alpha); - float sr = (float) sc.x; - float sg = (float) sc.y; - float sb = (float) sc.z;// + 0.5f; - - if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { - float srr = (sr * 30.0f + sg * 59.0f + sb * 11.0f) / 100.0f; - float sgg = (sr * 30.0f + sg * 70.0f) / (100.0f); - float sbb = (sr * 30.0f + sb * 70.0f) / (100.0f); - - sr = srr; - sg = sgg; - sb = sbb; - } - glColor4f2(sr, sg, Mth::Min(1.0f, sb), 1); - - //Tesselator& t = Tesselator::instance; - - glEnable2(GL_FOG); - glColor4f2(sr, sg, sb, 1.0f); - -#ifdef OPENGL_ES - drawArrayVT(skyBuffer, skyVertexCount); -#endif - glEnable2(GL_TEXTURE_2D); -} - -void LevelRenderer::renderClouds( float alpha ) { - //if (!mc->level->dimension->isNaturalDimension()) return; - glEnable2(GL_TEXTURE_2D); - glDisable(GL_CULL_FACE); - float yOffs = (float) (mc->player->yOld + (mc->player->y - mc->player->yOld) * alpha); - int s = 32; - int d = 256 / s; - Tesselator& t = Tesselator::instance; - - //glBindTexture(GL_TEXTURE_2D, texturesloadTexture("/environment/clouds.png")); - textures->loadAndBindTexture("environment/clouds.png"); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - Vec3 cc = level->getCloudColor(alpha); - float cr = (float) cc.x; - float cg = (float) cc.y; - float cb = (float) cc.z; - - float scale = 1 / 2048.0f; - - float time = (ticks + alpha); - float xo = mc->player->xo + (mc->player->x - mc->player->xo) * alpha + time * 0.03f; - float zo = mc->player->zo + (mc->player->z - mc->player->zo) * alpha; - int xOffs = Mth::floor(xo / 2048); - int zOffs = Mth::floor(zo / 2048); - xo -= xOffs * 2048; - zo -= zOffs * 2048; - - float yy = /*level.dimension.getCloudHeight()*/ 128 - yOffs + 0.33f;//mc->player->y + 1; - float uo = (float) (xo * scale); - float vo = (float) (zo * scale); - t.begin(); - - t.color(cr, cg, cb, 0.8f); - for (int xx = -s * d; xx < +s * d; xx += s) { - for (int zz = -s * d; zz < +s * d; zz += s) { - t.vertexUV((float)xx, yy, (float)zz + s, xx * scale + uo, (zz + s) * scale + vo); - t.vertexUV((float)xx + s, yy, (float)zz + s, (xx + s) * scale + uo, (zz + s) * scale + vo); - t.vertexUV((float)xx + s, yy, (float)zz, (xx + s) * scale + uo, zz * scale + vo); - t.vertexUV((float)xx, yy, (float)zz, xx * scale + uo, zz * scale + vo); - } - } - t.endOverrideAndDraw(); - glColor4f(1, 1, 1, 1.0f); - glDisable(GL_BLEND); - glEnable(GL_CULL_FACE); -} - -void LevelRenderer::playSound(const std::string& name, float x, float y, float z, float volume, float pitch) { - // @todo: deny sounds here if sound is off (rather than waiting 'til SoundEngine) - float dd = 16; - - if (volume > 1) dd *= volume; - if (mc->cameraTargetPlayer->distanceToSqr(x, y, z) < dd * dd) { - mc->soundEngine->play(name, x, y, z, volume, pitch); - } -} - -void LevelRenderer::addParticle(const std::string& name, float x, float y, float z, float xa, float ya, float za, int data) { - - float xd = mc->cameraTargetPlayer->x - x; - float yd = mc->cameraTargetPlayer->y - y; - float zd = mc->cameraTargetPlayer->z - z; - float distanceSquared = xd * xd + yd * yd + zd * zd; - - //Particle* p = NULL; - //if (name == "hugeexplosion") p = new HugeExplosionSeedParticle(level, x, y, z, xa, ya, za); - //else if (name == "largeexplode") p = new HugeExplosionParticle(textures, level, x, y, z, xa, ya, za); - - //if (p) { - // if (distanceSquared < 32 * 32) { - // mc->particleEngine->add(p); - // } else { delete p; } - // return; - //} - - const float particleDistance = 16; - if (distanceSquared > particleDistance * particleDistance) return; - - //static Stopwatch sw; - //sw.start(); - - if (name == "bubble") mc->particleEngine->add(new BubbleParticle(level, x, y, z, xa, ya, za)); - else if (name == "crit") mc->particleEngine->add(new CritParticle2(level, x, y, z, xa, ya, za)); - else if (name == "smoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za)); - //else if (name == "note") mc->particleEngine->add(new NoteParticle(level, x, y, z, xa, ya, za)); - else if (name == "explode") mc->particleEngine->add(new ExplodeParticle(level, x, y, z, xa, ya, za)); - else if (name == "flame") mc->particleEngine->add(new FlameParticle(level, x, y, z, xa, ya, za)); - else if (name == "lava") mc->particleEngine->add(new LavaParticle(level, x, y, z)); - //else if (name == "splash") mc->particleEngine->add(new SplashParticle(level, x, y, z, xa, ya, za)); - else if (name == "largesmoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f)); - else if (name == "reddust") mc->particleEngine->add(new RedDustParticle(level, x, y, z, xa, ya, za)); - else if (name == "iconcrack") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data])); - else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); - //else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); - //else if (name == "slime") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::slimeBall)); - //else if (name == "heart") mc->particleEngine->add(new HeartParticle(level, x, y, z, xa, ya, za)); - - //sw.stop(); - //sw.printEvery(50, "add-particle-string"); -} - -/* -void LevelRenderer::addParticle(ParticleType::Id name, float x, float y, float z, float xa, float ya, float za, int data) { - float xd = mc->cameraTargetPlayer->x - x; - float yd = mc->cameraTargetPlayer->y - y; - float zd = mc->cameraTargetPlayer->z - z; - - const float particleDistance = 16; - if (xd * xd + yd * yd + zd * zd > particleDistance * particleDistance) return; - - //static Stopwatch sw; - //sw.start(); - - //Particle* p = NULL; - - if (name == ParticleType::bubble) mc->particleEngine->add( new BubbleParticle(level, x, y, z, xa, ya, za) ); - else if (name == ParticleType::crit) mc->particleEngine->add(new CritParticle2(level, x, y, z, xa, ya, za) ); - else if (name == ParticleType::smoke) mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za) ); - else if (name == ParticleType::explode) mc->particleEngine->add( new ExplodeParticle(level, x, y, z, xa, ya, za) ); - else if (name == ParticleType::flame) mc->particleEngine->add( new FlameParticle(level, x, y, z, xa, ya, za) ); - else if (name == ParticleType::lava) mc->particleEngine->add( new LavaParticle(level, x, y, z) ); - else if (name == ParticleType::largesmoke) mc->particleEngine->add( new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f) ); - else if (name == ParticleType::reddust) mc->particleEngine->add( new RedDustParticle(level, x, y, z, xa, ya, za) ); - else if (name == ParticleType::iconcrack) mc->particleEngine->add( new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data]) ); - - //switch (name) { - // case ParticleType::bubble: p = new BubbleParticle(level, x, y, z, xa, ya, za); break; - // case ParticleType::crit: p = new CritParticle2(level, x, y, z, xa, ya, za); break; - // case ParticleType::smoke: p = new SmokeParticle(level, x, y, z, xa, ya, za); break; - // //case ParticleType::note: p = new NoteParticle(level, x, y, z, xa, ya, za); break; - // case ParticleType::explode: p = new ExplodeParticle(level, x, y, z, xa, ya, za); break; - // case ParticleType::flame: p = new FlameParticle(level, x, y, z, xa, ya, za); break; - // case ParticleType::lava: p = new LavaParticle(level, x, y, z); break; - // //case ParticleType::splash: p = new SplashParticle(level, x, y, z, xa, ya, za); break; - // case ParticleType::largesmoke: p = new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f); break; - // case ParticleType::reddust: p = new RedDustParticle(level, x, y, z, xa, ya, za); break; - // case ParticleType::iconcrack: p = new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data]); break; - // //case ParticleType::snowballpoof: p = new BreakingItemParticle(level, x, y, z, Item::snowBall); break; - // //case ParticleType::slime: p = new BreakingItemParticle(level, x, y, z, Item::slimeBall); break; - // //case ParticleType::heart: p = new HeartParticle(level, x, y, z, xa, ya, za); break; - // default: - // LOGW("Couldn't find particle of type: %d\n", name); - // break; - //} - //if (p) { - // mc->particleEngine->add(p); - //} - - //sw.stop(); - //sw.printEvery(50, "add-particle-enum"); -} -*/ - -void LevelRenderer::renderHitSelect( Player* player, const HitResult& h, int mode, /*ItemInstance*/void* inventoryItem, float a ) -{ - //if (h.type == TILE) LOGI("type: %s @ (%d, %d, %d)\n", Tile::tiles[level->getTile(h.x, h.y, h.z)]->getDescriptionId().c_str(), h.x, h.y, h.z); - - if (mode == 0) { - - Tesselator& t = Tesselator::instance; - glEnable2(GL_BLEND); - glDisable2(GL_TEXTURE_2D); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE); - glBlendFunc2(GL_DST_COLOR, GL_SRC_COLOR); - glEnable2(GL_DEPTH_TEST); - - textures->loadAndBindTexture("terrain.png"); - - int tileId = level->getTile(h.x, h.y, h.z); - Tile* tile = tileId > 0 ? Tile::tiles[tileId] : NULL; - glDisable2(GL_ALPHA_TEST); - - //LOGI("block: %d - %d (%s)\n", tileId, level->getData(h.x, h.y, h.z), tile==NULL?"null" : tile->getDescriptionId().c_str() ); - - const float br = 0.65f; - glColor4f2(br * 1.0f, br * 1.0f, br * 1.0f, br * 1.0f); - glPushMatrix2(); - - //glPolygonOffset(-.3f, -.3f); - glPolygonOffset(-1.f, -1.f); //Implementation dependent units - glEnable2(GL_POLYGON_OFFSET_FILL); - float xo = player->xOld + (player->x - player->xOld) * a; - float yo = player->yOld + (player->y - player->yOld) * a; - float zo = player->zOld + (player->z - player->zOld) * a; - - t.begin(); - t.offset(-xo, -yo, -zo); - t.noColor(); - - if (tile == NULL) tile = Tile::rock; - tileRenderer->tesselateInWorld(tile, h.x, h.y, h.z); - - t.draw(); - t.offset(0, 0, 0); - glPolygonOffset(0.0f, 0.0f); - - glDisable2(GL_POLYGON_OFFSET_FILL); - glEnable2(GL_TEXTURE_2D); - - glDepthMask(true); - glPopMatrix2(); - - glEnable2(GL_ALPHA_TEST); - glDisable2(GL_BLEND); - } -} - -void LevelRenderer::onGraphicsReset() -{ - generateSky(); - - // Get new buffers -#ifdef OPENGL_ES - glGenBuffers2(numListsOrBuffers, chunkBuffers); -#else - chunkLists = glGenLists(numListsOrBuffers); -#endif - - // Rebuild - allChanged(); -} - -void LevelRenderer::entityAdded( Entity* entity ) -{ - if (!entity->isPlayer()) - return; - - // Hack to (hopefully) get the players to show - EntityRenderDispatcher::getInstance()->onGraphicsReset(); -} - -int _t_keepPic = -1; - -void LevelRenderer::takePicture( TripodCamera* cam, Entity* entity ) -{ - // Push old values - Mob* oldCameraEntity = mc->cameraTargetPlayer; - bool hideGui = mc->options.getBooleanValue(OPTIONS_HIDEGUI); - bool thirdPerson = mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW); - - // @huge @attn: This is highly illegal, super temp! - mc->cameraTargetPlayer = (Mob*)cam; - mc->options.set(OPTIONS_HIDEGUI, true); - mc->options.set(OPTIONS_THIRD_PERSON_VIEW, false); - - mc->gameRenderer->renderLevel(0); - - // Pop values back - mc->cameraTargetPlayer = oldCameraEntity; - mc->options.set(OPTIONS_HIDEGUI, hideGui); - mc->options.set(OPTIONS_THIRD_PERSON_VIEW, thirdPerson); - - _t_keepPic = -1; - - // Save image - static char filename[256]; - sprintf(filename, "%s/games/com.mojang/img_%.4d.jpg", mc->externalStoragePath.c_str(), getTimeMs()); - - mc->platform()->saveScreenshot(filename, mc->width, mc->height); -} - -void LevelRenderer::levelEvent(Player* player, int type, int x, int y, int z, int data) { - switch (type) { - case LevelEvent::SOUND_OPEN_DOOR: - if (Mth::random() < 0.5f) { - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, "random.door_open", 1, level->random.nextFloat() * 0.1f + 0.9f); - } else { - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, "random.door_close", 1, level->random.nextFloat() * 0.1f + 0.9f); - } - break; - } -} +#include "LevelRenderer.hpp" + +#include "DirtyChunkSorter.hpp" +#include "DistanceChunkSorter.hpp" +#include "Chunk.hpp" +#include "TileRenderer.hpp" +#include +#include "util/Mth.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/tile/LevelEvent.hpp" +#include "world/level/tile/LeafTile.hpp" +#include "client/particle/ParticleEngine.hpp" +#include "client/particle/ParticleInclude.hpp" +#include "client/sound/SoundEngine.hpp" +#include "culling/Culler.hpp" +#include "entity/EntityRenderDispatcher.hpp" +#include "client/model/HumanoidModel.hpp" + +#include "GameRenderer.hpp" +#include "AppPlatform.hpp" +#include "util/PerfTimer.hpp" +#include "Textures.hpp" +#include "tileentity/TileEntityRenderDispatcher.hpp" +#include "client/particle/BreakingItemParticle.hpp" + +#include "client/player/LocalPlayer.hpp" + +#ifdef GFX_SMALLER_CHUNKS +/* static */ const int LevelRenderer::CHUNK_SIZE = 8; +#else +/* static */ const int LevelRenderer::CHUNK_SIZE = 16; +#endif + +LevelRenderer::LevelRenderer( Minecraft* mc) +: mc(mc), + textures(mc->textures), + level(NULL), + cullStep(0), + + chunkLists(0), + xChunks(0), yChunks(0), zChunks(0), + + chunks(NULL), + sortedChunks(NULL), + + xMinChunk(0), yMinChunk(0), zMinChunk(0), + xMaxChunk(0), yMaxChunk(0), zMaxChunk(0), + + lastViewDistance(-1), + + noEntityRenderFrames(2), + totalEntities(0), + renderedEntities(0), + culledEntities(0), + + occlusionCheck(false), + totalChunks(0), offscreenChunks(0), renderedChunks(0), occludedChunks(0), emptyChunks(0), + + chunkFixOffs(0), + xOld(-9999), yOld(-9999), zOld(-9999), + + ticks(0), + skyList(0), starList(0), darkList(0), + tileRenderer(NULL), + destroyProgress(0) +{ +#ifdef OPENGL_ES + int maxChunksWidth = 2 * LEVEL_WIDTH / CHUNK_SIZE + 1; + numListsOrBuffers = maxChunksWidth * maxChunksWidth * (128/CHUNK_SIZE) * 3; + chunkBuffers = new GLuint[numListsOrBuffers]; + glGenBuffers2(numListsOrBuffers, chunkBuffers); + LOGI("numBuffers: %d\n", numListsOrBuffers); + //for (int i = 0; i < numListsOrBuffers; ++i) printf("bufId %d: %d\t", i, chunkBuffers[i]); + + glGenBuffers2(1, &skyBuffer); + generateSky(); +#else + int maxChunksWidth = 1024 / CHUNK_SIZE; + numListsOrBuffers = maxChunksWidth * maxChunksWidth * maxChunksWidth * 3; + chunkLists = glGenLists(numListsOrBuffers); +#endif +} + +LevelRenderer::~LevelRenderer() +{ + delete tileRenderer; + tileRenderer = NULL; + + deleteChunks(); + +#ifdef OPENGL_ES + glDeleteBuffers(numListsOrBuffers, chunkBuffers); + glDeleteBuffers(1, &skyBuffer); + delete[] chunkBuffers; +#else + glDeleteLists(numListsOrBuffers, chunkLists); +#endif +} + +void LevelRenderer::generateSky() { + Tesselator& t = Tesselator::instance; + float yy; + int s = 128; + int d = (256 / s) + 2; + yy = (float) (16); + t.begin(); + + skyVertexCount = 0; + for (int xx = -s * d; xx <= s * d; xx += s) { + for (int zz = -s * d; zz <= s * d; zz += s) { + t.vertex((float) xx + 0, yy, (float) zz + 0); + t.vertex((float)(xx + s), yy, (float) zz + 0); + t.vertex((float)(xx + s), yy, (float)(zz + s)); + t.vertex((float) xx + 0, yy, (float)(zz + s)); + //LOGI("x, z: %d, %d\n", xx, zz); + skyVertexCount += 4; + } + } + + t.end(true, skyBuffer); + //LOGI("skyvertexcount: %d\n", skyVertexCount); + //glEndList(); +} + +void LevelRenderer::setLevel( Level* level ) +{ + if (this->level != NULL) { + this->level->removeListener(this); + } + + xOld = -9999; + yOld = -9999; + zOld = -9999; + + EntityRenderDispatcher::getInstance()->setLevel(level); + EntityRenderDispatcher::getInstance()->setMinecraft(mc); + this->level = level; + + delete tileRenderer; + tileRenderer = new TileRenderer(level); + + if (level != NULL) { + level->addListener(this); + allChanged(); + } +} + +void LevelRenderer::allChanged() +{ + deleteChunks(); + + bool fancy = mc->options.getBooleanValue(OPTIONS_FANCY_GRAPHICS); + + Tile::leaves->setFancy(fancy); + Tile::leaves_carried->setFancy(fancy); + lastViewDistance = mc->options.getIntValue(OPTIONS_VIEW_DISTANCE); + + int dist = (512 >> 3) << (3 - lastViewDistance); + if (lastViewDistance <= 2 && mc->isPowerVR()) + dist = (int)((float)dist * 0.8f); + LOGI("last: %d, power: %d\n", lastViewDistance, mc->isPowerVR()); + + #if defined(RPI) + dist *= 0.6f; + #endif + + if (dist > 400) dist = 400; + /* + * if (Minecraft.FLYBY_MODE) { dist = 512 - CHUNK_SIZE * 2; } + */ + xChunks = (dist / LevelRenderer::CHUNK_SIZE) + 1; + yChunks = (128 / LevelRenderer::CHUNK_SIZE); + zChunks = (dist / LevelRenderer::CHUNK_SIZE) + 1; + chunksLength = xChunks * yChunks * zChunks; + LOGI("chunksLength: %d. Distance: %d\n", chunksLength, dist); + + chunks = new Chunk*[chunksLength]; + sortedChunks = new Chunk*[chunksLength]; + + int id = 0; + int count = 0; + + xMinChunk = 0; + yMinChunk = 0; + zMinChunk = 0; + xMaxChunk = xChunks; + yMaxChunk = yChunks; + zMaxChunk = zChunks; + dirtyChunks.clear(); + //renderableTileEntities.clear(); + + for (int x = 0; x < xChunks; x++) { + for (int y = 0; y < yChunks; y++) { + for (int z = 0; z < zChunks; z++) { + const int c = getLinearCoord(x, y, z); + Chunk* chunk = new Chunk(level, x * CHUNK_SIZE, y * CHUNK_SIZE, z * CHUNK_SIZE, CHUNK_SIZE, chunkLists + id, &chunkBuffers[id]); + + if (occlusionCheck) { + chunk->occlusion_id = 0;//occlusionCheckIds.get(count); + } + chunk->occlusion_querying = false; + chunk->occlusion_visible = true; + chunk->visible = true; + chunk->id = count++; + chunk->setDirty(); + + chunks[c] = chunk; + sortedChunks[c] = chunk; + dirtyChunks.push_back(chunk); + + id += 3; + } + } + } + + if (level != NULL) { + Entity* player = mc->cameraTargetPlayer; + if (player != NULL) { + this->resortChunks(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); + DistanceChunkSorter distanceSorter(player); + std::sort(sortedChunks, sortedChunks + chunksLength, distanceSorter); + } + } + noEntityRenderFrames = 2; +} + +void LevelRenderer::deleteChunks() +{ + for (int z = 0; z < zChunks; ++z) + for (int y = 0; y < yChunks; ++y) + for (int x = 0; x < xChunks; ++x) { + int c = getLinearCoord(x, y, z); + delete chunks[c]; + } + + delete[] chunks; + chunks = NULL; + + delete[] sortedChunks; + sortedChunks = NULL; +} + +void LevelRenderer::resortChunks( int xc, int yc, int zc ) +{ + xc -= CHUNK_SIZE / 2; + //yc -= CHUNK_SIZE / 2; + zc -= CHUNK_SIZE / 2; + xMinChunk = INT_MAX; + yMinChunk = INT_MAX; + zMinChunk = INT_MAX; + xMaxChunk = INT_MIN; + yMaxChunk = INT_MIN; + zMaxChunk = INT_MIN; + + int dirty = 0; + + int s2 = xChunks * CHUNK_SIZE; + int s1 = s2 / 2; + + for (int x = 0; x < xChunks; x++) { + int xx = x * CHUNK_SIZE; + + int xOff = (xx + s1 - xc); + if (xOff < 0) xOff -= (s2 - 1); + xOff /= s2; + xx -= xOff * s2; + + if (xx < xMinChunk) xMinChunk = xx; + if (xx > xMaxChunk) xMaxChunk = xx; + + for (int z = 0; z < zChunks; z++) { + int zz = z * CHUNK_SIZE; + int zOff = (zz + s1 - zc); + if (zOff < 0) zOff -= (s2 - 1); + zOff /= s2; + zz -= zOff * s2; + + if (zz < zMinChunk) zMinChunk = zz; + if (zz > zMaxChunk) zMaxChunk = zz; + + for (int y = 0; y < yChunks; y++) { + int yy = y * CHUNK_SIZE; + if (yy < yMinChunk) yMinChunk = yy; + if (yy > yMaxChunk) yMaxChunk = yy; + + Chunk* chunk = chunks[(z * yChunks + y) * xChunks + x]; + bool wasDirty = chunk->isDirty(); + chunk->setPos(xx, yy, zz); + if (!wasDirty && chunk->isDirty()) { + dirtyChunks.push_back(chunk); + ++dirty; + } + } + } + } +} + +int LevelRenderer::render( Mob* player, int layer, float alpha ) +{ + if (mc->options.getIntValue(OPTIONS_VIEW_DISTANCE) != lastViewDistance) { + allChanged(); + } + + TIMER_PUSH("sortchunks"); + for (int i = 0; i < 10; i++) { + chunkFixOffs = (chunkFixOffs + 1) % chunksLength; + Chunk* c = chunks[chunkFixOffs]; + if (c->isDirty() && std::find(dirtyChunks.begin(), dirtyChunks.end(), c) == dirtyChunks.end()) { + dirtyChunks.push_back(c); + } + } + + if (layer == 0) { + totalChunks = 0; + offscreenChunks = 0; + occludedChunks = 0; + renderedChunks = 0; + emptyChunks = 0; + } + + float xOff = player->xOld + (player->x - player->xOld) * alpha; + float yOff = player->yOld + (player->y - player->yOld) * alpha; + float zOff = player->zOld + (player->z - player->zOld) * alpha; + + float xd = player->x - xOld; + float yd = player->y - yOld; + float zd = player->z - zOld; + if (xd * xd + yd * yd + zd * zd > 4 * 4) { + xOld = player->x; + yOld = player->y; + zOld = player->z; + + resortChunks(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); + DistanceChunkSorter distanceSorter(player); + std::sort(sortedChunks, sortedChunks + chunksLength, distanceSorter); + } + + int count = 0; + if (occlusionCheck && !mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D) && layer == 0) { + int from = 0; + int to = 16; + //checkQueryResults(from, to); + for (int i = from; i < to; i++) { + sortedChunks[i]->occlusion_visible = true; + } + + count += renderChunks(from, to, layer, alpha); + + do { + from = to; + to = to * 2; + if (to > chunksLength) to = chunksLength; + + glDisable2(GL_TEXTURE_2D); + glDisable2(GL_LIGHTING); + glDisable2(GL_ALPHA_TEST); + glDisable2(GL_FOG); + + glColorMask(false, false, false, false); + glDepthMask(false); + //checkQueryResults(from, to); + glPushMatrix2(); + float xo = 0; + float yo = 0; + float zo = 0; + for (int i = from; i < to; i++) { + if (sortedChunks[i]->isEmpty()) { + sortedChunks[i]->visible = false; + continue; + } + if (!sortedChunks[i]->visible) { + sortedChunks[i]->occlusion_visible = true; + } + + if (sortedChunks[i]->visible && !sortedChunks[i]->occlusion_querying) { + float dist = Mth::sqrt(sortedChunks[i]->distanceToSqr(player)); + + int frequency = (int) (1 + dist / 128); + + if (ticks % frequency == i % frequency) { + Chunk* chunk = sortedChunks[i]; + float xt = (float) (chunk->x - xOff); + float yt = (float) (chunk->y - yOff); + float zt = (float) (chunk->z - zOff); + float xdd = xt - xo; + float ydd = yt - yo; + float zdd = zt - zo; + + if (xdd != 0 || ydd != 0 || zdd != 0) { + glTranslatef2(xdd, ydd, zdd); + xo += xdd; + yo += ydd; + zo += zdd; + } + + sortedChunks[i]->renderBB(); + sortedChunks[i]->occlusion_querying = true; + } + } + } + glPopMatrix2(); + glColorMask(true, true, true, true); + glDepthMask(true); + glEnable2(GL_TEXTURE_2D); + glEnable2(GL_ALPHA_TEST); + glEnable2(GL_FOG); + + count += renderChunks(from, to, layer, alpha); + + } while (to < chunksLength); + + } else { + TIMER_POP_PUSH("render"); + count += renderChunks(0, chunksLength, layer, alpha); + } + + TIMER_POP(); + return count; +} + +void LevelRenderer::renderDebug(const AABB& b, float a) const { + float x0 = b.x0; + float x1 = b.x1; + float y0 = b.y0; + float y1 = b.y1; + float z0 = b.z0; + float z1 = b.z1; + float u0 = 0, v0 = 0; + float u1 = 1, v1 = 1; + + glEnable2(GL_BLEND); + glBlendFunc2(GL_DST_COLOR, GL_SRC_COLOR); + glDisable2(GL_TEXTURE_2D); + glColor4f2(1, 1, 1, 1); + + textures->loadAndBindTexture("terrain.png"); + + Tesselator& t = Tesselator::instance; + t.begin(); + t.color(255, 255, 255, 255); + + t.offset(((Mob*)mc->player)->getPos(a).negated()); + + // up + t.vertexUV(x0, y0, z1, u0, v1); + t.vertexUV(x0, y0, z0, u0, v0); + t.vertexUV(x1, y0, z0, u1, v0); + t.vertexUV(x1, y0, z1, u1, v1); + + // down + t.vertexUV(x1, y1, z1, u1, v1); + t.vertexUV(x1, y1, z0, u1, v0); + t.vertexUV(x0, y1, z0, u0, v0); + t.vertexUV(x0, y1, z1, u0, v1); + + // north + t.vertexUV(x0, y1, z0, u1, v0); + t.vertexUV(x1, y1, z0, u0, v0); + t.vertexUV(x1, y0, z0, u0, v1); + t.vertexUV(x0, y0, z0, u1, v1); + + // south + t.vertexUV(x0, y1, z1, u0, v0); + t.vertexUV(x0, y0, z1, u0, v1); + t.vertexUV(x1, y0, z1, u1, v1); + t.vertexUV(x1, y1, z1, u1, v0); + + // west + t.vertexUV(x0, y1, z1, u1, v0); + t.vertexUV(x0, y1, z0, u0, v0); + t.vertexUV(x0, y0, z0, u0, v1); + t.vertexUV(x0, y0, z1, u1, v1); + + // east + t.vertexUV(x1, y0, z1, u0, v1); + t.vertexUV(x1, y0, z0, u1, v1); + t.vertexUV(x1, y1, z0, u1, v0); + t.vertexUV(x1, y1, z1, u0, v0); + + t.offset(0, 0, 0); + t.draw(); + + glEnable2(GL_TEXTURE_2D); + glDisable2(GL_BLEND); +} + +void LevelRenderer::render(const AABB& b) const +{ + Tesselator& t = Tesselator::instance; + + glColor4f2(1, 1, 1, 1); + + textures->loadAndBindTexture("terrain.png"); + + //t.begin(); + t.color(255, 255, 255, 255); + + t.offset(((Mob*)mc->player)->getPos(0).negated()); + + t.begin(GL_LINE_STRIP); + t.vertex(b.x0, b.y0, b.z0); + t.vertex(b.x1, b.y0, b.z0); + t.vertex(b.x1, b.y0, b.z1); + t.vertex(b.x0, b.y0, b.z1); + t.vertex(b.x0, b.y0, b.z0); + t.draw(); + + t.begin(GL_LINE_STRIP); + t.vertex(b.x0, b.y1, b.z0); + t.vertex(b.x1, b.y1, b.z0); + t.vertex(b.x1, b.y1, b.z1); + t.vertex(b.x0, b.y1, b.z1); + t.vertex(b.x0, b.y1, b.z0); + t.draw(); + + t.begin(GL_LINES); + t.vertex(b.x0, b.y0, b.z0); + t.vertex(b.x0, b.y1, b.z0); + t.vertex(b.x1, b.y0, b.z0); + t.vertex(b.x1, b.y1, b.z0); + t.vertex(b.x1, b.y0, b.z1); + t.vertex(b.x1, b.y1, b.z1); + t.vertex(b.x0, b.y0, b.z1); + t.vertex(b.x0, b.y1, b.z1); + + t.offset(0, 0, 0); + t.draw(); +} + +//void LevelRenderer::checkQueryResults( int from, int to ) +//{ +// for (int i = from; i < to; i++) { +// if (sortedChunks[i]->occlusion_querying) { +// // I wanna do a fast occusion culler here. +// } +// } +//} + +int LevelRenderer::renderChunks( int from, int to, int layer, float alpha ) +{ + _renderChunks.clear(); + int count = 0; + for (int i = from; i < to; i++) { + if (layer == 0) { + totalChunks++; + if (sortedChunks[i]->empty[layer]) emptyChunks++; + else if (!sortedChunks[i]->visible) offscreenChunks++; + else if (occlusionCheck && !sortedChunks[i]->occlusion_visible) occludedChunks++; + else renderedChunks++; + } + + if (!sortedChunks[i]->empty[layer] && sortedChunks[i]->visible && sortedChunks[i]->occlusion_visible) { + int list = sortedChunks[i]->getList(layer); + if (list >= 0) { + _renderChunks.push_back(sortedChunks[i]); + count++; + } + } + } + + Mob* player = mc->cameraTargetPlayer; + float xOff = player->xOld + (player->x - player->xOld) * alpha; + float yOff = player->yOld + (player->y - player->yOld) * alpha; + float zOff = player->zOld + (player->z - player->zOld) * alpha; + + //int lists = 0; + renderList.clear(); + renderList.init(xOff, yOff, zOff); + + for (unsigned int i = 0; i < _renderChunks.size(); ++i) { + Chunk* chunk = _renderChunks[i]; + #ifdef USE_VBO + renderList.addR(chunk->getRenderChunk(layer)); + #else + renderList.add(chunk->getList(layer)); + #endif + renderList.next(); + } + + renderSameAsLast(layer, alpha); + + return count; +} + +void LevelRenderer::renderSameAsLast( int layer, float alpha ) +{ + renderList.render(); +} + +void LevelRenderer::tick() +{ + ticks++; +} + +bool LevelRenderer::updateDirtyChunks( Mob* player, bool force ) +{ + bool slow = false; + + if (slow) { + DirtyChunkSorter dirtySorter(player); + std::sort(dirtyChunks.begin(), dirtyChunks.end(), dirtySorter); + int s = dirtyChunks.size() - 1; + int amount = dirtyChunks.size(); + for (int i = 0; i < amount; i++) { + Chunk* chunk = dirtyChunks[s-i]; + if (!force) { + if (chunk->distanceToSqr(player) > 16 * 16) { + if (chunk->visible) { + if (i >= MAX_VISIBLE_REBUILDS_PER_FRAME) return false; + } else { + if (i >= MAX_INVISIBLE_REBUILDS_PER_FRAME) return false; + } + } + } else { + if (!chunk->visible) continue; + } + chunk->rebuild(); + + dirtyChunks.erase( std::find(dirtyChunks.begin(), dirtyChunks.end(), chunk) ); // @q: s-i? + chunk->setClean(); + } + + return dirtyChunks.size() == 0; + } else { + const int count = 3; + + DirtyChunkSorter dirtyChunkSorter(player); + Chunk* toAdd[count] = {NULL}; + std::vector* nearChunks = NULL; + + int pendingChunkSize = dirtyChunks.size(); + int pendingChunkRemoved = 0; + + for (int i = 0; i < pendingChunkSize; i++) { + Chunk* chunk = dirtyChunks[i]; + + if (!force) { + if (chunk->distanceToSqr(player) > 1024.0f) { + int index; + + // is this chunk in the closest ? + for (index = 0; index < count; index++) { + if (toAdd[index] != NULL && dirtyChunkSorter(toAdd[index], chunk) == false) { + break; + } + } + + index--; + + if (index > 0) { + int x = index; + while (--x != 0) { + toAdd[x - 1] = toAdd[x]; + } + toAdd[index] = chunk; + } + + continue; + } + } else if (!chunk->visible) { + continue; + } + + // chunk is very close -- always render + + if (nearChunks == NULL) { + nearChunks = new std::vector(); + } + + pendingChunkRemoved++; + nearChunks->push_back(chunk); + dirtyChunks[i] = NULL; + } + + // if there are nearby chunks that need to be prepared for + // rendering, sort them and then process them + static const float MaxFrameTime = 1.0f / 100.0f; + Stopwatch chunkWatch; + chunkWatch.start(); + + if (nearChunks != NULL) { + if (nearChunks->size() > 1) { + std::sort(nearChunks->begin(), nearChunks->end(), dirtyChunkSorter); + } + + for (int i = nearChunks->size() - 1; i >= 0; i--) { + Chunk* chunk = (*nearChunks)[i]; + chunk->rebuild(); + chunk->setClean(); + } + delete nearChunks; + } + + // render the nearest chunks (farther than 1024 units away) + int secondaryRemoved = 0; + + for (int i = count - 1; i >= 0; i--) { + Chunk* chunk = toAdd[i]; + if (chunk != NULL) { + + float ttt = chunkWatch.stopContinue(); + if (ttt >= MaxFrameTime) { + //LOGI("Too much work, I quit2!\n"); + break; + } + + if (!chunk->visible && i != count - 1) { + // escape early if chunks aren't ready + toAdd[i] = NULL; + toAdd[0] = NULL; + break; + } + toAdd[i]->rebuild(); + toAdd[i]->setClean(); + secondaryRemoved++; + } + } + + // compact by removing nulls + int cursor = 0; + int target = 0; + int arraySize = dirtyChunks.size(); + while (cursor != arraySize) { + Chunk* chunk = dirtyChunks[cursor]; + if (chunk != NULL) { + bool remove = false; + for (int i = 0; i < count && !remove; i++) + if (chunk == toAdd[i]) { + remove = true; + } + + if (!remove) { + //if (chunk == toAdd[0] || chunk == toAdd[1] || chunk == toAdd[2]) { + // ; // this chunk was rendered and should be removed + //} else { + if (target != cursor) { + dirtyChunks[target] = chunk; + } + target++; + } + } + cursor++; + } + + // trim + if (cursor > target) + dirtyChunks.erase(dirtyChunks.begin() + target, dirtyChunks.end()); + + return pendingChunkSize == (pendingChunkRemoved + secondaryRemoved); + } +} + +void LevelRenderer::renderHit( Player* player, const HitResult& h, int mode, /*ItemInstance*/void* inventoryItem, float a ) +{ + if (mode == 0) { + if (destroyProgress > 0) { + Tesselator& t = Tesselator::instance; + glEnable2(GL_BLEND); + glBlendFunc2(GL_DST_COLOR, GL_SRC_COLOR); + + textures->loadAndBindTexture("terrain.png"); + glPushMatrix2(); + + int tileId = level->getTile(h.x, h.y, h.z); + Tile* tile = tileId > 0 ? Tile::tiles[tileId] : NULL; + //glDisable2(GL_ALPHA_TEST); + + glPolygonOffset(-3.0f, -3.0f); + glEnable2(GL_POLYGON_OFFSET_FILL); + t.begin(); + t.color(1.0f, 1.0f, 1.0f, 0.5f); + t.noColor(); + float xo = player->xOld + (player->x - player->xOld) * a; + float yo = player->yOld + (player->y - player->yOld) * a; + float zo = player->zOld + (player->z - player->zOld) * a; + + t.offset(-xo, -yo, -zo); + //t.noColor(); + + if (tile == NULL) tile = Tile::rock; + const int progress = (int) (destroyProgress * 10); + tileRenderer->tesselateInWorld(tile, h.x, h.y, h.z, 15 * 16 + progress); + + t.draw(); + t.offset(0, 0, 0); + glPolygonOffset(0.0f, 0.0f); + glDisable2(GL_POLYGON_OFFSET_FILL); + //glDisable2(GL_ALPHA_TEST); + glDisable2(GL_BLEND); + + glDepthMask(true); + glPopMatrix2(); + } + } + //else if (inventoryItem != NULL) { + // glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // float br = ((float) (util.Mth::sin(System.currentTimeMillis() / 100.0f)) * 0.2f + 0.8f); + // glColor4f2(br, br, br, ((float) (util.Mth::sin(System.currentTimeMillis() / 200.0f)) * 0.2f + 0.5f)); + + // int id = textures.loadTexture("terrain.png"); + // glBindTexture2(GL_TEXTURE_2D, id); + // int x = h.x; + // int y = h.y; + // int z = h.z; + // if (h.f == 0) y--; + // if (h.f == 1) y++; + // if (h.f == 2) z--; + // if (h.f == 3) z++; + // if (h.f == 4) x--; + // if (h.f == 5) x++; + // /* + // * t.begin(); t.noColor(); Tile.tiles[tileType].tesselate(level, x, + // * y, z, t); t.end(); + // */ + // } +} + +void LevelRenderer::renderHitOutline( Player* player, const HitResult& h, int mode, /*ItemInstance*/void* inventoryItem, float a ) +{ + if (mode == 0 && h.type == TILE) { + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glColor4f2(0, 0, 0, 0.4f); + glLineWidth(1.0f); + glDisable2(GL_TEXTURE_2D); + glDepthMask(false); + float ss = 0.002f; + int tileId = level->getTile(h.x, h.y, h.z); + + if (tileId > 0) { + Tile::tiles[tileId]->updateShape(level, h.x, h.y, h.z); + float xo = player->xOld + (player->x - player->xOld) * a; + float yo = player->yOld + (player->y - player->yOld) * a; + float zo = player->zOld + (player->z - player->zOld) * a; + render(Tile::tiles[tileId]->getTileAABB(level, h.x, h.y, h.z).grow(ss, ss, ss).cloneMove(-xo, -yo, -zo)); + } + glDepthMask(true); + glEnable2(GL_TEXTURE_2D); + glDisable2(GL_BLEND); + } +} + +void LevelRenderer::setDirty( int x0, int y0, int z0, int x1, int y1, int z1 ) +{ + int _x0 = Mth::intFloorDiv(x0, CHUNK_SIZE); + int _y0 = Mth::intFloorDiv(y0, CHUNK_SIZE); + int _z0 = Mth::intFloorDiv(z0, CHUNK_SIZE); + int _x1 = Mth::intFloorDiv(x1, CHUNK_SIZE); + int _y1 = Mth::intFloorDiv(y1, CHUNK_SIZE); + int _z1 = Mth::intFloorDiv(z1, CHUNK_SIZE); + + for (int x = _x0; x <= _x1; x++) { + int xx = x % xChunks; + if (xx < 0) xx += xChunks; + for (int y = _y0; y <= _y1; y++) { + int yy = y % yChunks; + if (yy < 0) yy += yChunks; + for (int z = _z0; z <= _z1; z++) { + int zz = z % zChunks; + if (zz < 0) zz += zChunks; + + int p = ((zz) * yChunks + (yy)) * xChunks + (xx); + Chunk* chunk = chunks[p]; + if (!chunk->isDirty()) { + dirtyChunks.push_back(chunk); + chunk->setDirty(); + } + } + } + } +} + +void LevelRenderer::tileChanged( int x, int y, int z) +{ + setDirty(x - 1, y - 1, z - 1, x + 1, y + 1, z + 1); +} + + +void LevelRenderer::setTilesDirty( int x0, int y0, int z0, int x1, int y1, int z1 ) +{ + setDirty(x0 - 1, y0 - 1, z0 - 1, x1 + 1, y1 + 1, z1 + 1); +} + + +void LevelRenderer::cull( Culler* culler, float a ) +{ + for (int i = 0; i < chunksLength; i++) { + if (!chunks[i]->isEmpty()) { + if (!chunks[i]->visible || ((i + cullStep) & 15) == 0) { + chunks[i]->cull(culler); + } + } + } + cullStep++; +} + +void LevelRenderer::skyColorChanged() +{ + for (int i = 0; i < chunksLength; i++) { + if (chunks[i]->skyLit) { + if (!chunks[i]->isDirty()) { + dirtyChunks.push_back(chunks[i]); + chunks[i]->setDirty(); + } + } + } +} + +bool entityRenderPredicate(const Entity* a, const Entity* b) { + return a->entityRendererId < b->entityRendererId; +} + +void LevelRenderer::renderEntities(Vec3 cam, Culler* culler, float a) { + if (noEntityRenderFrames > 0) { + noEntityRenderFrames--; + return; + } + + TIMER_PUSH("prepare"); + TileEntityRenderDispatcher::getInstance()->prepare(level, textures, mc->font, mc->cameraTargetPlayer, a); + EntityRenderDispatcher::getInstance()->prepare(level, mc->font, mc->cameraTargetPlayer, &mc->options, a); + + totalEntities = 0; + renderedEntities = 0; + culledEntities = 0; + + Entity* player = mc->cameraTargetPlayer; + EntityRenderDispatcher::xOff = TileEntityRenderDispatcher::xOff = (player->xOld + (player->x - player->xOld) * a); + EntityRenderDispatcher::yOff = TileEntityRenderDispatcher::yOff = (player->yOld + (player->y - player->yOld) * a); + EntityRenderDispatcher::zOff = TileEntityRenderDispatcher::zOff = (player->zOld + (player->z - player->zOld) * a); + + glEnableClientState2(GL_VERTEX_ARRAY); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + + TIMER_POP_PUSH("entities"); + const EntityList& entities = level->getAllEntities(); + totalEntities = entities.size(); + if (totalEntities > 0) { + Entity** toRender = new Entity*[totalEntities]; + for (int i = 0; i < totalEntities; i++) { + Entity* entity = entities[i]; + + bool thirdPerson = mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW); + + if (entity->shouldRender(cam) && culler->isVisible(entity->bb)) + { + if (entity == mc->cameraTargetPlayer && thirdPerson == 0 && mc->cameraTargetPlayer->isPlayer() && !((Player*)mc->cameraTargetPlayer)->isSleeping()) continue; + if (entity == mc->cameraTargetPlayer && !thirdPerson) + continue; + if (!level->hasChunkAt(Mth::floor(entity->x), Mth::floor(entity->y), Mth::floor(entity->z))) + continue; + + toRender[renderedEntities++] = entity; + //EntityRenderDispatcher::getInstance()->render(entity, a); + } + } + + if (renderedEntities > 0) { + std::sort(&toRender[0], &toRender[renderedEntities], entityRenderPredicate); + for (int i = 0; i < renderedEntities; ++i) { + EntityRenderDispatcher* disp = EntityRenderDispatcher::getInstance(); + disp->render(toRender[i], a); + } + } + + delete[] toRender; + } + + TIMER_POP_PUSH("tileentities"); + for (unsigned int i = 0; i < level->tileEntities.size(); i++) { + TileEntityRenderDispatcher::getInstance()->render(level->tileEntities[i], a); + } + + glDisableClientState2(GL_VERTEX_ARRAY); + glDisableClientState2(GL_TEXTURE_COORD_ARRAY); + + TIMER_POP(); +} + +std::string LevelRenderer::gatherStats1() { + std::stringstream ss; + ss << "C: " << renderedChunks << "/" << totalChunks << ". F: " << offscreenChunks << ", O: " << occludedChunks << ", E: " << emptyChunks << "\n"; + return ss.str(); +} + +// +// /*public*/ std::string gatherStats2() { +// return "E: " + renderedEntities + "/" + totalEntities + ". B: " + culledEntities + ", I: " + ((totalEntities - culledEntities) - renderedEntities); +// } +// +// int[] toRender = new int[50000]; +// IntBuffer resultBuffer = MemoryTracker.createIntBuffer(64); + +void LevelRenderer::renderSky(float alpha) { + if (mc->level->dimension->foggy) return; + + glDisable2(GL_TEXTURE_2D); + Vec3 sc = level->getSkyColor(mc->cameraTargetPlayer, alpha); + float sr = (float) sc.x; + float sg = (float) sc.y; + float sb = (float) sc.z;// + 0.5f; + + if (mc->options.getBooleanValue(OPTIONS_ANAGLYPH_3D)) { + float srr = (sr * 30.0f + sg * 59.0f + sb * 11.0f) / 100.0f; + float sgg = (sr * 30.0f + sg * 70.0f) / (100.0f); + float sbb = (sr * 30.0f + sb * 70.0f) / (100.0f); + + sr = srr; + sg = sgg; + sb = sbb; + } + glColor4f2(sr, sg, Mth::Min(1.0f, sb), 1); + + //Tesselator& t = Tesselator::instance; + + glEnable2(GL_FOG); + glColor4f2(sr, sg, sb, 1.0f); + +#ifdef OPENGL_ES + drawArrayVT(skyBuffer, skyVertexCount); +#endif + glEnable2(GL_TEXTURE_2D); +} + +void LevelRenderer::renderClouds( float alpha ) { + //if (!mc->level->dimension->isNaturalDimension()) return; + glEnable2(GL_TEXTURE_2D); + glDisable(GL_CULL_FACE); + float yOffs = (float) (mc->player->yOld + (mc->player->y - mc->player->yOld) * alpha); + int s = 32; + int d = 256 / s; + Tesselator& t = Tesselator::instance; + + //glBindTexture(GL_TEXTURE_2D, texturesloadTexture("/environment/clouds.png")); + textures->loadAndBindTexture("environment/clouds.png"); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Vec3 cc = level->getCloudColor(alpha); + float cr = (float) cc.x; + float cg = (float) cc.y; + float cb = (float) cc.z; + + float scale = 1 / 2048.0f; + + float time = (ticks + alpha); + float xo = mc->player->xo + (mc->player->x - mc->player->xo) * alpha + time * 0.03f; + float zo = mc->player->zo + (mc->player->z - mc->player->zo) * alpha; + int xOffs = Mth::floor(xo / 2048); + int zOffs = Mth::floor(zo / 2048); + xo -= xOffs * 2048; + zo -= zOffs * 2048; + + float yy = /*level.dimension.getCloudHeight()*/ 128 - yOffs + 0.33f;//mc->player->y + 1; + float uo = (float) (xo * scale); + float vo = (float) (zo * scale); + t.begin(); + + t.color(cr, cg, cb, 0.8f); + for (int xx = -s * d; xx < +s * d; xx += s) { + for (int zz = -s * d; zz < +s * d; zz += s) { + t.vertexUV((float)xx, yy, (float)zz + s, xx * scale + uo, (zz + s) * scale + vo); + t.vertexUV((float)xx + s, yy, (float)zz + s, (xx + s) * scale + uo, (zz + s) * scale + vo); + t.vertexUV((float)xx + s, yy, (float)zz, (xx + s) * scale + uo, zz * scale + vo); + t.vertexUV((float)xx, yy, (float)zz, xx * scale + uo, zz * scale + vo); + } + } + t.endOverrideAndDraw(); + glColor4f(1, 1, 1, 1.0f); + glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); +} + +void LevelRenderer::playSound(const std::string& name, float x, float y, float z, float volume, float pitch) { + // @todo: deny sounds here if sound is off (rather than waiting 'til SoundEngine) + float dd = 16; + + if (volume > 1) dd *= volume; + if (mc->cameraTargetPlayer->distanceToSqr(x, y, z) < dd * dd) { + mc->soundEngine->play(name, x, y, z, volume, pitch); + } +} + +void LevelRenderer::addParticle(const std::string& name, float x, float y, float z, float xa, float ya, float za, int data) { + + float xd = mc->cameraTargetPlayer->x - x; + float yd = mc->cameraTargetPlayer->y - y; + float zd = mc->cameraTargetPlayer->z - z; + float distanceSquared = xd * xd + yd * yd + zd * zd; + + //Particle* p = NULL; + //if (name == "hugeexplosion") p = new HugeExplosionSeedParticle(level, x, y, z, xa, ya, za); + //else if (name == "largeexplode") p = new HugeExplosionParticle(textures, level, x, y, z, xa, ya, za); + + //if (p) { + // if (distanceSquared < 32 * 32) { + // mc->particleEngine->add(p); + // } else { delete p; } + // return; + //} + + const float particleDistance = 16; + if (distanceSquared > particleDistance * particleDistance) return; + + //static Stopwatch sw; + //sw.start(); + + if (name == "bubble") mc->particleEngine->add(new BubbleParticle(level, x, y, z, xa, ya, za)); + else if (name == "crit") mc->particleEngine->add(new CritParticle2(level, x, y, z, xa, ya, za)); + else if (name == "smoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za)); + //else if (name == "note") mc->particleEngine->add(new NoteParticle(level, x, y, z, xa, ya, za)); + else if (name == "explode") mc->particleEngine->add(new ExplodeParticle(level, x, y, z, xa, ya, za)); + else if (name == "flame") mc->particleEngine->add(new FlameParticle(level, x, y, z, xa, ya, za)); + else if (name == "lava") mc->particleEngine->add(new LavaParticle(level, x, y, z)); + //else if (name == "splash") mc->particleEngine->add(new SplashParticle(level, x, y, z, xa, ya, za)); + else if (name == "largesmoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f)); + else if (name == "reddust") mc->particleEngine->add(new RedDustParticle(level, x, y, z, xa, ya, za)); + else if (name == "iconcrack") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data])); + else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); + //else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); + //else if (name == "slime") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::slimeBall)); + //else if (name == "heart") mc->particleEngine->add(new HeartParticle(level, x, y, z, xa, ya, za)); + + //sw.stop(); + //sw.printEvery(50, "add-particle-string"); +} + +/* +void LevelRenderer::addParticle(ParticleType::Id name, float x, float y, float z, float xa, float ya, float za, int data) { + float xd = mc->cameraTargetPlayer->x - x; + float yd = mc->cameraTargetPlayer->y - y; + float zd = mc->cameraTargetPlayer->z - z; + + const float particleDistance = 16; + if (xd * xd + yd * yd + zd * zd > particleDistance * particleDistance) return; + + //static Stopwatch sw; + //sw.start(); + + //Particle* p = NULL; + + if (name == ParticleType::bubble) mc->particleEngine->add( new BubbleParticle(level, x, y, z, xa, ya, za) ); + else if (name == ParticleType::crit) mc->particleEngine->add(new CritParticle2(level, x, y, z, xa, ya, za) ); + else if (name == ParticleType::smoke) mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za) ); + else if (name == ParticleType::explode) mc->particleEngine->add( new ExplodeParticle(level, x, y, z, xa, ya, za) ); + else if (name == ParticleType::flame) mc->particleEngine->add( new FlameParticle(level, x, y, z, xa, ya, za) ); + else if (name == ParticleType::lava) mc->particleEngine->add( new LavaParticle(level, x, y, z) ); + else if (name == ParticleType::largesmoke) mc->particleEngine->add( new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f) ); + else if (name == ParticleType::reddust) mc->particleEngine->add( new RedDustParticle(level, x, y, z, xa, ya, za) ); + else if (name == ParticleType::iconcrack) mc->particleEngine->add( new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data]) ); + + //switch (name) { + // case ParticleType::bubble: p = new BubbleParticle(level, x, y, z, xa, ya, za); break; + // case ParticleType::crit: p = new CritParticle2(level, x, y, z, xa, ya, za); break; + // case ParticleType::smoke: p = new SmokeParticle(level, x, y, z, xa, ya, za); break; + // //case ParticleType::note: p = new NoteParticle(level, x, y, z, xa, ya, za); break; + // case ParticleType::explode: p = new ExplodeParticle(level, x, y, z, xa, ya, za); break; + // case ParticleType::flame: p = new FlameParticle(level, x, y, z, xa, ya, za); break; + // case ParticleType::lava: p = new LavaParticle(level, x, y, z); break; + // //case ParticleType::splash: p = new SplashParticle(level, x, y, z, xa, ya, za); break; + // case ParticleType::largesmoke: p = new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f); break; + // case ParticleType::reddust: p = new RedDustParticle(level, x, y, z, xa, ya, za); break; + // case ParticleType::iconcrack: p = new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data]); break; + // //case ParticleType::snowballpoof: p = new BreakingItemParticle(level, x, y, z, Item::snowBall); break; + // //case ParticleType::slime: p = new BreakingItemParticle(level, x, y, z, Item::slimeBall); break; + // //case ParticleType::heart: p = new HeartParticle(level, x, y, z, xa, ya, za); break; + // default: + // LOGW("Couldn't find particle of type: %d\n", name); + // break; + //} + //if (p) { + // mc->particleEngine->add(p); + //} + + //sw.stop(); + //sw.printEvery(50, "add-particle-enum"); +} +*/ + +void LevelRenderer::renderHitSelect( Player* player, const HitResult& h, int mode, /*ItemInstance*/void* inventoryItem, float a ) +{ + //if (h.type == TILE) LOGI("type: %s @ (%d, %d, %d)\n", Tile::tiles[level->getTile(h.x, h.y, h.z)]->getDescriptionId().c_str(), h.x, h.y, h.z); + + if (mode == 0) { + + Tesselator& t = Tesselator::instance; + glEnable2(GL_BLEND); + glDisable2(GL_TEXTURE_2D); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE); + glBlendFunc2(GL_DST_COLOR, GL_SRC_COLOR); + glEnable2(GL_DEPTH_TEST); + + textures->loadAndBindTexture("terrain.png"); + + int tileId = level->getTile(h.x, h.y, h.z); + Tile* tile = tileId > 0 ? Tile::tiles[tileId] : NULL; + glDisable2(GL_ALPHA_TEST); + + //LOGI("block: %d - %d (%s)\n", tileId, level->getData(h.x, h.y, h.z), tile==NULL?"null" : tile->getDescriptionId().c_str() ); + + const float br = 0.65f; + glColor4f2(br * 1.0f, br * 1.0f, br * 1.0f, br * 1.0f); + glPushMatrix2(); + + //glPolygonOffset(-.3f, -.3f); + glPolygonOffset(-1.f, -1.f); //Implementation dependent units + glEnable2(GL_POLYGON_OFFSET_FILL); + float xo = player->xOld + (player->x - player->xOld) * a; + float yo = player->yOld + (player->y - player->yOld) * a; + float zo = player->zOld + (player->z - player->zOld) * a; + + t.begin(); + t.offset(-xo, -yo, -zo); + t.noColor(); + + if (tile == NULL) tile = Tile::rock; + tileRenderer->tesselateInWorld(tile, h.x, h.y, h.z); + + t.draw(); + t.offset(0, 0, 0); + glPolygonOffset(0.0f, 0.0f); + + glDisable2(GL_POLYGON_OFFSET_FILL); + glEnable2(GL_TEXTURE_2D); + + glDepthMask(true); + glPopMatrix2(); + + glEnable2(GL_ALPHA_TEST); + glDisable2(GL_BLEND); + } +} + +void LevelRenderer::onGraphicsReset() +{ + generateSky(); + + // Get new buffers +#ifdef OPENGL_ES + glGenBuffers2(numListsOrBuffers, chunkBuffers); +#else + chunkLists = glGenLists(numListsOrBuffers); +#endif + + // Rebuild + allChanged(); +} + +void LevelRenderer::entityAdded( Entity* entity ) +{ + if (!entity->isPlayer()) + return; + + // Hack to (hopefully) get the players to show + EntityRenderDispatcher::getInstance()->onGraphicsReset(); +} + +int _t_keepPic = -1; + +void LevelRenderer::takePicture( TripodCamera* cam, Entity* entity ) +{ + // Push old values + Mob* oldCameraEntity = mc->cameraTargetPlayer; + bool hideGui = mc->options.getBooleanValue(OPTIONS_HIDEGUI); + bool thirdPerson = mc->options.getBooleanValue(OPTIONS_THIRD_PERSON_VIEW); + + // @huge @attn: This is highly illegal, super temp! + mc->cameraTargetPlayer = (Mob*)cam; + mc->options.set(OPTIONS_HIDEGUI, true); + mc->options.set(OPTIONS_THIRD_PERSON_VIEW, false); + + mc->gameRenderer->renderLevel(0); + + // Pop values back + mc->cameraTargetPlayer = oldCameraEntity; + mc->options.set(OPTIONS_HIDEGUI, hideGui); + mc->options.set(OPTIONS_THIRD_PERSON_VIEW, thirdPerson); + + _t_keepPic = -1; + + // Save image + static char filename[256]; + sprintf(filename, "%s/games/com.mojang/img_%.4d.jpg", mc->externalStoragePath.c_str(), getTimeMs()); + + mc->platform()->saveScreenshot(filename, mc->width, mc->height); +} + +void LevelRenderer::levelEvent(Player* player, int type, int x, int y, int z, int data) { + switch (type) { + case LevelEvent::SOUND_OPEN_DOOR: + if (Mth::random() < 0.5f) { + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, "random.door_open", 1, level->random.nextFloat() * 0.1f + 0.9f); + } else { + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, "random.door_close", 1, level->random.nextFloat() * 0.1f + 0.9f); + } + break; + } +} diff --git a/src/client/renderer/LevelRenderer.h b/src/client/renderer/LevelRenderer.hpp similarity index 96% rename from src/client/renderer/LevelRenderer.h rename to src/client/renderer/LevelRenderer.hpp index d646ef2..7bd5374 100755 --- a/src/client/renderer/LevelRenderer.h +++ b/src/client/renderer/LevelRenderer.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.renderer; -#include "../../world/level/LevelListener.h" -#include "../../world/phys/Vec3.h" -#include "RenderList.h" -#include "gles.h" +#include "world/level/LevelListener.hpp" +#include "world/phys/Vec3.hpp" +#include "RenderList.hpp" +#include "gles.hpp" #include class MinecraftClient; diff --git a/src/client/renderer/RenderChunk.cpp b/src/client/renderer/RenderChunk.cpp index a676ea8..60b142c 100755 --- a/src/client/renderer/RenderChunk.cpp +++ b/src/client/renderer/RenderChunk.cpp @@ -1,17 +1,17 @@ -#include "RenderChunk.h" - -int RenderChunk::runningId = 0; - -RenderChunk::RenderChunk() : - vboId(-1), - vertexCount(0) -{ - id = ++runningId; -} - -RenderChunk::RenderChunk( GLuint vboId_, int vertexCount_ ) -: vboId(vboId_), - vertexCount(vertexCount_) -{ - id = ++runningId; -} +#include "RenderChunk.hpp" + +int RenderChunk::runningId = 0; + +RenderChunk::RenderChunk() : + vboId(-1), + vertexCount(0) +{ + id = ++runningId; +} + +RenderChunk::RenderChunk( GLuint vboId_, int vertexCount_ ) +: vboId(vboId_), + vertexCount(vertexCount_) +{ + id = ++runningId; +} diff --git a/src/client/renderer/RenderChunk.h b/src/client/renderer/RenderChunk.hpp similarity index 82% rename from src/client/renderer/RenderChunk.h rename to src/client/renderer/RenderChunk.hpp index adc452f..a96e522 100755 --- a/src/client/renderer/RenderChunk.h +++ b/src/client/renderer/RenderChunk.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer; -#include "gles.h" -#include "../../world/phys/Vec3.h" +#include "gles.hpp" +#include "world/phys/Vec3.hpp" class RenderChunk { diff --git a/src/client/renderer/RenderChunkHandler.h b/src/client/renderer/RenderChunkHandler.hpp similarity index 90% rename from src/client/renderer/RenderChunkHandler.h rename to src/client/renderer/RenderChunkHandler.hpp index 5c785bb..fe6a096 100755 --- a/src/client/renderer/RenderChunkHandler.h +++ b/src/client/renderer/RenderChunkHandler.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "RenderChunk.h" +#include "RenderChunk.hpp" typedef std::vector ChunkList; diff --git a/src/client/renderer/RenderList.cpp b/src/client/renderer/RenderList.cpp index 1dfa95f..833c24f 100755 --- a/src/client/renderer/RenderList.cpp +++ b/src/client/renderer/RenderList.cpp @@ -1,96 +1,96 @@ -#include "RenderList.h" - -#include "gles.h" -#include "RenderChunk.h" -#include "Tesselator.h" - - -RenderList::RenderList() - : inited(false), - rendered(false) -{ - lists = new int[MAX_NUM_OBJECTS]; - rlists = new RenderChunk[MAX_NUM_OBJECTS]; - - for (int i = 0; i < MAX_NUM_OBJECTS; ++i) - rlists[i].vboId = -1; -} - -RenderList::~RenderList() { - delete[] lists; - delete[] rlists; -} - -void RenderList::init(float xOff, float yOff, float zOff) { - inited = true; - listIndex = 0; - - this->xOff = (float) xOff; - this->yOff = (float) yOff; - this->zOff = (float) zOff; -} - -void RenderList::add(int list) { - lists[listIndex] = list; - if (listIndex == MAX_NUM_OBJECTS) /*lists.remaining() == 0)*/ render(); -} - -void RenderList::addR(const RenderChunk& chunk) { - rlists[listIndex] = chunk; -} - -void RenderList::render() { - - if (!inited) return; - if (!rendered) { - bufferLimit = listIndex; - listIndex = 0; - rendered = true; - } - if (listIndex < bufferLimit) { - glPushMatrix2(); - glTranslatef2(-xOff, -yOff, -zOff); - - #ifndef USE_VBO - glCallLists(bufferLimit, GL_UNSIGNED_INT, lists); - #else - renderChunks(); - #endif/*!USE_VBO*/ - - glPopMatrix2(); - } -} - -void RenderList::renderChunks() { - //glDisableClientState2(GL_NORMAL_ARRAY); - glEnableClientState2(GL_VERTEX_ARRAY); - glEnableClientState2(GL_COLOR_ARRAY); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - - const int Stride = VertexSizeBytes; - - for (int i = 0; i < bufferLimit; ++i) { - RenderChunk& rc = rlists[i]; - - glPushMatrix2(); - glTranslatef2(rc.pos.x, rc.pos.y, rc.pos.z); - glBindBuffer2(GL_ARRAY_BUFFER, rc.vboId); - - glVertexPointer2 (3, GL_FLOAT, Stride, 0); - glTexCoordPointer2 (2, GL_FLOAT, Stride, (GLvoid*) (3 * 4)); - glColorPointer2 (4, GL_UNSIGNED_BYTE, Stride, (GLvoid*) (5 * 4)); - - glDrawArrays2(GL_TRIANGLES, 0, rc.vertexCount); - - glPopMatrix2(); - } - - glDisableClientState2(GL_VERTEX_ARRAY); - glDisableClientState2(GL_COLOR_ARRAY); - glDisableClientState2(GL_TEXTURE_COORD_ARRAY); -} - -void RenderList::clear() { - inited = false; - rendered = false; -} +#include "RenderList.hpp" + +#include "gles.hpp" +#include "RenderChunk.hpp" +#include "Tesselator.hpp" + + +RenderList::RenderList() + : inited(false), + rendered(false) +{ + lists = new int[MAX_NUM_OBJECTS]; + rlists = new RenderChunk[MAX_NUM_OBJECTS]; + + for (int i = 0; i < MAX_NUM_OBJECTS; ++i) + rlists[i].vboId = -1; +} + +RenderList::~RenderList() { + delete[] lists; + delete[] rlists; +} + +void RenderList::init(float xOff, float yOff, float zOff) { + inited = true; + listIndex = 0; + + this->xOff = (float) xOff; + this->yOff = (float) yOff; + this->zOff = (float) zOff; +} + +void RenderList::add(int list) { + lists[listIndex] = list; + if (listIndex == MAX_NUM_OBJECTS) /*lists.remaining() == 0)*/ render(); +} + +void RenderList::addR(const RenderChunk& chunk) { + rlists[listIndex] = chunk; +} + +void RenderList::render() { + + if (!inited) return; + if (!rendered) { + bufferLimit = listIndex; + listIndex = 0; + rendered = true; + } + if (listIndex < bufferLimit) { + glPushMatrix2(); + glTranslatef2(-xOff, -yOff, -zOff); + + #ifndef USE_VBO + glCallLists(bufferLimit, GL_UNSIGNED_INT, lists); + #else + renderChunks(); + #endif/*!USE_VBO*/ + + glPopMatrix2(); + } +} + +void RenderList::renderChunks() { + //glDisableClientState2(GL_NORMAL_ARRAY); + glEnableClientState2(GL_VERTEX_ARRAY); + glEnableClientState2(GL_COLOR_ARRAY); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + + const int Stride = VertexSizeBytes; + + for (int i = 0; i < bufferLimit; ++i) { + RenderChunk& rc = rlists[i]; + + glPushMatrix2(); + glTranslatef2(rc.pos.x, rc.pos.y, rc.pos.z); + glBindBuffer2(GL_ARRAY_BUFFER, rc.vboId); + + glVertexPointer2 (3, GL_FLOAT, Stride, 0); + glTexCoordPointer2 (2, GL_FLOAT, Stride, (GLvoid*) (3 * 4)); + glColorPointer2 (4, GL_UNSIGNED_BYTE, Stride, (GLvoid*) (5 * 4)); + + glDrawArrays2(GL_TRIANGLES, 0, rc.vertexCount); + + glPopMatrix2(); + } + + glDisableClientState2(GL_VERTEX_ARRAY); + glDisableClientState2(GL_COLOR_ARRAY); + glDisableClientState2(GL_TEXTURE_COORD_ARRAY); +} + +void RenderList::clear() { + inited = false; + rendered = false; +} diff --git a/src/client/renderer/RenderList.h b/src/client/renderer/RenderList.hpp similarity index 100% rename from src/client/renderer/RenderList.h rename to src/client/renderer/RenderList.hpp diff --git a/src/client/renderer/Tesselator.cpp b/src/client/renderer/Tesselator.cpp index dedaca3..c07e7cf 100755 --- a/src/client/renderer/Tesselator.cpp +++ b/src/client/renderer/Tesselator.cpp @@ -1,437 +1,437 @@ -#include "Tesselator.h" -#include -#include -#include - -Tesselator Tesselator::instance(sizeof(GLfloat) * MAX_FLOATS); // max size in bytes - -const int VertexSizeBytes = sizeof(VERTEX); - -Tesselator::Tesselator( int size ) -: size(size), - vertices(0), - u(0), v(0), - _color(0), - hasColor(false), - hasTexture(false), - hasNormal(false), - p(0), - count(0), - _noColor(false), - mode(0), - xo(0), yo(0), zo(0), - _normal(0), - _sx(1), _sy(1), - - tesselating(false), - vboId(-1), - vboCounts(128), - totalSize(0), - accessMode(ACCESS_STATIC), - maxVertices(size / sizeof(VERTEX)), - _voidBeginEnd(false) -{ - vboIds = new GLuint[vboCounts]; - - _varray = new VERTEX[maxVertices]; - - char* a = (char*)&_varray[0]; - char* b = (char*)&_varray[1]; - LOGI("Vsize: %lu, %d\n", sizeof(VERTEX), (b-a)); -} - -Tesselator::~Tesselator() -{ - delete[] vboIds; - delete[] _varray; -} - -void Tesselator::init() -{ -#ifndef STANDALONE_SERVER - glGenBuffers2(vboCounts, vboIds); -#endif -} - -void Tesselator::clear() -{ - accessMode = ACCESS_STATIC; - vertices = 0; - count = 0; - p = 0; - _voidBeginEnd = false; -} - -int Tesselator::getVboCount() { - return vboCounts; -} - -RenderChunk Tesselator::end( bool useMine, int bufferId ) -{ -#ifndef STANDALONE_SERVER - //if (!tesselating) throw /*new*/ IllegalStateException("Not tesselating!"); - if (!tesselating) - LOGI("not tesselating!\n"); - - if (!tesselating || _voidBeginEnd) return RenderChunk(); - - tesselating = false; - const int o_vertices = vertices; - - if (vertices > 0) { - if (p <= 0 || p > maxVertices) { clear(); return RenderChunk(); } - int bytes = p * sizeof(VERTEX); - if (bytes <= 0) return RenderChunk(); - if (++vboId >= vboCounts) - vboId = 0; - -#ifdef USE_VBO - // Using VBO, use default buffer id only if we don't send in any - if (!useMine) { - bufferId = vboIds[vboId]; - } -#else - // Not using VBO - always use the next buffer object - bufferId = vboIds[vboId]; -#endif - int access = GL_STATIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; - glBindBuffer2(GL_ARRAY_BUFFER, bufferId); - glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW - - totalSize += bytes; - -#ifndef USE_VBO - // 0 1 2 3 4 5 6 7 - // x y z u v c - if (hasTexture) { - glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) (3 * 4)); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - } - if (hasColor) { - glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) (5 * 4)); - glEnableClientState2(GL_COLOR_ARRAY); - } - if (hasNormal) { - glNormalPointer(GL_BYTE, VertexSizeBytes, (GLvoid*) (6 * 4)); - glEnableClientState2(GL_NORMAL_ARRAY); - } - glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, 0); - glEnableClientState2(GL_VERTEX_ARRAY); - - if (mode == GL_QUADS) { - glDrawArrays2(GL_TRIANGLES, 0, vertices); - } else { - glDrawArrays2(mode, 0, vertices); - } - //printf("drawing %d tris, size %d (%d,%d,%d)\n", vertices, p, hasTexture, hasColor, hasNormal); - glDisableClientState2(GL_VERTEX_ARRAY); - if (hasTexture) glDisableClientState2(GL_TEXTURE_COORD_ARRAY); - if (hasColor) glDisableClientState2(GL_COLOR_ARRAY); - if (hasNormal) glDisableClientState2(GL_NORMAL_ARRAY); -#endif /*!USE_VBO*/ - } - - clear(); - RenderChunk out(bufferId, o_vertices); - //map.insert( std::make_pair(bufferId, out.id) ); - return out; -#else - return RenderChunk(); -#endif - -} - -void Tesselator::begin( int mode ) -{ - if (tesselating || _voidBeginEnd) { - if (tesselating && !_voidBeginEnd) - LOGI("already tesselating!\n"); - return; - } - //if (tesselating) { - // throw /*new*/ IllegalStateException("Already tesselating!"); - //} - tesselating = true; - - clear(); - this->mode = mode; - hasNormal = false; - hasColor = false; - hasTexture = false; - _noColor = false; -} - -void Tesselator::begin() -{ - begin(GL_QUADS); -} - -void Tesselator::tex( float u, float v ) -{ - hasTexture = true; - this->u = u; - this->v = v; -} - -int Tesselator::getColor() { - return _color; -} - -void Tesselator::color( float r, float g, float b ) -{ - color((int) (r * 255), (int) (g * 255), (int) (b * 255)); -} - -void Tesselator::color( float r, float g, float b, float a ) -{ - color((int) (r * 255), (int) (g * 255), (int) (b * 255), (int) (a * 255)); -} - -void Tesselator::color( int r, int g, int b ) -{ - color(r, g, b, 255); -} - -void Tesselator::color( int r, int g, int b, int a ) -{ - if (_noColor) return; - - if (r > 255) r = 255; - if (g > 255) g = 255; - if (b > 255) b = 255; - if (a > 255) a = 255; - if (r < 0) r = 0; - if (g < 0) g = 0; - if (b < 0) b = 0; - if (a < 0) a = 0; - - hasColor = true; - //if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { - if (true) { - _color = (a << 24) | (b << 16) | (g << 8) | (r); - } else { - _color = (r << 24) | (g << 16) | (b << 8) | (a); - } -} - -void Tesselator::color( char r, char g, char b ) -{ - color(r & 0xff, g & 0xff, b & 0xff); -} - -void Tesselator::color( int c ) -{ - int r = ((c >> 16) & 255); - int g = ((c >> 8) & 255); - int b = ((c) & 255); - color(r, g, b); -} - -//@note: doesn't care about endianess -void Tesselator::colorABGR( int c ) -{ - if (_noColor) return; - hasColor = true; - _color = c; -} - -void Tesselator::color( int c, int alpha ) -{ - int r = ((c >> 16) & 255); - int g = ((c >> 8) & 255); - int b = ((c) & 255); - color(r, g, b, alpha); -} - -void Tesselator::vertexUV( float x, float y, float z, float u, float v ) -{ - tex(u, v); - vertex(x, y, z); -} - -void Tesselator::scale2d(float sx, float sy) { - _sx *= sx; - _sy *= sy; -} - -void Tesselator::resetScale() { - _sx = _sy = 1; -} - -void Tesselator::vertex( float x, float y, float z ) -{ -#ifndef STANDALONE_SERVER - count++; - - if (mode == GL_QUADS && (count & 3) == 0) { - for (int i = 0; i < 2; i++) { - - const int offs = 3 - i; - if (p - offs < 0 || p >= maxVertices) { clear(); return; } - VERTEX& src = _varray[p - offs]; - VERTEX& dst = _varray[p]; - - if (hasTexture) { - dst.u = src.u; - dst.v = src.v; - } - if (hasColor) { - dst.color = src.color; - } - //if (hasNormal) { - // dst.normal = src.normal; - //} - - dst.x = src.x; - dst.y = src.y; - dst.z = src.z; - - ++vertices; - ++p; - } - } - - if (p < 0 || p >= maxVertices) { clear(); return; } - VERTEX& vertex = _varray[p]; - - if (hasTexture) { - vertex.u = u; - vertex.v = v; - } - if (hasColor) { - vertex.color = _color; - } - //if (hasNormal) { - // vertex.normal = _normal; - //} - - vertex.x = _sx * (x + xo); - vertex.y = _sy * (y + yo); - vertex.z = z + zo; - - ++p; - ++vertices; - - if ((vertices & 3) == 0 && p >= maxVertices-1) { - for (int i = 0; i < 3; ++i) - printf("Overwriting the vertex buffer! This chunk/entity won't show up\n"); - clear(); - } -#endif -} - -void Tesselator::noColor() -{ - _noColor = true; -} - -void Tesselator::setAccessMode(int mode) -{ - accessMode = mode; -} - -void Tesselator::normal( float x, float y, float z ) -{ - static int _warn_t = 0; - if ((++_warn_t & 32767) == 1) - LOGI("WARNING: Can't use normals (Tesselator::normal)\n"); - return; - - if (!tesselating) printf("But.."); - hasNormal = true; - char xx = (char) (x * 128); - char yy = (char) (y * 127); - char zz = (char) (z * 127); - - _normal = xx | (yy << 8) | (zz << 16); -} - -void Tesselator::offset( float xo, float yo, float zo ) { - this->xo = xo; - this->yo = yo; - this->zo = zo; -} - -void Tesselator::addOffset( float x, float y, float z ) { - xo += x; - yo += y; - zo += z; -} - -void Tesselator::offset( const Vec3& v ) { - xo = v.x; - yo = v.y; - zo = v.z; -} - -void Tesselator::addOffset( const Vec3& v ) { - xo += v.x; - yo += v.y; - zo += v.z; -} - -void Tesselator::draw() -{ -#ifndef STANDALONE_SERVER - if (!tesselating) - LOGI("not (draw) tesselating!\n"); - - if (!tesselating || _voidBeginEnd) - return; - - tesselating = false; - - if (vertices > 0) { - if (p <= 0 || p > maxVertices) { clear(); return; } - int bytes = p * sizeof(VERTEX); - if (bytes <= 0) { clear(); return; } - if (++vboId >= vboCounts) - vboId = 0; - - int bufferId = vboIds[vboId]; - - int access = GL_DYNAMIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; - glBindBuffer2(GL_ARRAY_BUFFER, bufferId); - glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW - - if (hasTexture) { - glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) (3 * 4)); - //glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) &_varray->u); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - } - if (hasColor) { - glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) (5 * 4)); - //glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) &_varray->color); - glEnableClientState2(GL_COLOR_ARRAY); - } - //if (hasNormal) { - // glNormalPointer(GL_BYTE, VertexSizeBytes, (GLvoid*) (6 * 4)); - // glEnableClientState2(GL_NORMAL_ARRAY); - //} - //glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, (GLvoid*)&_varray); - glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, 0); - glEnableClientState2(GL_VERTEX_ARRAY); - - if (mode == GL_QUADS) { - glDrawArrays2(GL_TRIANGLES, 0, vertices); - } else { - glDrawArrays2(mode, 0, vertices); - } - - glDisableClientState2(GL_VERTEX_ARRAY); - if (hasTexture) glDisableClientState2(GL_TEXTURE_COORD_ARRAY); - if (hasColor) glDisableClientState2(GL_COLOR_ARRAY); - //if (hasNormal) glDisableClientState2(GL_NORMAL_ARRAY); - } - - clear(); -#endif -} - -void Tesselator::voidBeginAndEndCalls(bool doVoid) { - _voidBeginEnd = doVoid; -} - -void Tesselator::enableColor() { - _noColor = false; -} +#include "Tesselator.hpp" +#include +#include +#include + +Tesselator Tesselator::instance(sizeof(GLfloat) * MAX_FLOATS); // max size in bytes + +const int VertexSizeBytes = sizeof(VERTEX); + +Tesselator::Tesselator( int size ) +: size(size), + vertices(0), + u(0), v(0), + _color(0), + hasColor(false), + hasTexture(false), + hasNormal(false), + p(0), + count(0), + _noColor(false), + mode(0), + xo(0), yo(0), zo(0), + _normal(0), + _sx(1), _sy(1), + + tesselating(false), + vboId(-1), + vboCounts(128), + totalSize(0), + accessMode(ACCESS_STATIC), + maxVertices(size / sizeof(VERTEX)), + _voidBeginEnd(false) +{ + vboIds = new GLuint[vboCounts]; + + _varray = new VERTEX[maxVertices]; + + char* a = (char*)&_varray[0]; + char* b = (char*)&_varray[1]; + LOGI("Vsize: %lu, %d\n", sizeof(VERTEX), (b-a)); +} + +Tesselator::~Tesselator() +{ + delete[] vboIds; + delete[] _varray; +} + +void Tesselator::init() +{ +#ifndef STANDALONE_SERVER + glGenBuffers2(vboCounts, vboIds); +#endif +} + +void Tesselator::clear() +{ + accessMode = ACCESS_STATIC; + vertices = 0; + count = 0; + p = 0; + _voidBeginEnd = false; +} + +int Tesselator::getVboCount() { + return vboCounts; +} + +RenderChunk Tesselator::end( bool useMine, int bufferId ) +{ +#ifndef STANDALONE_SERVER + //if (!tesselating) throw /*new*/ IllegalStateException("Not tesselating!"); + if (!tesselating) + LOGI("not tesselating!\n"); + + if (!tesselating || _voidBeginEnd) return RenderChunk(); + + tesselating = false; + const int o_vertices = vertices; + + if (vertices > 0) { + if (p <= 0 || p > maxVertices) { clear(); return RenderChunk(); } + int bytes = p * sizeof(VERTEX); + if (bytes <= 0) return RenderChunk(); + if (++vboId >= vboCounts) + vboId = 0; + +#ifdef USE_VBO + // Using VBO, use default buffer id only if we don't send in any + if (!useMine) { + bufferId = vboIds[vboId]; + } +#else + // Not using VBO - always use the next buffer object + bufferId = vboIds[vboId]; +#endif + int access = GL_STATIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + glBindBuffer2(GL_ARRAY_BUFFER, bufferId); + glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW + + totalSize += bytes; + +#ifndef USE_VBO + // 0 1 2 3 4 5 6 7 + // x y z u v c + if (hasTexture) { + glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) (3 * 4)); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + } + if (hasColor) { + glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) (5 * 4)); + glEnableClientState2(GL_COLOR_ARRAY); + } + if (hasNormal) { + glNormalPointer(GL_BYTE, VertexSizeBytes, (GLvoid*) (6 * 4)); + glEnableClientState2(GL_NORMAL_ARRAY); + } + glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, 0); + glEnableClientState2(GL_VERTEX_ARRAY); + + if (mode == GL_QUADS) { + glDrawArrays2(GL_TRIANGLES, 0, vertices); + } else { + glDrawArrays2(mode, 0, vertices); + } + //printf("drawing %d tris, size %d (%d,%d,%d)\n", vertices, p, hasTexture, hasColor, hasNormal); + glDisableClientState2(GL_VERTEX_ARRAY); + if (hasTexture) glDisableClientState2(GL_TEXTURE_COORD_ARRAY); + if (hasColor) glDisableClientState2(GL_COLOR_ARRAY); + if (hasNormal) glDisableClientState2(GL_NORMAL_ARRAY); +#endif /*!USE_VBO*/ + } + + clear(); + RenderChunk out(bufferId, o_vertices); + //map.insert( std::make_pair(bufferId, out.id) ); + return out; +#else + return RenderChunk(); +#endif + +} + +void Tesselator::begin( int mode ) +{ + if (tesselating || _voidBeginEnd) { + if (tesselating && !_voidBeginEnd) + LOGI("already tesselating!\n"); + return; + } + //if (tesselating) { + // throw /*new*/ IllegalStateException("Already tesselating!"); + //} + tesselating = true; + + clear(); + this->mode = mode; + hasNormal = false; + hasColor = false; + hasTexture = false; + _noColor = false; +} + +void Tesselator::begin() +{ + begin(GL_QUADS); +} + +void Tesselator::tex( float u, float v ) +{ + hasTexture = true; + this->u = u; + this->v = v; +} + +int Tesselator::getColor() { + return _color; +} + +void Tesselator::color( float r, float g, float b ) +{ + color((int) (r * 255), (int) (g * 255), (int) (b * 255)); +} + +void Tesselator::color( float r, float g, float b, float a ) +{ + color((int) (r * 255), (int) (g * 255), (int) (b * 255), (int) (a * 255)); +} + +void Tesselator::color( int r, int g, int b ) +{ + color(r, g, b, 255); +} + +void Tesselator::color( int r, int g, int b, int a ) +{ + if (_noColor) return; + + if (r > 255) r = 255; + if (g > 255) g = 255; + if (b > 255) b = 255; + if (a > 255) a = 255; + if (r < 0) r = 0; + if (g < 0) g = 0; + if (b < 0) b = 0; + if (a < 0) a = 0; + + hasColor = true; + //if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { + if (true) { + _color = (a << 24) | (b << 16) | (g << 8) | (r); + } else { + _color = (r << 24) | (g << 16) | (b << 8) | (a); + } +} + +void Tesselator::color( char r, char g, char b ) +{ + color(r & 0xff, g & 0xff, b & 0xff); +} + +void Tesselator::color( int c ) +{ + int r = ((c >> 16) & 255); + int g = ((c >> 8) & 255); + int b = ((c) & 255); + color(r, g, b); +} + +//@note: doesn't care about endianess +void Tesselator::colorABGR( int c ) +{ + if (_noColor) return; + hasColor = true; + _color = c; +} + +void Tesselator::color( int c, int alpha ) +{ + int r = ((c >> 16) & 255); + int g = ((c >> 8) & 255); + int b = ((c) & 255); + color(r, g, b, alpha); +} + +void Tesselator::vertexUV( float x, float y, float z, float u, float v ) +{ + tex(u, v); + vertex(x, y, z); +} + +void Tesselator::scale2d(float sx, float sy) { + _sx *= sx; + _sy *= sy; +} + +void Tesselator::resetScale() { + _sx = _sy = 1; +} + +void Tesselator::vertex( float x, float y, float z ) +{ +#ifndef STANDALONE_SERVER + count++; + + if (mode == GL_QUADS && (count & 3) == 0) { + for (int i = 0; i < 2; i++) { + + const int offs = 3 - i; + if (p - offs < 0 || p >= maxVertices) { clear(); return; } + VERTEX& src = _varray[p - offs]; + VERTEX& dst = _varray[p]; + + if (hasTexture) { + dst.u = src.u; + dst.v = src.v; + } + if (hasColor) { + dst.color = src.color; + } + //if (hasNormal) { + // dst.normal = src.normal; + //} + + dst.x = src.x; + dst.y = src.y; + dst.z = src.z; + + ++vertices; + ++p; + } + } + + if (p < 0 || p >= maxVertices) { clear(); return; } + VERTEX& vertex = _varray[p]; + + if (hasTexture) { + vertex.u = u; + vertex.v = v; + } + if (hasColor) { + vertex.color = _color; + } + //if (hasNormal) { + // vertex.normal = _normal; + //} + + vertex.x = _sx * (x + xo); + vertex.y = _sy * (y + yo); + vertex.z = z + zo; + + ++p; + ++vertices; + + if ((vertices & 3) == 0 && p >= maxVertices-1) { + for (int i = 0; i < 3; ++i) + printf("Overwriting the vertex buffer! This chunk/entity won't show up\n"); + clear(); + } +#endif +} + +void Tesselator::noColor() +{ + _noColor = true; +} + +void Tesselator::setAccessMode(int mode) +{ + accessMode = mode; +} + +void Tesselator::normal( float x, float y, float z ) +{ + static int _warn_t = 0; + if ((++_warn_t & 32767) == 1) + LOGI("WARNING: Can't use normals (Tesselator::normal)\n"); + return; + + if (!tesselating) printf("But.."); + hasNormal = true; + char xx = (char) (x * 128); + char yy = (char) (y * 127); + char zz = (char) (z * 127); + + _normal = xx | (yy << 8) | (zz << 16); +} + +void Tesselator::offset( float xo, float yo, float zo ) { + this->xo = xo; + this->yo = yo; + this->zo = zo; +} + +void Tesselator::addOffset( float x, float y, float z ) { + xo += x; + yo += y; + zo += z; +} + +void Tesselator::offset( const Vec3& v ) { + xo = v.x; + yo = v.y; + zo = v.z; +} + +void Tesselator::addOffset( const Vec3& v ) { + xo += v.x; + yo += v.y; + zo += v.z; +} + +void Tesselator::draw() +{ +#ifndef STANDALONE_SERVER + if (!tesselating) + LOGI("not (draw) tesselating!\n"); + + if (!tesselating || _voidBeginEnd) + return; + + tesselating = false; + + if (vertices > 0) { + if (p <= 0 || p > maxVertices) { clear(); return; } + int bytes = p * sizeof(VERTEX); + if (bytes <= 0) { clear(); return; } + if (++vboId >= vboCounts) + vboId = 0; + + int bufferId = vboIds[vboId]; + + int access = GL_DYNAMIC_DRAW;//(accessMode==ACCESS_DYNAMIC) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW; + glBindBuffer2(GL_ARRAY_BUFFER, bufferId); + glBufferData2(GL_ARRAY_BUFFER, bytes, _varray, access); // GL_STREAM_DRAW + + if (hasTexture) { + glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) (3 * 4)); + //glTexCoordPointer2(2, GL_FLOAT, VertexSizeBytes, (GLvoid*) &_varray->u); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + } + if (hasColor) { + glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) (5 * 4)); + //glColorPointer2(4, GL_UNSIGNED_BYTE, VertexSizeBytes, (GLvoid*) &_varray->color); + glEnableClientState2(GL_COLOR_ARRAY); + } + //if (hasNormal) { + // glNormalPointer(GL_BYTE, VertexSizeBytes, (GLvoid*) (6 * 4)); + // glEnableClientState2(GL_NORMAL_ARRAY); + //} + //glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, (GLvoid*)&_varray); + glVertexPointer2(3, GL_FLOAT, VertexSizeBytes, 0); + glEnableClientState2(GL_VERTEX_ARRAY); + + if (mode == GL_QUADS) { + glDrawArrays2(GL_TRIANGLES, 0, vertices); + } else { + glDrawArrays2(mode, 0, vertices); + } + + glDisableClientState2(GL_VERTEX_ARRAY); + if (hasTexture) glDisableClientState2(GL_TEXTURE_COORD_ARRAY); + if (hasColor) glDisableClientState2(GL_COLOR_ARRAY); + //if (hasNormal) glDisableClientState2(GL_NORMAL_ARRAY); + } + + clear(); +#endif +} + +void Tesselator::voidBeginAndEndCalls(bool doVoid) { + _voidBeginEnd = doVoid; +} + +void Tesselator::enableColor() { + _noColor = false; +} diff --git a/src/client/renderer/Tesselator.h b/src/client/renderer/Tesselator.hpp similarity index 96% rename from src/client/renderer/Tesselator.h rename to src/client/renderer/Tesselator.hpp index d6d3c08..521071e 100755 --- a/src/client/renderer/Tesselator.h +++ b/src/client/renderer/Tesselator.hpp @@ -3,9 +3,9 @@ //package net.minecraft.client.renderer; #include -#include "RenderChunk.h" -#include "gles.h" -#include "VertecDecl.h" +#include "RenderChunk.hpp" +#include "gles.hpp" +#include "VertecDecl.hpp" extern const int VertexSizeBytes; diff --git a/src/client/renderer/TextureData.h b/src/client/renderer/TextureData.hpp similarity index 100% rename from src/client/renderer/TextureData.h rename to src/client/renderer/TextureData.hpp diff --git a/src/client/renderer/Textures.cpp b/src/client/renderer/Textures.cpp index 098fedb..88caf90 100755 --- a/src/client/renderer/Textures.cpp +++ b/src/client/renderer/Textures.cpp @@ -1,347 +1,347 @@ -#include "Textures.h" - -#include "TextureData.h" -#include "ptexture/DynamicTexture.h" -#include "../Options.h" -#include "../../platform/time.h" -#include "../../util/StringUtils.h" - -/*static*/ int Textures::textureChanges = 0; - -Textures::~Textures() { - clear(); - - for (unsigned int i = 0; i < dynamicTextures.size(); ++i) - delete dynamicTextures[i]; -} - -void Textures::clear() { - for (TextureMap::iterator it = idMap.begin(); it != idMap.end(); ++it) { - if (it->second != TEXTURES_INVALID_ID) - glDeleteTextures(1, &it->second); - } - for (TextureImageMap::iterator it = loadedImages.begin(); it != loadedImages.end(); ++it) { - if (!(it->second).memoryHandledExternally) - delete[] (it->second).data; - } - idMap.clear(); - loadedImages.clear(); - - lastBoundTexture = TEXTURES_INVALID_ID; -} - -TextureId Textures::loadAndBindTexture( const std::string& resourceName ) -{ - //static Stopwatch t; - - //t.start(); - TextureId id = loadTexture(resourceName); - //t.stop(); - if (id != TEXTURES_INVALID_ID) - bind(id); - - //t.printEvery(1000); - - return id; -} - -TextureId Textures::loadTexture(const std::string& resourceName, bool inTextureFolder) { - TextureMap::iterator it = idMap.find(resourceName); - if (it != idMap.end()) - return it->second; - - bool isUrl = Util::startsWith(resourceName, "http://") || Util::startsWith(resourceName, "https://"); - TextureData texdata = m_platform.loadTexture(resourceName, isUrl ? false : inTextureFolder); - if (texdata.data) - return assignTexture(resourceName, texdata); - else if (texdata.identifier != TEXTURES_INVALID_ID) { - //LOGI("Adding id: %d for %s\n", texdata.identifier, resourceName.c_str()); - idMap.insert(std::make_pair(resourceName, texdata.identifier)); - } - else { - idMap.insert(std::make_pair(resourceName, TEXTURES_INVALID_ID)); - //loadedImages.insert(std::make_pair(InvalidId, texdata)); - } - return TEXTURES_INVALID_ID; -} - -TextureId Textures::assignTexture( const std::string& resourceName, const TextureData& img ) -{ - TextureId id; - glGenTextures(1, &id); - - bind(id); - -#ifdef TEXTURES_MIPMAP - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); -#else - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); -#endif - - if (blur) { - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - - if (clamp) { - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - - switch (img.format) - { - case TEXF_COMPRESSED_PVRTC_4444: - case TEXF_COMPRESSED_PVRTC_565: - case TEXF_COMPRESSED_PVRTC_5551: - { -#if defined(__APPLE__) - int fmt = img.transparent? GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, img.w, img.h, 0, img.numBytes, img.data); -#endif - break; - } - - default: - const GLint mode = img.transparent? GL_RGBA : GL_RGB; - - if (img.format == TEXF_UNCOMPRESSED_565) { - glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_5_6_5, img.data); - } - else if (img.format == TEXF_UNCOMPRESSED_4444) { - glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_4_4_4_4, img.data); - } - else if (img.format == TEXF_UNCOMPRESSED_5551) { - glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_5_5_5_1, img.data); - } - else { - glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_BYTE, img.data); - } - break; - } - - //LOGI("Adding id: %d to map\n", id); - idMap.insert(std::make_pair(resourceName, id)); - loadedImages.insert(std::make_pair(id, img)); - - return id; -} - -const TextureData* Textures::getTemporaryTextureData( TextureId id ) -{ - TextureImageMap::iterator it = loadedImages.find(id); - if (it == loadedImages.end()) - return NULL; - - return &it->second; -} - -void Textures::tick(bool uploadToGraphicsCard) -{ - for (unsigned int i = 0; i < dynamicTextures.size(); ++i ) { - DynamicTexture* tex = dynamicTextures[i]; - tex->tick(); - - if (uploadToGraphicsCard) { - tex->bindTexture(this); - for (int xx = 0; xx < tex->replicate; xx++) - for (int yy = 0; yy < tex->replicate; yy++) { - glTexSubImage2D2(GL_TEXTURE_2D, 0, tex->tex % 16 * 16 + xx * 16, - tex->tex / 16 * 16 + yy * 16, 16, 16, - GL_RGBA, GL_UNSIGNED_BYTE, tex->pixels); - } - } - } -} - -void Textures::addDynamicTexture( DynamicTexture* dynamicTexture ) -{ - dynamicTextures.push_back(dynamicTexture); - dynamicTexture->tick(); -} - -void Textures::reloadAll() -{ - //TexturePack skin = skins.selected; - - //for (int id : loadedImages.keySet()) { - // BufferedImage image = loadedImages.get(id); - // loadTexture(image, id); - //} - - ////for (HttpTexture httpTexture : httpTextures.values()) { - //// httpTexture.isLoaded = false; - ////} - - //for (std::string name : idMap.keySet()) { - // try { - // BufferedImage image; - // if (name.startsWith("##")) { - // image = makeStrip(readImage(skin.getResource(name.substring(2)))); - // } else if (name.startsWith("%clamp%")) { - // clamp = true; - // image = readImage(skin.getResource(name.substring(7))); - // } else if (name.startsWith("%blur%")) { - // blur = true; - // image = readImage(skin.getResource(name.substring(6))); - // } else { - // image = readImage(skin.getResource(name)); - // } - // int id = idMap.get(name); - // loadTexture(image, id); - // blur = false; - // clamp = false; - // } catch (IOException e) { - // e.printStackTrace(); - // } - //} -} - -int Textures::smoothBlend( int c0, int c1 ) -{ - int a0 = (int) (((c0 & 0xff000000) >> 24)) & 0xff; - int a1 = (int) (((c1 & 0xff000000) >> 24)) & 0xff; - return ((a0 + a1) >> 1 << 24) + (((c0 & 0x00fefefe) + (c1 & 0x00fefefe)) >> 1); -} - -int Textures::crispBlend( int c0, int c1 ) -{ - int a0 = (int) (((c0 & 0xff000000) >> 24)) & 0xff; - int a1 = (int) (((c1 & 0xff000000) >> 24)) & 0xff; - - int a = 255; - if (a0 + a1 == 0) { - a0 = 1; - a1 = 1; - a = 0; - } - - int r0 = ((c0 >> 16) & 0xff) * a0; - int g0 = ((c0 >> 8) & 0xff) * a0; - int b0 = ((c0) & 0xff) * a0; - - int r1 = ((c1 >> 16) & 0xff) * a1; - int g1 = ((c1 >> 8) & 0xff) * a1; - int b1 = ((c1) & 0xff) * a1; - - int r = (r0 + r1) / (a0 + a1); - int g = (g0 + g1) / (a0 + a1); - int b = (b0 + b1) / (a0 + a1); - - return (a << 24) | (r << 16) | (g << 8) | b; -} - -///*public*/ int loadHttpTexture(std::string url, std::string backup) { -// HttpTexture texture = httpTextures.get(url); -// if (texture != NULL) { -// if (texture.loadedImage != NULL && !texture.isLoaded) { -// if (texture.id < 0) { -// texture.id = getTexture(texture.loadedImage); -// } else { -// loadTexture(texture.loadedImage, texture.id); -// } -// texture.isLoaded = true; -// } -// } -// if (texture == NULL || texture.id < 0) { -// if (backup == NULL) return -1; -// return loadTexture(backup); -// } -// return texture.id; -//} - -//HttpTexture addHttpTexture(std::string url, HttpTextureProcessor processor) { -// HttpTexture texture = httpTextures.get(url); -// if (texture == NULL) { -// httpTextures.put(url, /*new*/ HttpTexture(url, processor)); -// } else { -// texture.count++; -// } -// return texture; -//} - -//void removeHttpTexture(std::string url) { -// HttpTexture texture = httpTextures.get(url); -// if (texture != NULL) { -// texture.count--; -// if (texture.count == 0) { -// if (texture.id >= 0) releaseTexture(texture.id); -// httpTextures.remove(url); -// } -// } -//} - -//void tick() { -// for (int i = 0; i < dynamicTextures.size(); i++) { -// DynamicTexture dynamicTexture = dynamicTextures.get(i); -// dynamicTexture.anaglyph3d = options.anaglyph3d; -// dynamicTexture.tick(); -// -// pixels.clear(); -// pixels.put(dynamicTexture.pixels); -// pixels.position(0).limit(dynamicTexture.pixels.length); -// -// dynamicTexture.bindTexture(this); -// -// for (int xx = 0; xx < dynamicTexture.replicate; xx++) -// for (int yy = 0; yy < dynamicTexture.replicate; yy++) { -// -// glTexSubImage2D2(GL_TEXTURE_2D, 0, dynamicTexture.tex % 16 * 16 + xx * 16, dynamicTexture.tex / 16 * 16 + yy * 16, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, pixels); -// if (MIPMAP) { -// for (int level = 1; level <= 4; level++) { -// int os = 16 >> (level - 1); -// int s = 16 >> level; -// -// for (int x = 0; x < s; x++) -// for (int y = 0; y < s; y++) { -// int c0 = pixels.getInt(((x * 2 + 0) + (y * 2 + 0) * os) * 4); -// int c1 = pixels.getInt(((x * 2 + 1) + (y * 2 + 0) * os) * 4); -// int c2 = pixels.getInt(((x * 2 + 1) + (y * 2 + 1) * os) * 4); -// int c3 = pixels.getInt(((x * 2 + 0) + (y * 2 + 1) * os) * 4); -// int col = smoothBlend(smoothBlend(c0, c1), smoothBlend(c2, c3)); -// pixels.putInt((x + y * s) * 4, col); -// } -// glTexSubImage2D2(GL_TEXTURE_2D, level, dynamicTexture.tex % 16 * s, dynamicTexture.tex / 16 * s, s, s, GL_RGBA, GL_UNSIGNED_BYTE, pixels); -// } -// } -// } -// } -// -// for (int i = 0; i < dynamicTextures.size(); i++) { -// DynamicTexture dynamicTexture = dynamicTextures.get(i); -// -// if (dynamicTexture.copyTo > 0) { -// pixels.clear(); -// pixels.put(dynamicTexture.pixels); -// pixels.position(0).limit(dynamicTexture.pixels.length); -// glBindTexture2(GL_TEXTURE_2D, dynamicTexture.copyTo); -// glTexSubImage2D2(GL_TEXTURE_2D, 0, 0, 0, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, pixels); -// if (MIPMAP) { -// for (int level = 1; level <= 4; level++) { -// int os = 16 >> (level - 1); -// int s = 16 >> level; -// -// for (int x = 0; x < s; x++) -// for (int y = 0; y < s; y++) { -// int c0 = pixels.getInt(((x * 2 + 0) + (y * 2 + 0) * os) * 4); -// int c1 = pixels.getInt(((x * 2 + 1) + (y * 2 + 0) * os) * 4); -// int c2 = pixels.getInt(((x * 2 + 1) + (y * 2 + 1) * os) * 4); -// int c3 = pixels.getInt(((x * 2 + 0) + (y * 2 + 1) * os) * 4); -// int col = smoothBlend(smoothBlend(c0, c1), smoothBlend(c2, c3)); -// pixels.putInt((x + y * s) * 4, col); -// } -// glTexSubImage2D2(GL_TEXTURE_2D, level, 0, 0, s, s, GL_RGBA, GL_UNSIGNED_BYTE, pixels); -// } -// } -// } -// } -//} -// void releaseTexture(int id) { -// loadedImages.erase(id); -// glDeleteTextures(1, (const GLuint*)&id); -// } - +#include "Textures.hpp" + +#include "TextureData.hpp" +#include "ptexture/DynamicTexture.hpp" +#include "client/Options.hpp" +#include "platform/time.hpp" +#include "util/StringUtils.hpp" + +/*static*/ int Textures::textureChanges = 0; + +Textures::~Textures() { + clear(); + + for (unsigned int i = 0; i < dynamicTextures.size(); ++i) + delete dynamicTextures[i]; +} + +void Textures::clear() { + for (TextureMap::iterator it = idMap.begin(); it != idMap.end(); ++it) { + if (it->second != TEXTURES_INVALID_ID) + glDeleteTextures(1, &it->second); + } + for (TextureImageMap::iterator it = loadedImages.begin(); it != loadedImages.end(); ++it) { + if (!(it->second).memoryHandledExternally) + delete[] (it->second).data; + } + idMap.clear(); + loadedImages.clear(); + + lastBoundTexture = TEXTURES_INVALID_ID; +} + +TextureId Textures::loadAndBindTexture( const std::string& resourceName ) +{ + //static Stopwatch t; + + //t.start(); + TextureId id = loadTexture(resourceName); + //t.stop(); + if (id != TEXTURES_INVALID_ID) + bind(id); + + //t.printEvery(1000); + + return id; +} + +TextureId Textures::loadTexture(const std::string& resourceName, bool inTextureFolder) { + TextureMap::iterator it = idMap.find(resourceName); + if (it != idMap.end()) + return it->second; + + bool isUrl = Util::startsWith(resourceName, "http://") || Util::startsWith(resourceName, "https://"); + TextureData texdata = m_platform.loadTexture(resourceName, isUrl ? false : inTextureFolder); + if (texdata.data) + return assignTexture(resourceName, texdata); + else if (texdata.identifier != TEXTURES_INVALID_ID) { + //LOGI("Adding id: %d for %s\n", texdata.identifier, resourceName.c_str()); + idMap.insert(std::make_pair(resourceName, texdata.identifier)); + } + else { + idMap.insert(std::make_pair(resourceName, TEXTURES_INVALID_ID)); + //loadedImages.insert(std::make_pair(InvalidId, texdata)); + } + return TEXTURES_INVALID_ID; +} + +TextureId Textures::assignTexture( const std::string& resourceName, const TextureData& img ) +{ + TextureId id; + glGenTextures(1, &id); + + bind(id); + +#ifdef TEXTURES_MIPMAP + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#else + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +#endif + + if (blur) { + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (clamp) { + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri2(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + + switch (img.format) + { + case TEXF_COMPRESSED_PVRTC_4444: + case TEXF_COMPRESSED_PVRTC_565: + case TEXF_COMPRESSED_PVRTC_5551: + { +#if defined(__APPLE__) + int fmt = img.transparent? GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, img.w, img.h, 0, img.numBytes, img.data); +#endif + break; + } + + default: + const GLint mode = img.transparent? GL_RGBA : GL_RGB; + + if (img.format == TEXF_UNCOMPRESSED_565) { + glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_5_6_5, img.data); + } + else if (img.format == TEXF_UNCOMPRESSED_4444) { + glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_4_4_4_4, img.data); + } + else if (img.format == TEXF_UNCOMPRESSED_5551) { + glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_SHORT_5_5_5_1, img.data); + } + else { + glTexImage2D2(GL_TEXTURE_2D, 0, mode, img.w, img.h, 0, mode, GL_UNSIGNED_BYTE, img.data); + } + break; + } + + //LOGI("Adding id: %d to map\n", id); + idMap.insert(std::make_pair(resourceName, id)); + loadedImages.insert(std::make_pair(id, img)); + + return id; +} + +const TextureData* Textures::getTemporaryTextureData( TextureId id ) +{ + TextureImageMap::iterator it = loadedImages.find(id); + if (it == loadedImages.end()) + return NULL; + + return &it->second; +} + +void Textures::tick(bool uploadToGraphicsCard) +{ + for (unsigned int i = 0; i < dynamicTextures.size(); ++i ) { + DynamicTexture* tex = dynamicTextures[i]; + tex->tick(); + + if (uploadToGraphicsCard) { + tex->bindTexture(this); + for (int xx = 0; xx < tex->replicate; xx++) + for (int yy = 0; yy < tex->replicate; yy++) { + glTexSubImage2D2(GL_TEXTURE_2D, 0, tex->tex % 16 * 16 + xx * 16, + tex->tex / 16 * 16 + yy * 16, 16, 16, + GL_RGBA, GL_UNSIGNED_BYTE, tex->pixels); + } + } + } +} + +void Textures::addDynamicTexture( DynamicTexture* dynamicTexture ) +{ + dynamicTextures.push_back(dynamicTexture); + dynamicTexture->tick(); +} + +void Textures::reloadAll() +{ + //TexturePack skin = skins.selected; + + //for (int id : loadedImages.keySet()) { + // BufferedImage image = loadedImages.get(id); + // loadTexture(image, id); + //} + + ////for (HttpTexture httpTexture : httpTextures.values()) { + //// httpTexture.isLoaded = false; + ////} + + //for (std::string name : idMap.keySet()) { + // try { + // BufferedImage image; + // if (name.startsWith("##")) { + // image = makeStrip(readImage(skin.getResource(name.substring(2)))); + // } else if (name.startsWith("%clamp%")) { + // clamp = true; + // image = readImage(skin.getResource(name.substring(7))); + // } else if (name.startsWith("%blur%")) { + // blur = true; + // image = readImage(skin.getResource(name.substring(6))); + // } else { + // image = readImage(skin.getResource(name)); + // } + // int id = idMap.get(name); + // loadTexture(image, id); + // blur = false; + // clamp = false; + // } catch (IOException e) { + // e.printStackTrace(); + // } + //} +} + +int Textures::smoothBlend( int c0, int c1 ) +{ + int a0 = (int) (((c0 & 0xff000000) >> 24)) & 0xff; + int a1 = (int) (((c1 & 0xff000000) >> 24)) & 0xff; + return ((a0 + a1) >> 1 << 24) + (((c0 & 0x00fefefe) + (c1 & 0x00fefefe)) >> 1); +} + +int Textures::crispBlend( int c0, int c1 ) +{ + int a0 = (int) (((c0 & 0xff000000) >> 24)) & 0xff; + int a1 = (int) (((c1 & 0xff000000) >> 24)) & 0xff; + + int a = 255; + if (a0 + a1 == 0) { + a0 = 1; + a1 = 1; + a = 0; + } + + int r0 = ((c0 >> 16) & 0xff) * a0; + int g0 = ((c0 >> 8) & 0xff) * a0; + int b0 = ((c0) & 0xff) * a0; + + int r1 = ((c1 >> 16) & 0xff) * a1; + int g1 = ((c1 >> 8) & 0xff) * a1; + int b1 = ((c1) & 0xff) * a1; + + int r = (r0 + r1) / (a0 + a1); + int g = (g0 + g1) / (a0 + a1); + int b = (b0 + b1) / (a0 + a1); + + return (a << 24) | (r << 16) | (g << 8) | b; +} + +///*public*/ int loadHttpTexture(std::string url, std::string backup) { +// HttpTexture texture = httpTextures.get(url); +// if (texture != NULL) { +// if (texture.loadedImage != NULL && !texture.isLoaded) { +// if (texture.id < 0) { +// texture.id = getTexture(texture.loadedImage); +// } else { +// loadTexture(texture.loadedImage, texture.id); +// } +// texture.isLoaded = true; +// } +// } +// if (texture == NULL || texture.id < 0) { +// if (backup == NULL) return -1; +// return loadTexture(backup); +// } +// return texture.id; +//} + +//HttpTexture addHttpTexture(std::string url, HttpTextureProcessor processor) { +// HttpTexture texture = httpTextures.get(url); +// if (texture == NULL) { +// httpTextures.put(url, /*new*/ HttpTexture(url, processor)); +// } else { +// texture.count++; +// } +// return texture; +//} + +//void removeHttpTexture(std::string url) { +// HttpTexture texture = httpTextures.get(url); +// if (texture != NULL) { +// texture.count--; +// if (texture.count == 0) { +// if (texture.id >= 0) releaseTexture(texture.id); +// httpTextures.remove(url); +// } +// } +//} + +//void tick() { +// for (int i = 0; i < dynamicTextures.size(); i++) { +// DynamicTexture dynamicTexture = dynamicTextures.get(i); +// dynamicTexture.anaglyph3d = options.anaglyph3d; +// dynamicTexture.tick(); +// +// pixels.clear(); +// pixels.put(dynamicTexture.pixels); +// pixels.position(0).limit(dynamicTexture.pixels.length); +// +// dynamicTexture.bindTexture(this); +// +// for (int xx = 0; xx < dynamicTexture.replicate; xx++) +// for (int yy = 0; yy < dynamicTexture.replicate; yy++) { +// +// glTexSubImage2D2(GL_TEXTURE_2D, 0, dynamicTexture.tex % 16 * 16 + xx * 16, dynamicTexture.tex / 16 * 16 + yy * 16, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, pixels); +// if (MIPMAP) { +// for (int level = 1; level <= 4; level++) { +// int os = 16 >> (level - 1); +// int s = 16 >> level; +// +// for (int x = 0; x < s; x++) +// for (int y = 0; y < s; y++) { +// int c0 = pixels.getInt(((x * 2 + 0) + (y * 2 + 0) * os) * 4); +// int c1 = pixels.getInt(((x * 2 + 1) + (y * 2 + 0) * os) * 4); +// int c2 = pixels.getInt(((x * 2 + 1) + (y * 2 + 1) * os) * 4); +// int c3 = pixels.getInt(((x * 2 + 0) + (y * 2 + 1) * os) * 4); +// int col = smoothBlend(smoothBlend(c0, c1), smoothBlend(c2, c3)); +// pixels.putInt((x + y * s) * 4, col); +// } +// glTexSubImage2D2(GL_TEXTURE_2D, level, dynamicTexture.tex % 16 * s, dynamicTexture.tex / 16 * s, s, s, GL_RGBA, GL_UNSIGNED_BYTE, pixels); +// } +// } +// } +// } +// +// for (int i = 0; i < dynamicTextures.size(); i++) { +// DynamicTexture dynamicTexture = dynamicTextures.get(i); +// +// if (dynamicTexture.copyTo > 0) { +// pixels.clear(); +// pixels.put(dynamicTexture.pixels); +// pixels.position(0).limit(dynamicTexture.pixels.length); +// glBindTexture2(GL_TEXTURE_2D, dynamicTexture.copyTo); +// glTexSubImage2D2(GL_TEXTURE_2D, 0, 0, 0, 16, 16, GL_RGBA, GL_UNSIGNED_BYTE, pixels); +// if (MIPMAP) { +// for (int level = 1; level <= 4; level++) { +// int os = 16 >> (level - 1); +// int s = 16 >> level; +// +// for (int x = 0; x < s; x++) +// for (int y = 0; y < s; y++) { +// int c0 = pixels.getInt(((x * 2 + 0) + (y * 2 + 0) * os) * 4); +// int c1 = pixels.getInt(((x * 2 + 1) + (y * 2 + 0) * os) * 4); +// int c2 = pixels.getInt(((x * 2 + 1) + (y * 2 + 1) * os) * 4); +// int c3 = pixels.getInt(((x * 2 + 0) + (y * 2 + 1) * os) * 4); +// int col = smoothBlend(smoothBlend(c0, c1), smoothBlend(c2, c3)); +// pixels.putInt((x + y * s) * 4, col); +// } +// glTexSubImage2D2(GL_TEXTURE_2D, level, 0, 0, s, s, GL_RGBA, GL_UNSIGNED_BYTE, pixels); +// } +// } +// } +// } +//} +// void releaseTexture(int id) { +// loadedImages.erase(id); +// glDeleteTextures(1, (const GLuint*)&id); +// } + diff --git a/src/client/renderer/Textures.h b/src/client/renderer/Textures.hpp similarity index 96% rename from src/client/renderer/Textures.h rename to src/client/renderer/Textures.hpp index af3f4df..827edad 100755 --- a/src/client/renderer/Textures.h +++ b/src/client/renderer/Textures.hpp @@ -5,9 +5,9 @@ #include #include #include -#include -#include "gles.h" -#include "TextureData.h" +#include +#include "gles.hpp" +#include "TextureData.hpp" #define TEXTURES_INVALID_ID -1 #define TEXTURES_MIPMAP 0 diff --git a/src/client/renderer/TileRenderer.cpp b/src/client/renderer/TileRenderer.cpp index fc87e0e..ea758f6 100755 --- a/src/client/renderer/TileRenderer.cpp +++ b/src/client/renderer/TileRenderer.cpp @@ -1,2814 +1,2814 @@ -#include "TileRenderer.h" -#include "Chunk.h" -#include -#include "Tesselator.h" - -#include "../../world/level/LevelSource.h" -#include "../../world/level/tile/Tile.h" -#include "../../world/level/tile/DoorTile.h" -#include "../../world/level/tile/LiquidTile.h" -#include "../../world/level/tile/FenceTile.h" -#include "../../world/level/tile/FenceGateTile.h" -#include "../../world/level/tile/ThinFenceTile.h" -#include "../../world/level/tile/BedTile.h" -#include "../../world/level/tile/StemTile.h" -#include "../../world/level/tile/StairTile.h" -#include "../../world/Direction.h" -#include "../../world/Facing.h" -#include "tileentity/TileEntityRenderer.h" -#include "EntityTileRenderer.h" - -TileRenderer::TileRenderer( LevelSource* level /* = NULL */ ) -: level(level), - fixedTexture(-1), - xFlipTexture(false), - noCulling(false), - blsmooth(1), - applyAmbienceOcclusion(false) -{ -} - -bool TileRenderer::tesselateBlockInWorld(Tile* tt, int x, int y, int z) { - int col = tt->getColor(level, x, y, z); - float r = ((col >> 16) & 0xff) / 255.0f; - float g = ((col >> 8) & 0xff) / 255.0f; - float b = ((col) & 0xff) / 255.0f; // xFlipTexture = (x & 1) != (y & 1); - - if (Minecraft::useAmbientOcclusion) { - return tesselateBlockInWorldWithAmbienceOcclusion(tt, x, y, z, r, g, b); - } else - { - return tesselateBlockInWorld(tt, x, y, z, r, g, b); - } -} - -bool TileRenderer::tesselateBlockInWorld( Tile* tt, int x, int y, int z, float r, float g, float b ) -{ - applyAmbienceOcclusion = false; - float xf = (float)x; - float yf = (float)y; - float zf = (float)z; - - Tesselator& t = Tesselator::instance; - - bool changed = false; - float c10 = 0.5f; - float c11 = 1; - float c2 = 0.8f; - float c3 = 0.6f; - - - float r11 = c11 * r; - float g11 = c11 * g; - float b11 = c11 * b; - - if (tt == (Tile*)Tile::grass) { - r = g = b = 1.0f; - } - - float r10 = c10 * r; - float r2 = c2 * r; - float r3 = c3 * r; - - float g10 = c10 * g; - float g2 = c2 * g; - float g3 = c3 * g; - - float b10 = c10 * b; - float b2 = c2 * b; - float b3 = c3 * b; - - float centerBrightness = tt->getBrightness(level, x, y, z); - - if (noCulling || tt->shouldRenderFace(level, x, y - 1, z, Facing::DOWN)) { - float br = tt->getBrightness(level, x, y - 1, z); - t.color(r10 * br, g10 * br, b10 * br); - renderFaceDown(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 0)); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x, y + 1, z, Facing::UP)) { - float br = tt->getBrightness(level, x, y + 1, z); - if (tt->yy1 != 1 && !tt->material->isLiquid()) br = centerBrightness; - t.color(r11 * br, g11 * br, b11 * br); - renderFaceUp(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 1)); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x, y, z - 1, Facing::NORTH)) { - float br = tt->getBrightness(level, x, y, z - 1); - if (tt->zz0 > 0) br = centerBrightness; - t.color(r2 * br, g2 * br, b2 * br); - renderNorth(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 2)); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x, y, z + 1, Facing::SOUTH)) { - float br = tt->getBrightness(level, x, y, z + 1); - if (tt->zz1 < 1) br = centerBrightness; - t.color(r2 * br, g2 * br, b2 * br); - renderSouth(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 3)); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x - 1, y, z, Facing::WEST)) { - float br = tt->getBrightness(level, x - 1, y, z); - if (tt->xx0 > 0) br = centerBrightness; - t.color(r3 * br, g3 * br, b3 * br); - renderWest(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 4)); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x + 1, y, z, Facing::EAST)) { - float br = tt->getBrightness(level, x + 1, y, z); - if (tt->xx1 < 1) br = centerBrightness; - t.color(r3 * br, g3 * br, b3 * br); - renderEast(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 5)); - changed = true; - } - - return changed; -} - - -void TileRenderer::tesselateInWorld( Tile* tile, int x, int y, int z, int fixedTexture ) -{ - this->fixedTexture = fixedTexture; - tesselateInWorld(tile, x, y, z); - this->fixedTexture = -1; -} - -bool TileRenderer::tesselateInWorld( Tile* tt, int x, int y, int z ) -{ - int shape = tt->getRenderShape(); - tt->updateShape(level, x, y, z); - - if (shape == Tile::SHAPE_BLOCK) { - return tesselateBlockInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_WATER) { - return tesselateWaterInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_CACTUS) { - return tesselateCactusInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_CROSS_TEXTURE) { - return tesselateCrossInWorld(tt, x, y, z); - } else if(shape == Tile::SHAPE_STEM) { - return tesselateStemInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_ROWS) { - return tesselateRowInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_TORCH) { - return tesselateTorchInWorld(tt, x, y, z); - //} else if (shape == Tile::SHAPE_FIRE) { - // return tesselateFireInWorld(tt, x, y, z); - //} else if (shape == Tile::SHAPE_RED_DUST) { - // return tesselateDustInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_LADDER) { - return tesselateLadderInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_DOOR) { - return tesselateDoorInWorld(tt, x, y, z); - //} else if (shape == Tile::SHAPE_RAIL) { - // return tesselateRailInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_STAIRS) { - return tesselateStairsInWorld((StairTile*)tt, x, y, z); - } else if (shape == Tile::SHAPE_FENCE) { - return tesselateFenceInWorld((FenceTile*)tt, x, y, z); - } else if (shape == Tile::SHAPE_FENCE_GATE) { - return tesselateFenceGateInWorld((FenceGateTile*) tt, x, y, z); - //} else if (shape == Tile::SHAPE_LEVER) { - // return tesselateLeverInWorld(tt, x, y, z); - //} else if (shape == Tile::SHAPE_BED) { - // return tesselateBedInWorld(tt, x, y, z); - //} else if (shape == Tile::SHAPE_DIODE) { - // return tesselateDiodeInWorld(tt, x, y, z); - } else if (shape == Tile::SHAPE_IRON_FENCE) { - return tesselateThinFenceInWorld((ThinFenceTile*) tt, x, y, z); - } else if(shape == Tile::SHAPE_BED) { - return tesselateBedInWorld(tt, x, y, z); - } else { - return false; - } -} - -void TileRenderer::tesselateInWorldNoCulling( Tile* tile, int x, int y, int z ) -{ - noCulling = true; - tesselateInWorld(tile, x, y, z); - noCulling = false; -} - -bool TileRenderer::tesselateTorchInWorld( Tile* tt, int x, int y, int z ) -{ - int dir = level->getData(x, y, z); - - Tesselator& t = Tesselator::instance; - - float br = tt->getBrightness(level, x, y, z); - if (Tile::lightEmission[tt->id] > 0) br = 1.0f; - t.color(br, br, br); - - float r = 0.40f; - float r2 = 0.5f - r; - float h = 0.20f; - if (dir == 1) { - tesselateTorch(tt, (float)x - r2, (float)y + h, (float)z, -r, 0); - } else if (dir == 2) { - tesselateTorch(tt, (float)x + r2, (float)y + h, (float)z, +r, 0); - } else if (dir == 3) { - tesselateTorch(tt, (float)x, (float)y + h, (float)z - r2, 0, -r); - } else if (dir == 4) { - tesselateTorch(tt, (float)x, (float)y + h, (float)z + r2, 0, +r); - } else { - tesselateTorch(tt, (float)x, (float)y, (float)z, 0, 0); - } - return true; -} - -bool TileRenderer::tesselateLadderInWorld( Tile* tt, int x, int y, int z ) -{ - Tesselator& t = Tesselator::instance; - - int tex = tt->getTexture(0); - - if (fixedTexture >= 0) tex = fixedTexture; - - float br = tt->getBrightness(level, x, y, z); - t.color(br, br, br); - int xt = ((tex & 0xf) << 4); - int yt = tex & 0xf0; - - float u0 = (xt) / 256.0f; - float u1 = (xt + 15.99f) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 15.99f) / 256.0f; - - int face = level->getData(x, y, z); - - float o = 0 / 16.0f; - float r = 0.05f; - if (face == 5) { - t.vertexUV(x + r, y + 1 + o, z + 1 + o, u0, v0); - t.vertexUV(x + r, y + 0 - o, z + 1 + o, u0, v1); - t.vertexUV(x + r, y + 0 - o, z + 0 - o, u1, v1); - t.vertexUV(x + r, y + 1 + o, z + 0 - o, u1, v0); - } - if (face == 4) { - t.vertexUV(x + 1 - r, y + 0 - o, z + 1 + o, u1, v1); - t.vertexUV(x + 1 - r, y + 1 + o, z + 1 + o, u1, v0); - t.vertexUV(x + 1 - r, y + 1 + o, z + 0 - o, u0, v0); - t.vertexUV(x + 1 - r, y + 0 - o, z + 0 - o, u0, v1); - } - if (face == 3) { - t.vertexUV(x + 1 + o, y + 0 - o, z + r, u1, v1); - t.vertexUV(x + 1 + o, y + 1 + o, z + r, u1, v0); - t.vertexUV(x + 0 - o, y + 1 + o, z + r, u0, v0); - t.vertexUV(x + 0 - o, y + 0 - o, z + r, u0, v1); - } - if (face == 2) { - t.vertexUV(x + 1 + o, y + 1 + o, z + 1 - r, u0, v0); - t.vertexUV(x + 1 + o, y + 0 - o, z + 1 - r, u0, v1); - t.vertexUV(x + 0 - o, y + 0 - o, z + 1 - r, u1, v1); - t.vertexUV(x + 0 - o, y + 1 + o, z + 1 - r, u1, v0); - } - - return true; -} - -bool TileRenderer::tesselateCrossInWorld( Tile* tt, int x, int y, int z ) -{ - Tesselator& t = Tesselator::instance; - - float br = tt->getBrightness(level, x, y, z); - int col = tt->getColor(level, x, y, z); - float r = ((col >> 16) & 0xff) / 255.0f; - float g = ((col >> 8) & 0xff) / 255.0f; - float b = ((col) & 0xff) / 255.0f; - t.color(br * r, br * g, br * b); - - float xt = float(x); - float yt = float(y); - float zt = float(z); - - if (tt == Tile::tallgrass) { - long seed = (x * 3129871) ^ (z * 116129781l) ^ (y); - seed = seed * seed * 42317861 + seed * 11; - - xt += ((((seed >> 16) & 0xf) / 15.0f) - 0.5f) * 0.5f; - yt += ((((seed >> 20) & 0xf) / 15.0f) - 1.0f) * 0.2f; - zt += ((((seed >> 24) & 0xf) / 15.0f) - 0.5f) * 0.5f; - } - - tesselateCrossTexture(tt, level->getData(x, y, z), xt, yt, zt); - return true; - //return true; - /*Tesselator& t = Tesselator::instance; - - float br = tt->getBrightness(level, x, y, z); - t.color(br, br, br); - - tesselateCrossTexture(tt, level->getData(x, y, z), (float)x, (float)y, (float)z); - return true;*/ -} -bool TileRenderer::tesselateStemInWorld( Tile* _tt, int x, int y, int z ) { - StemTile* tt = (StemTile*) _tt; - Tesselator& t = Tesselator::instance; - - float br = tt->getBrightness(level, x, y, z); - - int col = tt->getColor(level, x, y, z); - float r = ((col >> 16) & 0xff) / 255.0f; - float g = ((col >> 8) & 0xff) / 255.0f; - float b = ((col) & 0xff) / 255.0f; - - t.color(br * r, br * g, br * b); - - tt->updateShape(level, x, y, z); - int dir = tt->getConnectDir(level, x, y, z); - if (dir < 0) { - tesselateStemTexture(tt, level->getData(x, y, z), tt->yy1, float(x), float(y - 1 / 16.0f), float(z)); - } else { - tesselateStemTexture(tt, level->getData(x, y, z), 0.5f, float(x), float(y - 1 / 16.0f), float(z)); - tesselateStemDirTexture(tt, level->getData(x, y, z), dir, tt->yy1, float(x), float(y - 1 / 16.0f), float(z)); - } - return true; -} -void TileRenderer::tesselateTorch( Tile* tt, float x, float y, float z, float xxa, float zza ) -{ - Tesselator& t = Tesselator::instance; - int tex = tt->getTexture(0); - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - float u0 = (xt) / 256.0f; - float u1 = (xt + 15.99f) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 15.99f) / 256.0f; - - - float uc0 = u0 + 7 / 256.0f; - float vc0 = v0 + 6 / 256.0f; - float uc1 = u0 + 9 / 256.0f; - float vc1 = v0 + 8 / 256.0f; - x += 0.5f; - z += 0.5f; - - float x0 = x - 0.5f; - float x1 = x + 0.5f; - float z0 = z - 0.5f; - float z1 = z + 0.5f; - float r = 1 / 16.0f; - - float h = 10.0f / 16.0f; - t.vertexUV(x + xxa * (1 - h) - r, y + h, z + zza * (1 - h) - r, uc0, vc0); - t.vertexUV(x + xxa * (1 - h) - r, y + h, z + zza * (1 - h) + r, uc0, vc1); - t.vertexUV(x + xxa * (1 - h) + r, y + h, z + zza * (1 - h) + r, uc1, vc1); - t.vertexUV(x + xxa * (1 - h) + r, y + h, z + zza * (1 - h) - r, uc1, vc0); - - t.vertexUV(x - r, y + 1, z0, u0, v0); - t.vertexUV(x - r + xxa, y + 0, z0 + zza, u0, v1); - t.vertexUV(x - r + xxa, y + 0, z1 + zza, u1, v1); - t.vertexUV(x - r, y + 1, z1, u1, v0); - - t.vertexUV(x + r, y + 1, z1, u0, v0); - t.vertexUV(x + xxa + r, y + 0, z1 + zza, u0, v1); - t.vertexUV(x + xxa + r, y + 0, z0 + zza, u1, v1); - t.vertexUV(x + r, y + 1, z0, u1, v0); - - t.vertexUV(x0, y + 1, z + r, u0, v0); - t.vertexUV(x0 + xxa, y + 0, z + r + zza, u0, v1); - t.vertexUV(x1 + xxa, y + 0, z + r + zza, u1, v1); - t.vertexUV(x1, y + 1, z + r, u1, v0); - - t.vertexUV(x1, y + 1, z - r, u0, v0); - t.vertexUV(x1 + xxa, y + 0, z - r + zza, u0, v1); - t.vertexUV(x0 + xxa, y + 0, z - r + zza, u1, v1); - t.vertexUV(x0, y + 1, z - r, u1, v0); -} - -void TileRenderer::tesselateCrossTexture( Tile* tt, int data, float x, float y, float z ) -{ - Tesselator& t = Tesselator::instance; - - int tex = tt->getTexture(0, data); - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - float u0 = (xt) / 256.0f; - float u1 = (xt + 15.99f) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 15.99f) / 256.0f; - - float x0 = x + 0.5f - 0.45f; - float x1 = x + 0.5f + 0.45f; - float z0 = z + 0.5f - 0.45f; - float z1 = z + 0.5f + 0.45f; - - t.vertexUV(x0, y + 1, z0, u0, v0); - t.vertexUV(x0, y + 0, z0, u0, v1); - t.vertexUV(x1, y + 0, z1, u1, v1); - t.vertexUV(x1, y + 1, z1, u1, v0); - - t.vertexUV(x1, y + 1, z1, u0, v0); - t.vertexUV(x1, y + 0, z1, u0, v1); - t.vertexUV(x0, y + 0, z0, u1, v1); - t.vertexUV(x0, y + 1, z0, u1, v0); - - t.vertexUV(x0, y + 1, z1, u0, v0); - t.vertexUV(x0, y + 0, z1, u0, v1); - t.vertexUV(x1, y + 0, z0, u1, v1); - t.vertexUV(x1, y + 1, z0, u1, v0); - - t.vertexUV(x1, y + 1, z0, u0, v0); - t.vertexUV(x1, y + 0, z0, u0, v1); - t.vertexUV(x0, y + 0, z1, u1, v1); - t.vertexUV(x0, y + 1, z1, u1, v0); -} -void TileRenderer::tesselateStemTexture( Tile* tt, int data, float h, float x, float y, float z ) { - Tesselator& t = Tesselator::instance; - int tex = tt->getTexture(0, data); - if(fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - float u0 = (xt) / 256.0f; - float u1 = (xt + 15.99f) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 15.99f * h) / 256.0f; - - float x0 = x + 0.5f - 0.45f; - float x1 = x + 0.5f + 0.45f; - float z0 = z + 0.5f - 0.45f; - float z1 = z + 0.5f + 0.45f; - - t.vertexUV(x0, y + h, z0, u0, v0); - t.vertexUV(x0, y + 0, z0, u0, v1); - t.vertexUV(x1, y + 0, z1, u1, v1); - t.vertexUV(x1, y + h, z1, u1, v0); - - t.vertexUV(x1, y + h, z1, u0, v0); - t.vertexUV(x1, y + 0, z1, u0, v1); - t.vertexUV(x0, y + 0, z0, u1, v1); - t.vertexUV(x0, y + h, z0, u1, v0); - - t.vertexUV(x0, y + h, z1, u0, v0); - t.vertexUV(x0, y + 0, z1, u0, v1); - t.vertexUV(x1, y + 0, z0, u1, v1); - t.vertexUV(x1, y + h, z0, u1, v0); - - t.vertexUV(x1, y + h, z0, u0, v0); - t.vertexUV(x1, y + 0, z0, u0, v1); - t.vertexUV(x0, y + 0, z1, u1, v1); - t.vertexUV(x0, y + h, z1, u1, v0); -} -void TileRenderer::tesselateStemDirTexture( Tile* tt, int data, int dir, float h, float x, float y, float z ) { - Tesselator& t = Tesselator::instance; - - int tex = tt->getTexture(0, data) + 16; - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - float u0 = (xt) / 256.0f; - float u1 = (xt + 15.99f) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 15.99f * h) / 256.0f; - - float x0 = x + 0.5f - 0.5f; - float x1 = x + 0.5f + 0.5f; - float z0 = z + 0.5f - 0.5f; - float z1 = z + 0.5f + 0.5f; - - float xm = x + 0.5f; - float zm = z + 0.5f; - - if ((dir + 1) / 2 % 2 == 1) { - float tmp = u1; - u1 = u0; - u0 = tmp; - } - - if (dir < 2) { - t.vertexUV(x0, y + h, zm, u0, v0); - t.vertexUV(x0, y + 0, zm, u0, v1); - t.vertexUV(x1, y + 0, zm, u1, v1); - t.vertexUV(x1, y + h, zm, u1, v0); - - t.vertexUV(x1, y + h, zm, u1, v0); - t.vertexUV(x1, y + 0, zm, u1, v1); - t.vertexUV(x0, y + 0, zm, u0, v1); - t.vertexUV(x0, y + h, zm, u0, v0); - } else { - - t.vertexUV(xm, y + h, z1, u0, v0); - t.vertexUV(xm, y + 0, z1, u0, v1); - t.vertexUV(xm, y + 0, z0, u1, v1); - t.vertexUV(xm, y + h, z0, u1, v0); - - t.vertexUV(xm, y + h, z0, u1, v0); - t.vertexUV(xm, y + 0, z0, u1, v1); - t.vertexUV(xm, y + 0, z1, u0, v1); - t.vertexUV(xm, y + h, z1, u0, v0); - } -} - -bool TileRenderer::tesselateWaterInWorld( Tile* tt, int x, int y, int z ) -{ - Tesselator& t = Tesselator::instance; - - bool up = tt->shouldRenderFace(level, x, y + 1, z, 1); - bool down = tt->shouldRenderFace(level, x, y - 1, z, 0); - - bool dirs[4]; // static? - dirs[0] = tt->shouldRenderFace(level, x, y, z - 1, 2); - dirs[1] = tt->shouldRenderFace(level, x, y, z + 1, 3); - dirs[2] = tt->shouldRenderFace(level, x - 1, y, z, 4); - dirs[3] = tt->shouldRenderFace(level, x + 1, y, z, 5); - - if (!up && !down && !dirs[0] && !dirs[1] && !dirs[2] && !dirs[3]) return false; - - bool changed = false; - float c10 = 0.5f; - float c11 = 1; - float c2 = 0.8f; - float c3 = 0.6f; - - const float yo0 = 0; - const float yo1 = 1; - - const Material* m = tt->material; - int data = level->getData(x, y, z); - - float h0 = getWaterHeight(x, y, z, m); - float h1 = getWaterHeight(x, y, z + 1, m); - float h2 = getWaterHeight(x + 1, y, z + 1, m); - float h3 = getWaterHeight(x + 1, y, z, m); - - // renderFaceUp(tt, x, y, z, tt->getTexture(0)); - if (noCulling || up) { - changed = true; - int tex = tt->getTexture(1, data); - float angle = (float) LiquidTile::getSlopeAngle(level, x, y, z, m); - if (angle > -999) { - tex = tt->getTexture(2, data); - } - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float uc = (xt + 0.5f * 16) / 256.0f; - float vc = (yt + 0.5f * 16) / 256.0f; - if (angle < -999) { - angle = 0; - } else { - uc = (xt + 1 * 16) / 256.0f; - vc = (yt + 1 * 16) / 256.0f; - } - float s = (Mth::sin(angle) * 8) / 256.5f; // @attn: to get rid of "jitter" (caused - float c = (Mth::cos(angle) * 8) / 256.5f; // of fp rounding errors) in big oceans) - - float br = tt->getBrightness(level, x, y, z); - t.color(c11 * br, c11 * br, c11 * br); - t.vertexUV((float)x + 0, (float)y + h0, (float)z + 0, uc - c - s, vc - c + s); - t.vertexUV((float)x + 0, (float)y + h1, (float)z + 1, uc - c + s, vc + c + s); - t.vertexUV((float)x + 1, (float)y + h2, (float)z + 1, uc + c + s, vc + c - s); - t.vertexUV((float)x + 1, (float)y + h3, (float)z + 0, uc + c - s, vc - c - s); - } - - if (noCulling || down) { - float br = tt->getBrightness(level, x, y - 1, z); - t.color(c10 * br, c10 * br, c10 * br); - renderFaceDown(tt, (float)x, (float)y, (float)z, tt->getTexture(0)); - changed = true; - } - - for (int face = 0; face < 4; face++) { - int xt = x; - int yt = y; - int zt = z; - - if (face == 0) zt--; - if (face == 1) zt++; - if (face == 2) xt--; - if (face == 3) xt++; - - int tex = tt->getTexture(face + 2, data); - int xTex = (tex & 0xf) << 4; - int yTex = tex & 0xf0; - - if (noCulling || dirs[face]) { - float hh0; - float hh1; - float x0, z0, x1, z1; - if (face == 0) { - hh0 = h0; - hh1 = h3; - x0 = (float)(x ); - x1 = (float)(x + 1); - z0 = (float)(z ); - z1 = (float)(z ); - } else if (face == 1) { - hh0 = h2; - hh1 = h1; - x0 = (float)(x + 1); - x1 = (float)(x ); - z0 = (float)(z + 1); - z1 = (float)(z + 1); - } else if (face == 2) { - hh0 = h1; - hh1 = h0; - x0 = (float)(x ); - x1 = (float)(x ); - z0 = (float)(z + 1); - z1 = (float)(z ); - } else { - hh0 = h3; - hh1 = h2; - x0 = (float)(x + 1); - x1 = (float)(x + 1); - z0 = (float)(z ); - z1 = (float)(z + 1); - } - - changed = true; - float u0 = (xTex + 0 * 16) / 256.0f; - float u1 = (xTex + 1 * 16 - 0.01f) / 256.0f; - - float v01 = (yTex + (1 - hh0) * 16) / 256.0f; - float v02 = (yTex + (1 - hh1) * 16) / 256.0f; - float v1 = (yTex + 1 * 16 - 0.01f) / 256.0f; - - float br = tt->getBrightness(level, xt, yt, zt); - if (face < 2) br *= c2; - else br *= c3; - - float yf = (float)y; - t.color(c11 * br, c11 * br, c11 * br); - t.vertexUV(x0, yf + hh0, z0, u0, v01); - t.vertexUV(x1, yf + hh1, z1, u1, v02); - t.vertexUV(x1, yf + 0, z1, u1, v1); - t.vertexUV(x0, yf + 0, z0, u0, v1); - } - } - - //printf("w: %d ", (dirs[0] + dirs[1] + dirs[2] + dirs[3] + up + down)); - - tt->yy0 = yo0; - tt->yy1 = yo1; - - return changed; -} - -float TileRenderer::getWaterHeight( int x, int y, int z, const Material* m ) -{ - int count = 0; - float h = 0; - for (int i = 0; i < 4; i++) { - int xx = x - (i & 1); - int yy = y; - int zz = z - ((i >> 1) & 1); - if (level->getMaterial(xx, yy + 1, zz) == m) { - return 1; - } - const Material* tm = level->getMaterial(xx, yy, zz); - if (tm == m) { - int d = level->getData(xx, yy, zz); - if (d >= 8 || d == 0) { - h += (LiquidTile::getHeight(d)) * 10; - count += 10; - } - h += LiquidTile::getHeight(d); - count++; - } else if (!tm->isSolid()) { - h += 1; - count++; - } - } - return 1 - h / count; -} - -void TileRenderer::renderBlock(Tile* tt, LevelSource* level, int x, int y, int z) { - float c10 = 0.5f; - float c11 = 1; - float c2 = 0.8f; - float c3 = 0.6f; - - Tesselator& t = Tesselator::instance; - t.begin(); - - float center = tt->getBrightness(level, x, y, z); - float br = tt->getBrightness(level, x, y - 1, z); - if (br < center) br = center; - - t.color(c10 * br, c10 * br, c10 * br); - renderFaceDown(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(0)); - - br = tt->getBrightness(level, x, y + 1, z); - if (br < center) br = center; - t.color(c11 * br, c11 * br, c11 * br); - renderFaceUp(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(1)); - - br = tt->getBrightness(level, x, y, z - 1); - if (br < center) br = center; - t.color(c2 * br, c2 * br, c2 * br); - renderNorth(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(2)); - - br = tt->getBrightness(level, x, y, z + 1); - if (br < center) br = center; - t.color(c2 * br, c2 * br, c2 * br); - renderSouth(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(3)); - - br = tt->getBrightness(level, x - 1, y, z); - if (br < center) br = center; - t.color(c3 * br, c3 * br, c3 * br); - renderWest(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(4)); - - br = tt->getBrightness(level, x + 1, y, z); - if (br < center) br = center; - t.color(c3 * br, c3 * br, c3 * br); - renderEast(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(5)); - t.draw(); -} - -bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusion( Tile* tt, int pX, int pY, int pZ, float pBaseRed, float pBaseGreen, float pBaseBlue ) -{ - applyAmbienceOcclusion = true; - bool i = false; - float ll1 = ll000; - float ll2 = ll000; - float ll3 = ll000; - float ll4 = ll000; - bool tint0 = true; - bool tint1 = true; - bool tint2 = true; - bool tint3 = true; - bool tint4 = true; - bool tint5 = true; - - ll000 = tt->getBrightness(level, pX, pY, pZ); - llx00 = tt->getBrightness(level, pX - 1, pY, pZ); - ll0y0 = tt->getBrightness(level, pX, pY - 1, pZ); - ll00z = tt->getBrightness(level, pX, pY, pZ - 1); - llX00 = tt->getBrightness(level, pX + 1, pY, pZ); - ll0Y0 = tt->getBrightness(level, pX, pY + 1, pZ); - ll00Z = tt->getBrightness(level, pX, pY, pZ + 1); - - llTransXY0 = Tile::translucent[level->getTile(pX + 1, pY + 1, pZ)]; - llTransXy0 = Tile::translucent[level->getTile(pX + 1, pY - 1, pZ)]; - llTransX0Z = Tile::translucent[level->getTile(pX + 1, pY, pZ + 1)]; - llTransX0z = Tile::translucent[level->getTile(pX + 1, pY, pZ - 1)]; - llTransxY0 = Tile::translucent[level->getTile(pX - 1, pY + 1, pZ)]; - llTransxy0 = Tile::translucent[level->getTile(pX - 1, pY - 1, pZ)]; - llTransx0z = Tile::translucent[level->getTile(pX - 1, pY, pZ - 1)]; - llTransx0Z = Tile::translucent[level->getTile(pX - 1, pY, pZ + 1)]; - llTrans0YZ = Tile::translucent[level->getTile(pX, pY + 1, pZ + 1)]; - llTrans0Yz = Tile::translucent[level->getTile(pX, pY + 1, pZ - 1)]; - llTrans0yZ = Tile::translucent[level->getTile(pX, pY - 1, pZ + 1)]; - llTrans0yz = Tile::translucent[level->getTile(pX, pY - 1, pZ - 1)]; - - if (tt->tex == 3) tint0 = tint2 = tint3 = tint4 = tint5 = false; - - if ((noCulling) || (tt->shouldRenderFace(level, pX, pY - 1, pZ, 0))) { - if (blsmooth > 0) { - pY--; - - llxy0 = tt->getBrightness(level, pX - 1, pY, pZ); - ll0yz = tt->getBrightness(level, pX, pY, pZ - 1); - ll0yZ = tt->getBrightness(level, pX, pY, pZ + 1); - llXy0 = tt->getBrightness(level, pX + 1, pY, pZ); - - if (llTrans0yz || llTransxy0) { - llxyz = tt->getBrightness(level, pX - 1, pY, pZ - 1); - } else { - llxyz = llxy0; - } - if (llTrans0yZ || llTransxy0) { - llxyZ = tt->getBrightness(level, pX - 1, pY, pZ + 1); - } else { - llxyZ = llxy0; - } - if (llTrans0yz || llTransXy0) { - llXyz = tt->getBrightness(level, pX + 1, pY, pZ - 1); - } else { - llXyz = llXy0; - } - if (llTrans0yZ || llTransXy0) { - llXyZ = tt->getBrightness(level, pX + 1, pY, pZ + 1); - } else { - llXyZ = llXy0; - } - - pY++; - ll1 = (llxyZ + llxy0 + ll0yZ + ll0y0) / 4.0f; - ll4 = (ll0yZ + ll0y0 + llXyZ + llXy0) / 4.0f; - ll3 = (ll0y0 + ll0yz + llXy0 + llXyz) / 4.0f; - ll2 = (llxy0 + llxyz + ll0y0 + ll0yz) / 4.0f; - } else ll1 = ll2 = ll3 = ll4 = ll0y0; - c1r = c2r = c3r = c4r = (tint0 ? pBaseRed : 1.0f) * 0.5f; - c1g = c2g = c3g = c4g = (tint0 ? pBaseGreen : 1.0f) * 0.5f; - c1b = c2b = c3b = c4b = (tint0 ? pBaseBlue : 1.0f) * 0.5f; - c1r *= ll1; - c1g *= ll1; - c1b *= ll1; - c2r *= ll2; - c2g *= ll2; - c2b *= ll2; - c3r *= ll3; - c3g *= ll3; - c3b *= ll3; - c4r *= ll4; - c4g *= ll4; - c4b *= ll4; - - renderFaceDown(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 0)); - i = true; - } - if ((noCulling) || (tt->shouldRenderFace(level, pX, pY + 1, pZ, 1))) { - if (blsmooth > 0) { - pY++; - - llxY0 = tt->getBrightness(level, pX - 1, pY, pZ); - llXY0 = tt->getBrightness(level, pX + 1, pY, pZ); - ll0Yz = tt->getBrightness(level, pX, pY, pZ - 1); - ll0YZ = tt->getBrightness(level, pX, pY, pZ + 1); - - if (llTrans0Yz || llTransxY0) { - llxYz = tt->getBrightness(level, pX - 1, pY, pZ - 1); - } else { - llxYz = llxY0; - } - if (llTrans0Yz || llTransXY0) { - llXYz = tt->getBrightness(level, pX + 1, pY, pZ - 1); - } else { - llXYz = llXY0; - } - if (llTrans0YZ || llTransxY0) { - llxYZ = tt->getBrightness(level, pX - 1, pY, pZ + 1); - } else { - llxYZ = llxY0; - } - if (llTrans0YZ || llTransXY0) { - llXYZ = tt->getBrightness(level, pX + 1, pY, pZ + 1); - } else { - llXYZ = llXY0; - } - pY--; - - ll4 = (llxYZ + llxY0 + ll0YZ + ll0Y0) / 4.0f; - ll1 = (ll0YZ + ll0Y0 + llXYZ + llXY0) / 4.0f; - ll2 = (ll0Y0 + ll0Yz + llXY0 + llXYz) / 4.0f; - ll3 = (llxY0 + llxYz + ll0Y0 + ll0Yz) / 4.0f; - } else ll1 = ll2 = ll3 = ll4 = ll0Y0; - c1r = c2r = c3r = c4r = (tint1 ? pBaseRed : 1.0f); - c1g = c2g = c3g = c4g = (tint1 ? pBaseGreen : 1.0f); - c1b = c2b = c3b = c4b = (tint1 ? pBaseBlue : 1.0f); - c1r *= ll1; - c1g *= ll1; - c1b *= ll1; - c2r *= ll2; - c2g *= ll2; - c2b *= ll2; - c3r *= ll3; - c3g *= ll3; - c3b *= ll3; - c4r *= ll4; - c4g *= ll4; - c4b *= ll4; - renderFaceUp(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 1)); - i = true; - } - if ((noCulling) || (tt->shouldRenderFace(level, pX, pY, pZ - 1, 2))) { - if (blsmooth > 0) { - pZ--; - llx0z = tt->getBrightness(level, pX - 1, pY, pZ); - ll0yz = tt->getBrightness(level, pX, pY - 1, pZ); - ll0Yz = tt->getBrightness(level, pX, pY + 1, pZ); - llX0z = tt->getBrightness(level, pX + 1, pY, pZ); - - if (llTransx0z || llTrans0yz) { - llxyz = tt->getBrightness(level, pX - 1, pY - 1, pZ); - } else { - llxyz = llx0z; - } - if (llTransx0z || llTrans0Yz) { - llxYz = tt->getBrightness(level, pX - 1, pY + 1, pZ); - } else { - llxYz = llx0z; - } - if (llTransX0z || llTrans0yz) { - llXyz = tt->getBrightness(level, pX + 1, pY - 1, pZ); - } else { - llXyz = llX0z; - } - if (llTransX0z || llTrans0Yz) { - llXYz = tt->getBrightness(level, pX + 1, pY + 1, pZ); - } else { - llXYz = llX0z; - } - pZ++; - ll1 = (llx0z + llxYz + ll00z + ll0Yz) / 4.0f; - ll2 = (ll00z + ll0Yz + llX0z + llXYz) / 4.0f; - ll3 = (ll0yz + ll00z + llXyz + llX0z) / 4.0f; - ll4 = (llxyz + llx0z + ll0yz + ll00z) / 4.0f; - } else ll1 = ll2 = ll3 = ll4 = ll00z; - c1r = c2r = c3r = c4r = (tint2 ? pBaseRed : 1.0f) * 0.8f; - c1g = c2g = c3g = c4g = (tint2 ? pBaseGreen : 1.0f) * 0.8f; - c1b = c2b = c3b = c4b = (tint2 ? pBaseBlue : 1.0f) * 0.8f; - c1r *= ll1; - c1g *= ll1; - c1b *= ll1; - c2r *= ll2; - c2g *= ll2; - c2b *= ll2; - c3r *= ll3; - c3g *= ll3; - c3b *= ll3; - c4r *= ll4; - c4g *= ll4; - c4b *= ll4; - renderNorth(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 2)); - i = true; - } - if ((noCulling) || (tt->shouldRenderFace(level, pX, pY, pZ + 1, 3))) { - if (blsmooth > 0) { - pZ++; - - llx0Z = tt->getBrightness(level, pX - 1, pY, pZ); - llX0Z = tt->getBrightness(level, pX + 1, pY, pZ); - ll0yZ = tt->getBrightness(level, pX, pY - 1, pZ); - ll0YZ = tt->getBrightness(level, pX, pY + 1, pZ); - - if (llTransx0Z || llTrans0yZ) { - llxyZ = tt->getBrightness(level, pX - 1, pY - 1, pZ); - } else { - llxyZ = llx0Z; - } - if (llTransx0Z || llTrans0YZ) { - llxYZ = tt->getBrightness(level, pX - 1, pY + 1, pZ); - } else { - llxYZ = llx0Z; - } - if (llTransX0Z || llTrans0yZ) { - llXyZ = tt->getBrightness(level, pX + 1, pY - 1, pZ); - } else { - llXyZ = llX0Z; - } - if (llTransX0Z || llTrans0YZ) { - llXYZ = tt->getBrightness(level, pX + 1, pY + 1, pZ); - } else { - llXYZ = llX0Z; - } - pZ--; - ll1 = (llx0Z + llxYZ + ll00Z + ll0YZ) / 4.0f; - ll4 = (ll00Z + ll0YZ + llX0Z + llXYZ) / 4.0f; - ll3 = (ll0yZ + ll00Z + llXyZ + llX0Z) / 4.0f; - ll2 = (llxyZ + llx0Z + ll0yZ + ll00Z) / 4.0f; - } else ll1 = ll2 = ll3 = ll4 = ll00Z; - c1r = c2r = c3r = c4r = (tint3 ? pBaseRed : 1.0f) * 0.8f; - c1g = c2g = c3g = c4g = (tint3 ? pBaseGreen : 1.0f) * 0.8f; - c1b = c2b = c3b = c4b = (tint3 ? pBaseBlue : 1.0f) * 0.8f; - c1r *= ll1; - c1g *= ll1; - c1b *= ll1; - c2r *= ll2; - c2g *= ll2; - c2b *= ll2; - c3r *= ll3; - c3g *= ll3; - c3b *= ll3; - c4r *= ll4; - c4g *= ll4; - c4b *= ll4; - renderSouth(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 3)); - i = true; - } - if ((noCulling) || (tt->shouldRenderFace(level, pX - 1, pY, pZ, 4))) { - if (blsmooth > 0) { - pX--; - llxy0 = tt->getBrightness(level, pX, pY - 1, pZ); - llx0z = tt->getBrightness(level, pX, pY, pZ - 1); - llx0Z = tt->getBrightness(level, pX, pY, pZ + 1); - llxY0 = tt->getBrightness(level, pX, pY + 1, pZ); - - if (llTransx0z || llTransxy0) { - llxyz = tt->getBrightness(level, pX, pY - 1, pZ - 1); - } else { - llxyz = llx0z; - } - if (llTransx0Z || llTransxy0) { - llxyZ = tt->getBrightness(level, pX, pY - 1, pZ + 1); - } else { - llxyZ = llx0Z; - } - if (llTransx0z || llTransxY0) { - llxYz = tt->getBrightness(level, pX, pY + 1, pZ - 1); - } else { - llxYz = llx0z; - } - if (llTransx0Z || llTransxY0) { - llxYZ = tt->getBrightness(level, pX, pY + 1, pZ + 1); - } else { - llxYZ = llx0Z; - } - pX++; - ll4 = (llxy0 + llxyZ + llx00 + llx0Z) / 4.0f; - ll1 = (llx00 + llx0Z + llxY0 + llxYZ) / 4.0f; - ll2 = (llx0z + llx00 + llxYz + llxY0) / 4.0f; - ll3 = (llxyz + llxy0 + llx0z + llx00) / 4.0f; - } else ll1 = ll2 = ll3 = ll4 = llx00; - c1r = c2r = c3r = c4r = (tint4 ? pBaseRed : 1.0f) * 0.6f; - c1g = c2g = c3g = c4g = (tint4 ? pBaseGreen : 1.0f) * 0.6f; - c1b = c2b = c3b = c4b = (tint4 ? pBaseBlue : 1.0f) * 0.6f; - c1r *= ll1; - c1g *= ll1; - c1b *= ll1; - c2r *= ll2; - c2g *= ll2; - c2b *= ll2; - c3r *= ll3; - c3g *= ll3; - c3b *= ll3; - c4r *= ll4; - c4g *= ll4; - c4b *= ll4; - renderWest(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 4)); - i = true; - } - if ((noCulling) || (tt->shouldRenderFace(level, pX + 1, pY, pZ, 5))) { - if (blsmooth > 0) { - pX++; - llXy0 = tt->getBrightness(level, pX, pY - 1, pZ); - llX0z = tt->getBrightness(level, pX, pY, pZ - 1); - llX0Z = tt->getBrightness(level, pX, pY, pZ + 1); - llXY0 = tt->getBrightness(level, pX, pY + 1, pZ); - - if (llTransXy0 || llTransX0z) { - llXyz = tt->getBrightness(level, pX, pY - 1, pZ - 1); - } else { - llXyz = llX0z; - } - if (llTransXy0 || llTransX0Z) { - llXyZ = tt->getBrightness(level, pX, pY - 1, pZ + 1); - } else { - llXyZ = llX0Z; - } - if (llTransXY0 || llTransX0z) { - llXYz = tt->getBrightness(level, pX, pY + 1, pZ - 1); - } else { - llXYz = llX0z; - } - if (llTransXY0 || llTransX0Z) { - llXYZ = tt->getBrightness(level, pX, pY + 1, pZ + 1); - } else { - llXYZ = llX0Z; - } - pX--; - ll1 = (llXy0 + llXyZ + llX00 + llX0Z) / 4.0f; - ll4 = (llX00 + llX0Z + llXY0 + llXYZ) / 4.0f; - ll3 = (llX0z + llX00 + llXYz + llXY0) / 4.0f; - ll2 = (llXyz + llXy0 + llX0z + llX00) / 4.0f; - } else ll1 = ll2 = ll3 = ll4 = llX00; - c1r = c2r = c3r = c4r = (tint5 ? pBaseRed : 1.0f) * 0.6f; - c1g = c2g = c3g = c4g = (tint5 ? pBaseGreen : 1.0f) * 0.6f; - c1b = c2b = c3b = c4b = (tint5 ? pBaseBlue : 1.0f) * 0.6f; - c1r *= ll1; - c1g *= ll1; - c1b *= ll1; - c2r *= ll2; - c2g *= ll2; - c2b *= ll2; - c3r *= ll3; - c3g *= ll3; - c3b *= ll3; - c4r *= ll4; - c4g *= ll4; - c4b *= ll4; - - renderEast(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 5)); - i = true; - } - applyAmbienceOcclusion = false; - return i; -} - -bool TileRenderer::tesselateCactusInWorld(Tile* tt, int x, int y, int z) { - int col = tt->getColor(level, x, y, z); - float r = ((col >> 16) & 0xff) / 255.0f; - float g = ((col >> 8) & 0xff) / 255.0f; - float b = ((col) & 0xff) / 255.0f; - return tesselateCactusInWorld(tt, x, y, z, r, g, b); -} - -bool TileRenderer::tesselateCactusInWorld(Tile* tt, int x, int y, int z, float r, float g, float b) { - Tesselator& t = Tesselator::instance; - - bool changed = false; - float c10 = 0.5f; - float c11 = 1; - float c2 = 0.8f; - float c3 = 0.6f; - - float r10 = c10 * r; - float r11 = c11 * r; - float r2 = c2 * r; - float r3 = c3 * r; - - float g10 = c10 * g; - float g11 = c11 * g; - float g2 = c2 * g; - float g3 = c3 * g; - - float b10 = c10 * b; - float b11 = c11 * b; - float b2 = c2 * b; - float b3 = c3 * b; - - float s = 1 / 16.0f; - const float X = (float)x; - const float Y = (float)y; - const float Z = (float)z; - - float centerBrightness = tt->getBrightness(level, x, y, z); - - if (noCulling || tt->shouldRenderFace(level, x, y - 1, z, 0)) { - float br = tt->getBrightness(level, x, y - 1, z); - // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = -// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; - t.color(r10 * br, g10 * br, b10 * br); - renderFaceDown(tt, X, Y, Z, tt->getTexture(level, x, y, z, 0)); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x, y + 1, z, 1)) { - float br = tt->getBrightness(level, x, y + 1, z); - if (tt->yy1 != 1 && !tt->material->isLiquid()) br = centerBrightness; - // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = -// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; - t.color(r11 * br, g11 * br, b11 * br); - renderFaceUp(tt, X, Y, Z, tt->getTexture(level, x, y, z, 1)); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x, y, z - 1, 2)) { - float br = tt->getBrightness(level, x, y, z - 1); - if (tt->zz0 > 0) br = centerBrightness; - // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = -// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; - t.color(r2 * br, g2 * br, b2 * br); - t.addOffset(0, 0, s); - renderNorth(tt, X, Y, Z, tt->getTexture(level, x, y, z, 2)); - t.addOffset(0, 0, -s); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x, y, z + 1, 3)) { - float br = tt->getBrightness(level, x, y, z + 1); - if (tt->zz1 < 1) br = centerBrightness; - // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = -// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; - t.color(r2 * br, g2 * br, b2 * br); - t.addOffset(0, 0, -s); - renderSouth(tt, X, Y, Z, tt->getTexture(level, x, y, z, 3)); - t.addOffset(0, 0, s); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x - 1, y, z, 4)) { - float br = tt->getBrightness(level, x - 1, y, z); - if (tt->xx0 > 0) br = centerBrightness; - // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = -// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; - t.color(r3 * br, g3 * br, b3 * br); - t.addOffset(s, 0, 0); - renderWest(tt, X, Y, Z, tt->getTexture(level, x, y, z, 4)); - t.addOffset(-s, 0, 0); - changed = true; - } - - if (noCulling || tt->shouldRenderFace(level, x + 1, y, z, 5)) { - float br = tt->getBrightness(level, x + 1, y, z); - if (tt->xx1 < 1) br = centerBrightness; - // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = -// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; - t.color(r3 * br, g3 * br, b3 * br); - t.addOffset(-s, 0, 0); - renderEast(tt, X, Y, Z, tt->getTexture(level, x, y, z, 5)); - t.addOffset(s, 0, 0); - changed = true; - } - - return changed; -} - -bool TileRenderer::tesselateFenceInWorld(FenceTile* tt, int x, int y, int z) { - bool changed = true; - - float a = 6 / 16.0f; - float b = 10 / 16.0f; - tt->setShape(a, 0, a, b, 1, b); - tesselateBlockInWorld(tt, x, y, z); - - bool vertical = false; - bool horizontal = false; - - bool l = tt->connectsTo(level, x - 1, y, z); - bool r = tt->connectsTo(level, x + 1, y, z); - bool u = tt->connectsTo(level, x, y, z - 1); - bool d = tt->connectsTo(level, x, y, z + 1); - - if (l || r) vertical = true; - if (u || d) horizontal = true; - - if (!vertical && !horizontal) vertical = true; - - a = 7 / 16.0f; - b = 9 / 16.0f; - float h0 = 12 / 16.0f; - float h1 = 15 / 16.0f; - - float x0 = l ? 0 : a; - float x1 = r ? 1 : b; - float z0 = u ? 0 : a; - float z1 = d ? 1 : b; - - if (vertical) { - tt->setShape(x0, h0, a, x1, h1, b); - tesselateBlockInWorld(tt, x, y, z); - } - if (horizontal) { - tt->setShape(a, h0, z0, b, h1, z1); - tesselateBlockInWorld(tt, x, y, z); - } - - h0 = 6 / 16.0f; - h1 = 9 / 16.0f; - if (vertical) { - tt->setShape(x0, h0, a, x1, h1, b); - tesselateBlockInWorld(tt, x, y, z); - } - if (horizontal) { - tt->setShape(a, h0, z0, b, h1, z1); - tesselateBlockInWorld(tt, x, y, z); - } - - tt->setShape(0, 0, 0, 1, 1, 1); - return changed; -} - -bool TileRenderer::tesselateFenceGateInWorld(FenceGateTile* tt, int x, int y, int z) { - bool changed = true; - - int data = level->getData(x, y, z); - bool isOpen = FenceGateTile::isOpen(data); - int direction = FenceGateTile::getDirection(data); - - const float h00 = 6 / 16.0f; - const float h01 = 9 / 16.0f; - const float h10 = 12 / 16.0f; - const float h11 = 15 / 16.0f; - const float h20 = 5 / 16.0f; - const float h21 = 16 / 16.0f; - - // edge sticks - if (direction == Direction::EAST || direction == Direction::WEST) { - float x0 = 7 / 16.0f; - float x1 = 9 / 16.0f; - float z0 = 0 / 16.0f; - float z1 = 2 / 16.0f; - tt->setShape(x0, h20, z0, x1, h21, z1); - tesselateBlockInWorld(tt, x, y, z); - - z0 = 14 / 16.0f; - z1 = 16 / 16.0f; - tt->setShape(x0, h20, z0, x1, h21, z1); - tesselateBlockInWorld(tt, x, y, z); - } else { - float x0 = 0 / 16.0f; - float x1 = 2 / 16.0f; - float z0 = 7 / 16.0f; - float z1 = 9 / 16.0f; - tt->setShape(x0, h20, z0, x1, h21, z1); - tesselateBlockInWorld(tt, x, y, z); - - x0 = 14 / 16.0f; - x1 = 16 / 16.0f; - tt->setShape(x0, h20, z0, x1, h21, z1); - tesselateBlockInWorld(tt, x, y, z); - } - if (!isOpen) { - if (direction == Direction::EAST || direction == Direction::WEST) { - float x0 = 7 / 16.0f; - float x1 = 9 / 16.0f; - float z0 = 6 / 16.0f; - float z1 = 8 / 16.0f; - tt->setShape(x0, h00, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - z0 = 8 / 16.0f; - z1 = 10 / 16.0f; - tt->setShape(x0, h00, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - z0 = 10 / 16.0f; - z1 = 14 / 16.0f; - tt->setShape(x0, h00, z0, x1, h01, z1); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x0, h10, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - z0 = 2 / 16.0f; - z1 = 6 / 16.0f; - tt->setShape(x0, h00, z0, x1, h01, z1); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x0, h10, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - } else { - float x0 = 6 / 16.0f; - float x1 = 8 / 16.0f; - float z0 = 7 / 16.0f; - float z1 = 9 / 16.0f; - tt->setShape(x0, h00, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - x0 = 8 / 16.0f; - x1 = 10 / 16.0f; - tt->setShape(x0, h00, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - x0 = 10 / 16.0f; - x1 = 14 / 16.0f; - tt->setShape(x0, h00, z0, x1, h01, z1); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x0, h10, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - x0 = 2 / 16.0f; - x1 = 6 / 16.0f; - tt->setShape(x0, h00, z0, x1, h01, z1); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x0, h10, z0, x1, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - - } - } else { - if (direction == Direction::EAST) { - - const float z00 = 0 / 16.0f; - const float z01 = 2 / 16.0f; - const float z10 = 14 / 16.0f; - const float z11 = 16 / 16.0f; - - const float x0 = 9 / 16.0f; - const float x1 = 13 / 16.0f; - const float x2 = 15 / 16.0f; - - tt->setShape(x1, h00, z00, x2, h11, z01); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x1, h00, z10, x2, h11, z11); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x0, h00, z00, x1, h01, z01); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x0, h00, z10, x1, h01, z11); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x0, h10, z00, x1, h11, z01); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x0, h10, z10, x1, h11, z11); - tesselateBlockInWorld(tt, x, y, z); - } else if (direction == Direction::WEST) { - const float z00 = 0 / 16.0f; - const float z01 = 2 / 16.0f; - const float z10 = 14 / 16.0f; - const float z11 = 16 / 16.0f; - - const float x0 = 1 / 16.0f; - const float x1 = 3 / 16.0f; - const float x2 = 7 / 16.0f; - - tt->setShape(x0, h00, z00, x1, h11, z01); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x0, h00, z10, x1, h11, z11); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x1, h00, z00, x2, h01, z01); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x1, h00, z10, x2, h01, z11); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x1, h10, z00, x2, h11, z01); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x1, h10, z10, x2, h11, z11); - tesselateBlockInWorld(tt, x, y, z); - } else if (direction == Direction::SOUTH) { - - const float x00 = 0 / 16.0f; - const float x01 = 2 / 16.0f; - const float x10 = 14 / 16.0f; - const float x11 = 16 / 16.0f; - - const float z0 = 9 / 16.0f; - const float z1 = 13 / 16.0f; - const float z2 = 15 / 16.0f; - - tt->setShape(x00, h00, z1, x01, h11, z2); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x10, h00, z1, x11, h11, z2); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x00, h00, z0, x01, h01, z1); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x10, h00, z0, x11, h01, z1); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x00, h10, z0, x01, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x10, h10, z0, x11, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - } else if (direction == Direction::NORTH) { - const float x00 = 0 / 16.0f; - const float x01 = 2 / 16.0f; - const float x10 = 14 / 16.0f; - const float x11 = 16 / 16.0f; - - const float z0 = 1 / 16.0f; - const float z1 = 3 / 16.0f; - const float z2 = 7 / 16.0f; - - tt->setShape(x00, h00, z0, x01, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x10, h00, z0, x11, h11, z1); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x00, h00, z1, x01, h01, z2); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x10, h00, z1, x11, h01, z2); - tesselateBlockInWorld(tt, x, y, z); - - tt->setShape(x00, h10, z1, x01, h11, z2); - tesselateBlockInWorld(tt, x, y, z); - tt->setShape(x10, h10, z1, x11, h11, z2); - tesselateBlockInWorld(tt, x, y, z); - } - } - - tt->setShape(0, 0, 0, 1, 1, 1); - return changed; -} - -bool TileRenderer::tesselateBedInWorld(Tile *tt, int x, int y, int z) { - Tesselator& t = Tesselator::instance; - int data = level->getData(x, y, z); - int direction = BedTile::getDirection(data); - bool isHead = BedTile::isHeadPiece(data); - - float c10 = 0.5f; - float c11 = 1; - float c2 = 0.8f; - float c3 = 0.6f; - - float r11 = c11; - float g11 = c11; - float b11 = c11; - - float r10 = c10; - float r2 = c2; - float r3 = c3; - - float g10 = c10; - float g2 = c2; - float g3 = c3; - - float b10 = c10; - float b2 = c2; - float b3 = c3; - - float centerBrightness = tt->getBrightness(level, x, y, z); - // render wooden underside - { - t.color(r10 * centerBrightness, g10 * centerBrightness, b10 * centerBrightness); - int tex = tt->getTexture(level, x, y, z, Facing::DOWN); - - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt) / 256.0f; - float u1 = (xt + 16 - 0.01f) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 16 - 0.01f) / 256.0f; - - float x0 = x + tt->xx0; - float x1 = x + tt->xx1; - float y0 = y + tt->yy0 + 3.0f / 16.0f; - float z0 = z + tt->zz0; - float z1 = z + tt->zz1; - - t.vertexUV(x0, y0, z1, u0, v1); - t.vertexUV(x0, y0, z0, u0, v0); - t.vertexUV(x1, y0, z0, u1, v0); - t.vertexUV(x1, y0, z1, u1, v1); - } - - // render bed top - - float brightness = tt->getBrightness(level, x, y + 1, z); - t.color(r11 * brightness, g11 * brightness, b11 * brightness); - - int tex = tt->getTexture(level, x, y, z, Facing::UP); - - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt) / 256.0f; - float u1 = (xt + 16 ) / 256.0f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 16) / 256.0f; - - // Default is west - float topLeftU = u0; - float topRightU = u1; - float topLeftV = v0; - float topRightV = v0; - float bottomLeftU = u0; - float bottomRightU = u1; - float bottomLeftV = v1; - float bottomRightV = v1; - - if (direction == Direction::SOUTH) { - // rotate 90 degrees clockwise - topRightU = u0; - topLeftV = v1; - bottomLeftU = u1; - bottomRightV = v0; - } else if (direction == Direction::NORTH) { - // rotate 90 degrees counter-clockwise - topLeftU = u1; - topRightV = v1; - bottomRightU = u0; - bottomLeftV = v0; - } else if (direction == Direction::EAST) { - // rotate 180 degrees - topLeftU = u1; - topRightV = v1; - bottomRightU = u0; - bottomLeftV = v0; - topRightU = u0; - topLeftV = v1; - bottomLeftU = u1; - bottomRightV = v0; - } - - float x0 = x + tt->xx0; - float x1 = x + tt->xx1; - float y1 = y + tt->yy1; - float z0 = z + tt->zz0; - float z1 = z + tt->zz1; - - t.vertexUV(x1, y1, z1, bottomLeftU, bottomLeftV); - t.vertexUV(x1, y1, z0, topLeftU, topLeftV); - t.vertexUV(x0, y1, z0, topRightU, topRightV); - t.vertexUV(x0, y1, z1, bottomRightU, bottomRightV); - - // determine which edge to skip (the one between foot and head piece) - int skipEdge = Direction::DIRECTION_FACING[direction]; - if (isHead) { - skipEdge = Direction::DIRECTION_FACING[Direction::DIRECTION_OPPOSITE[direction]]; - } - // and which edge to x-flip - int flipEdge = Facing::WEST; - switch (direction) { - case Direction::NORTH: - break; - case Direction::SOUTH: - flipEdge = Facing::EAST; - break; - case Direction::EAST: - flipEdge = Facing::NORTH; - break; - case Direction::WEST: - flipEdge = Facing::SOUTH; - break; - } - - if ((skipEdge != Facing::NORTH) && (noCulling || tt->shouldRenderFace(level, x, y, z - 1, Facing::NORTH))) { - float br = tt->getBrightness(level, x, y, z - 1); - if (tt->zz0 > 0) br = centerBrightness; - - t.color(r2 * br, g2 * br, b2 * br); - xFlipTexture = flipEdge == Facing::NORTH; - renderNorth(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 2)); - } - - if ((skipEdge != Facing::SOUTH) && (noCulling || tt->shouldRenderFace(level, x, y, z + 1, Facing::SOUTH))) { - float br = tt->getBrightness(level, x, y, z + 1); - if (tt->zz1 < 1) br = centerBrightness; - - t.color(r2 * br, g2 * br, b2 * br); - - xFlipTexture = flipEdge == Facing::SOUTH; - renderSouth(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 3)); - } - - if ((skipEdge != Facing::WEST) && (noCulling || tt->shouldRenderFace(level, x - 1, y, z, Facing::WEST))) { - float br = tt->getBrightness(level, x - 1, y, z); - if (tt->xx0 > 0) br = centerBrightness; - - t.color(r3 * br, g3 * br, b3 * br); - xFlipTexture = flipEdge == Facing::WEST; - renderWest(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 4)); - } - - if ((skipEdge != Facing::EAST) && (noCulling || tt->shouldRenderFace(level, x + 1, y, z, Facing::EAST))) { - float br = tt->getBrightness(level, x + 1, y, z); - if (tt->xx1 < 1) br = centerBrightness; - - t.color(r3 * br, g3 * br, b3 * br); - xFlipTexture = flipEdge == Facing::EAST; - renderEast(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 5)); - } - xFlipTexture = false; - return true; -} - -bool TileRenderer::tesselateStairsInWorld( StairTile* tt, int x, int y, int z ) -{ - - tt->setBaseShape(level, x, y, z); - tesselateBlockInWorld(tt, x, y, z); - - bool checkInnerPiece = tt->setStepShape(level, x, y, z); - tesselateBlockInWorld(tt, x, y, z); - - if (checkInnerPiece) { - if (tt->setInnerPieceShape(level, x, y, z)) { - tesselateBlockInWorld(tt, x, y, z); - } - } - - // setShape(0, 0, 0, 1, 1, 1); - return true; -} - -bool TileRenderer::tesselateDoorInWorld( Tile* tt, int x, int y, int z ) -{ - Tesselator& t = Tesselator::instance; - - DoorTile* dt = (DoorTile*) tt; - - bool changed = false; - float c10 = 0.5f; - float c11 = 1; - float c2 = 0.8f; - float c3 = 0.6f; - - float centerBrightness = tt->getBrightness(level, x, y, z); - - { - float br = tt->getBrightness(level, x, y - 1, z); - if (dt->yy0 > 0) br = centerBrightness; - if (Tile::lightEmission[tt->id] > 0) br = 1.0f; - t.color(c10 * br, c10 * br, c10 * br); - renderFaceDown(tt, (float)x, (float)y, (float)z, tt->getTexture(level, x, y, z, 0)); - changed = true; - } - - { - float br = tt->getBrightness(level, x, y + 1, z); - if (dt->yy1 < 1) br = centerBrightness; - if (Tile::lightEmission[tt->id] > 0) br = 1.0f; - t.color(c11 * br, c11 * br, c11 * br); - renderFaceUp(tt, (float)x, (float)y, (float)z, tt->getTexture(level, x, y, z, 1)); - changed = true; - } - - { - float br = tt->getBrightness(level, x, y, z - 1); - if (dt->zz0 > 0) br = centerBrightness; - if (Tile::lightEmission[tt->id] > 0) br = 1.0f; - t.color(c2 * br, c2 * br, c2 * br); - int tex = tt->getTexture(level, x, y, z, 2); - if (tex < 0) { - xFlipTexture = true; - tex = -tex; - } - renderNorth(tt, (float)x, (float)y, (float)z, tex); - changed = true; - xFlipTexture = false; - } - - { - float br = tt->getBrightness(level, x, y, z + 1); - if (dt->zz1 < 1) br = centerBrightness; - if (Tile::lightEmission[tt->id] > 0) br = 1.0f; - t.color(c2 * br, c2 * br, c2 * br); - int tex = tt->getTexture(level, x, y, z, 3); - if (tex < 0) { - xFlipTexture = true; - tex = -tex; - } - renderSouth(tt, (float)x, (float)y, (float)z, tex); - changed = true; - xFlipTexture = false; - } - - { - float br = tt->getBrightness(level, x - 1, y, z); - if (dt->xx0 > 0) br = centerBrightness; - if (Tile::lightEmission[tt->id] > 0) br = 1.0f; - t.color(c3 * br, c3 * br, c3 * br); - int tex = tt->getTexture(level, x, y, z, 4); - if (tex < 0) { - xFlipTexture = true; - tex = -tex; - } - renderWest(tt, (float)x, (float)y, (float)z, tex); - changed = true; - xFlipTexture = false; - } - - { - float br = tt->getBrightness(level, x + 1, y, z); - if (dt->xx1 < 1) br = centerBrightness; - if (Tile::lightEmission[tt->id] > 0) br = 1.0f; - t.color(c3 * br, c3 * br, c3 * br); - int tex = tt->getTexture(level, x, y, z, 5); - if (tex < 0) { - xFlipTexture = true; - tex = -tex; - } - renderEast(tt, (float)x, (float)y, (float)z, tex); - changed = true; - xFlipTexture = false; - } - - return changed; -} - -bool TileRenderer::tesselateRowInWorld( Tile* tt, int x, int y, int z ) { - Tesselator& t = Tesselator::instance; - float br = tt->getBrightness(level, x, y, z); - t.color(br, br, br); - tesselateRowTexture(tt, level->getData(x, y, z), float(x), y - 1 / 16.0f, float(z)); - return true; -} - -void TileRenderer::renderFaceDown( Tile* tt, float x, float y, float z, int tex ) -{ - Tesselator& t = Tesselator::instance; - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt + tt->xx0 * 16) / 256.0f; - float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; - float v0 = (yt + tt->zz0 * 16) / 256.0f; - float v1 = (yt + tt->zz1 * 16 - 0.01f) / 256.0f; - - if (tt->xx0 < 0 || tt->xx1 > 1) { - u0 = (xt + 0 * 15.99f) / 256.0f; - u1 = (xt + 1 * 15.99f) / 256.0f; - } - if (tt->zz0 < 0 || tt->zz1 > 1) { - v0 = (yt + 0 * 15.99f) / 256.0f; - v1 = (yt + 1 * 15.99f) / 256.0f; - } - - float x0 = x + tt->xx0; - float x1 = x + tt->xx1; - float y0 = y + tt->yy0; - float z0 = z + tt->zz0; - float z1 = z + tt->zz1; - - if (applyAmbienceOcclusion) { - t.color(c1r, c1g, c1b); - t.vertexUV(x0, y0, z1, u0, v1); - t.color(c2r, c2g, c2b); - t.vertexUV(x0, y0, z0, u0, v0); - t.color(c3r, c3g, c3b); - t.vertexUV(x1, y0, z0, u1, v0); - t.color(c4r, c4g, c4b); - t.vertexUV(x1, y0, z1, u1, v1); - } else { - t.vertexUV(x0, y0, z1, u0, v1); - t.vertexUV(x0, y0, z0, u0, v0); - t.vertexUV(x1, y0, z0, u1, v0); - t.vertexUV(x1, y0, z1, u1, v1); - } -} - -void TileRenderer::renderFaceUp( Tile* tt, float x, float y, float z, int tex ) -{ - Tesselator& t = Tesselator::instance; - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt + tt->xx0 * 16) / 256.0f; - float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; - float v0 = (yt + tt->zz0 * 16) / 256.0f; - float v1 = (yt + tt->zz1 * 16 - 0.01f) / 256.0f; - - if (tt->xx0 < 0 || tt->xx1 > 1) { - u0 = (xt + 0 * 15.99f) / 256.0f; - u1 = (xt + 1 * 15.99f) / 256.0f; - } - if (tt->zz0 < 0 || tt->zz1 > 1) { - v0 = (yt + 0 * 15.99f) / 256.0f; - v1 = (yt + 1 * 15.99f) / 256.0f; - } - - float x0 = x + tt->xx0; - float x1 = x + tt->xx1; - float y1 = y + tt->yy1; - float z0 = z + tt->zz0; - float z1 = z + tt->zz1; - - if (applyAmbienceOcclusion) { - t.color(c1r, c1g, c1b); - t.vertexUV(x1, y1, z1, u1, v1); - t.color(c2r, c2g, c2b); - t.vertexUV(x1, y1, z0, u1, v0); - t.color(c3r, c3g, c3b); - t.vertexUV(x0, y1, z0, u0, v0); - t.color(c4r, c4g, c4b); - t.vertexUV(x0, y1, z1, u0, v1); - } else { - t.vertexUV(x1, y1, z1, u1, v1); - t.vertexUV(x1, y1, z0, u1, v0); - t.vertexUV(x0, y1, z0, u0, v0); - t.vertexUV(x0, y1, z1, u0, v1); - } -} - -void TileRenderer::renderNorth( Tile* tt, float x, float y, float z, int tex ) -{ - Tesselator& t = Tesselator::instance; - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - float u0 = (xt + tt->xx0 * 16) / 256.0f; - float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; - float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; - float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; - if (xFlipTexture) { - float tmp = u0; - u0 = u1; - u1 = tmp; - } - - if (tt->xx0 < 0 || tt->xx1 > 1) { - u0 = (xt + 0 * 15.99f) / 256.0f; - u1 = (xt + 1 * 15.99f) / 256.0f; - } - if (tt->yy0 < 0 || tt->yy1 > 1) { - v0 = (yt + 0 * 15.99f) / 256.0f; - v1 = (yt + 1 * 15.99f) / 256.0f; - } - - float x0 = x + tt->xx0; - float x1 = x + tt->xx1; - float y0 = y + tt->yy0; - float y1 = y + tt->yy1; - float z0 = z + tt->zz0; - - if (applyAmbienceOcclusion) { - t.color(c1r, c1g, c1b); - t.vertexUV(x0, y1, z0, u1, v0); - t.color(c2r, c2g, c2b); - t.vertexUV(x1, y1, z0, u0, v0); - t.color(c3r, c3g, c3b); - t.vertexUV(x1, y0, z0, u0, v1); - t.color(c4r, c4g, c4b); - t.vertexUV(x0, y0, z0, u1, v1); - } else { - t.vertexUV(x0, y1, z0, u1, v0); - t.vertexUV(x1, y1, z0, u0, v0); - t.vertexUV(x1, y0, z0, u0, v1); - t.vertexUV(x0, y0, z0, u1, v1); - } -} - -void TileRenderer::renderSouth( Tile* tt, float x, float y, float z, int tex ) -{ - Tesselator& t = Tesselator::instance; - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt + tt->xx0 * 16) / 256.0f; - float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; - float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; - float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; - if (xFlipTexture) { - float tmp = u0; - u0 = u1; - u1 = tmp; - } - - if (tt->xx0 < 0 || tt->xx1 > 1) { - u0 = (xt + 0 * 15.99f) / 256.0f; - u1 = (xt + 1 * 15.99f) / 256.0f; - } - if (tt->yy0 < 0 || tt->yy1 > 1) { - v0 = (yt + 0 * 15.99f) / 256.0f; - v1 = (yt + 1 * 15.99f) / 256.0f; - } - - float x0 = x + tt->xx0; - float x1 = x + tt->xx1; - float y0 = y + tt->yy0; - float y1 = y + tt->yy1; - float z1 = z + tt->zz1; - - if (applyAmbienceOcclusion) { - t.color(c1r, c1g, c1b); - t.vertexUV(x0, y1, z1, u0, v0); - t.color(c2r, c2g, c2b); - t.vertexUV(x0, y0, z1, u0, v1); - t.color(c3r, c3g, c3b); - t.vertexUV(x1, y0, z1, u1, v1); - t.color(c4r, c4g, c4b); - t.vertexUV(x1, y1, z1, u1, v0); - } else { - t.vertexUV(x0, y1, z1, u0, v0); - t.vertexUV(x0, y0, z1, u0, v1); - t.vertexUV(x1, y0, z1, u1, v1); - t.vertexUV(x1, y1, z1, u1, v0); - } -} - -void TileRenderer::renderWest( Tile* tt, float x, float y, float z, int tex ) -{ - Tesselator& t = Tesselator::instance; - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt + tt->zz0 * 16) / 256.0f; - float u1 = (xt + tt->zz1 * 16 - 0.01f) / 256.0f; - float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; - float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; - if (xFlipTexture) { - float tmp = u0; - u0 = u1; - u1 = tmp; - } - - if (tt->zz0 < 0 || tt->zz1 > 1) { - u0 = (xt + 0 * 15.99f) / 256.0f; - u1 = (xt + 1 * 15.99f) / 256.0f; - } - if (tt->yy0 < 0 || tt->yy1 > 1) { - v0 = (yt + 0 * 15.99f) / 256.0f; - v1 = (yt + 1 * 15.99f) / 256.0f; - } - - float x0 = x + tt->xx0; - float y0 = y + tt->yy0; - float y1 = y + tt->yy1; - float z0 = z + tt->zz0; - float z1 = z + tt->zz1; - - if (applyAmbienceOcclusion) { - t.color(c1r, c1g, c1b); - t.vertexUV(x0, y1, z1, u1, v0); - t.color(c2r, c2g, c2b); - t.vertexUV(x0, y1, z0, u0, v0); - t.color(c3r, c3g, c3b); - t.vertexUV(x0, y0, z0, u0, v1); - t.color(c4r, c4g, c4b); - t.vertexUV(x0, y0, z1, u1, v1); - } else { - t.vertexUV(x0, y1, z1, u1, v0); - t.vertexUV(x0, y1, z0, u0, v0); - t.vertexUV(x0, y0, z0, u0, v1); - t.vertexUV(x0, y0, z1, u1, v1); - } -} - -void TileRenderer::renderEast( Tile* tt, float x, float y, float z, int tex ) -{ - Tesselator& t = Tesselator::instance; - - if (fixedTexture >= 0) tex = fixedTexture; - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - - float u0 = (xt + tt->zz0 * 16) / 256.0f; - float u1 = (xt + tt->zz1 * 16 - 0.01f) / 256.0f; - float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; - float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; - if (xFlipTexture) { - float tmp = u0; - u0 = u1; - u1 = tmp; - } - - if (tt->zz0 < 0 || tt->zz1 > 1) { - u0 = (xt + 0 * 15.99f) / 256.0f; - u1 = (xt + 1 * 15.99f) / 256.0f; - } - if (tt->yy0 < 0 || tt->yy1 > 1) { - v0 = (yt + 0 * 15.99f) / 256.0f; - v1 = (yt + 1 * 15.99f) / 256.0f; - } - - float x1 = x + tt->xx1; - float y0 = y + tt->yy0; - float y1 = y + tt->yy1; - float z0 = z + tt->zz0; - float z1 = z + tt->zz1; - - if (applyAmbienceOcclusion) { - t.color(c1r, c1g, c1b); - t.vertexUV(x1, y0, z1, u0, v1); - t.color(c2r, c2g, c2b); - t.vertexUV(x1, y0, z0, u1, v1); - t.color(c3r, c3g, c3b); - t.vertexUV(x1, y1, z0, u1, v0); - t.color(c4r, c4g, c4b); - t.vertexUV(x1, y1, z1, u0, v0); - } else { - t.vertexUV(x1, y0, z1, u0, v1); - t.vertexUV(x1, y0, z0, u1, v1); - t.vertexUV(x1, y1, z0, u1, v0); - t.vertexUV(x1, y1, z1, u0, v0); - } -} - -void TileRenderer::renderTile( Tile* tile, int data ) -{ - Tesselator& t = Tesselator::instance; - - t.color(0xff, 0xff, 0xff); - int shape = tile->getRenderShape(); - - if (shape == Tile::SHAPE_BLOCK) { - tile->updateDefaultShape(); - t.addOffset(-0.5f, -0.5f, -0.5f); - t.begin(); - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0, data)); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1, data)); - renderNorth(tile, 0, 0, 0, tile->getTexture(2, data)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3, data)); - renderWest(tile, 0, 0, 0, tile->getTexture(4, data)); - renderEast(tile, 0, 0, 0, tile->getTexture(5, data)); - t.draw(); - - t.addOffset(0.5f, 0.5f, 0.5f); - - } else if (shape == Tile::SHAPE_CROSS_TEXTURE) { - t.begin(); - tesselateCrossTexture(tile, data, -0.5f, -0.5f, -0.5f); - t.draw(); - } else if(shape == Tile::SHAPE_STEM) { - t.begin(); - tile->updateDefaultShape(); - tesselateStemTexture(tile, data, tile->yy1, -0.5f, -0.5f, -0.5f); - t.draw(); - } else if (shape == Tile::SHAPE_CACTUS) { - tile->updateDefaultShape(); - t.offset(-0.5f, -0.5f, -0.5f); - float s = 1 / 16.0f; - t.begin(); - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); - t.addOffset(0, 0, s); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - t.addOffset(0, 0, -s); - t.addOffset(0, 0, -s); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - t.addOffset(0, 0, s); - t.addOffset(s, 0, 0); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - t.addOffset(-s, 0, 0); - t.addOffset(-s, 0, 0); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - t.addOffset(s, 0, 0); - t.draw(); - t.offset(0, 0, 0);//0.5f, 0.5f, 0.5f); - } else if (shape == Tile::SHAPE_ROWS) { - t.begin(); - t.normal(0, -1, 0); - tesselateRowTexture(tile, data, -0.5f, -0.5f, -0.5f); - //} else if (shape == Tile::SHAPE_TORCH) { - //// t.begin(); - //// t.normal(0, -1, 0); - //// tesselateTorch(tile, -0.5f, -0.5f, -0.5f, 0, 0); - //// t.end(); - } else if (shape == Tile::SHAPE_ENTITYTILE_ANIMATED) { - EntityTileRenderer::instance->render(tile, data, 1.0f); - //glEnable(GL_RESCALE_NORMAL); - } else if (shape == Tile::SHAPE_STAIRS) { - t.addOffset(-0.5f, -0.5f, -0.5f); - t.begin(); - for (int i = 0; i < 2; i++) { - if (i == 0) tile->setShape(0, 0, 0, 1, 1, 0.5f); - if (i == 1) tile->setShape(0, 0, 0.5f, 1, 0.5f, 1); - - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - } - t.draw(); - t.addOffset(0.5f, 0.5f, 0.5f); - } - else if (shape == Tile::SHAPE_FENCE) { - t.addOffset(-0.5f, -0.5f, -0.5f); - t.begin(); - for (int i = 0; i < 4; i++) { - float w = 2 / 16.0f; - if (i == 0) tile->setShape(0.5f - w, 0, 0, 0.5f + w, 1, w * 2); - if (i == 1) tile->setShape(0.5f - w, 0, 1 - w * 2, 0.5f + w, 1, 1); - w = 1 / 16.0f; - if (i == 2) tile->setShape(0.5f - w, 1 - w * 3, -w * 2, 0.5f + w, 1 - w, 1 + w * 2); - if (i == 3) tile->setShape(0.5f - w, 0.5f - w * 3, -w * 2, 0.5f + w, 0.5f - w, 1 + w * 2); - - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - } - t.draw(); - t.addOffset(0.5f, 0.5f, 0.5f); - tile->setShape(0, 0, 0, 1, 1, 1); - } else if (shape == Tile::SHAPE_FENCE_GATE) { - t.addOffset(-0.5f, -0.5f, -0.5f); - t.begin(); - for (int i = 0; i < 3; i++) { - float w = 1 / 16.0f; - if (i == 0) tile->setShape(0.5f - w, .3f, 0, 0.5f + w, 1, w * 2); - if (i == 1) tile->setShape(0.5f - w, .3f, 1 - w * 2, 0.5f + w, 1, 1); - if (i == 2) tile->setShape(0.5f - w, .5f, w * 2, 0.5f + w, 1 - w, 1 - w * 2); - - renderFaceUp(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceDown(tile, 0, 0, 0, tile->getTexture(1)); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - } - t.draw(); - t.addOffset(0.5f, 0.5f, 0.5f); - tile->setShape(0, 0, 0, 1, 1, 1); - } - -} - -bool TileRenderer::canRender( int renderShape ) -{ - if (renderShape == Tile::SHAPE_BLOCK) return true; - if (renderShape == Tile::SHAPE_CACTUS) return true; - if (renderShape == Tile::SHAPE_STAIRS) return true; - if (renderShape == Tile::SHAPE_FENCE) return true; - if (renderShape == Tile::SHAPE_FENCE_GATE) return true; - //if (renderShape == Tile::SHAPE_CROSS_TEXTURE) return true; - //if (renderShape == Tile::SHAPE_ENTITYTILE_ANIMATED) return true; - - return false; -} - -void TileRenderer::renderGuiTile( Tile* tile, int data ) -{ - Tesselator& t = Tesselator::instance; - - int shape = tile->getRenderShape(); - - if (shape == Tile::SHAPE_BLOCK) { - tile->updateDefaultShape(); - - t.begin(); - t.addOffset(-0.5f, -0.5f, -0.5f); - t.color(0xff, 0xff, 0xff); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1, data)); - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0, data)); - - t.color(0x80, 0x80, 0x80); - renderNorth(tile, 0, 0, 0, tile->getTexture(2, data)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3, data)); - - t.color(0xbb, 0xbb, 0xbb); - renderEast(tile, 0, 0, 0, tile->getTexture(5, data)); - renderWest(tile, 0, 0, 0, tile->getTexture(4, data)); - t.draw(); - t.addOffset(0.5f, 0.5f, 0.5f); - - } else if (shape == Tile::SHAPE_CROSS_TEXTURE) { - t.begin(); - //t.normal(0, -1, 0); - tesselateCrossTexture(tile, data, -0.5f, -0.5f, -0.5f); - //t.end(); - t.draw(); - } else if (shape == Tile::SHAPE_CACTUS) { - tile->updateDefaultShape(); - t.begin(); - t.offset(-0.5f, -0.5f, -0.5f); - float s = 1 / 16.0f; - t.color(0xff, 0xff, 0xff); - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); - - t.color(0x80, 0x80, 0x80); - t.addOffset(0, 0, s); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - t.addOffset(0, 0, -s-s); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - - t.color(0xbb, 0xbb, 0xbb); - t.addOffset(s, 0, s); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - t.addOffset(-s-s, 0, 0); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - - t.draw(); - t.addOffset(s+0.5f, 0.5f, 0.5f); - } else if (shape == Tile::SHAPE_STAIRS) { - t.offset(-0.5f, -0.5f, -0.5f); - t.begin(); - for (int i = 0; i < 2; i++) { - if (i == 0) tile->setShape(0, 0, 0, 1, 1, 0.5f); - if (i == 1) tile->setShape(0, 0, 0.5f, 1, 0.5f, 1); - - t.color(0xff, 0xff, 0xff); - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); - - t.color(0x80, 0x80, 0x80); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - - t.color(0xbb, 0xbb, 0xbb); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - } - t.draw(); - t.offset(0, 0, 0); - } - else if (shape == Tile::SHAPE_FENCE) { - t.addOffset(-0.5f, -0.5f, -0.5f); - t.begin(); - for (int i = 0; i < 4; i++) { - float w = 2 / 16.0f; - if (i == 0) tile->setShape(0.5f - w, 0, 0, 0.5f + w, 1, w * 2); - if (i == 1) tile->setShape(0.5f - w, 0, 1 - w * 2, 0.5f + w, 1, 1); - w = 1 / 16.0f; - if (i == 2) tile->setShape(0.5f - w, 1 - w * 3, -w * 2, 0.5f + w, 1 - w, 1 + w * 2); - if (i == 3) tile->setShape(0.5f - w, 0.5f - w * 3, -w * 2, 0.5f + w, 0.5f - w, 1 + w * 2); - - t.color(0xff, 0xff, 0xff); - - renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); - - t.color(0x80, 0x80, 0x80); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - - t.color(0xbb, 0xbb, 0xbb); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - } - t.draw(); - t.addOffset(0.5f, 0.5f, 0.5f); - tile->setShape(0, 0, 0, 1, 1, 1); - } - else if (shape == Tile::SHAPE_FENCE_GATE) { - t.addOffset(-0.5f, -0.5f, -0.5f); - t.begin(); - for (int i = 0; i < 3; i++) { - float w = 1 / 16.0f; - if (i == 0) tile->setShape(0.5f - w, .3f, 0, 0.5f + w, 1, w * 2); - if (i == 1) tile->setShape(0.5f - w, .3f, 1 - w * 2, 0.5f + w, 1, 1); - w = 1 / 16.0f; - if (i == 2) tile->setShape(0.5f - w, .5f, 0, 0.5f + w, 1 - w, 1); - - t.color(0xff, 0xff, 0xff); - renderFaceUp(tile, 0, 0, 0, tile->getTexture(0)); - renderFaceDown(tile, 0, 0, 0, tile->getTexture(1)); - - t.color(0x80, 0x80, 0x80); - renderNorth(tile, 0, 0, 0, tile->getTexture(2)); - renderSouth(tile, 0, 0, 0, tile->getTexture(3)); - - t.color(0xbb, 0xbb, 0xbb); - renderWest(tile, 0, 0, 0, tile->getTexture(4)); - renderEast(tile, 0, 0, 0, tile->getTexture(5)); - } - t.draw(); - tile->setShape(0, 0, 0, 1, 1, 1); - t.addOffset(0.5f, 0.5f, 0.5f); - } -} - -bool TileRenderer::tesselateThinFenceInWorld(ThinFenceTile* tt, int x, int y, int z) { - const int depth = 128; - Tesselator& t = Tesselator::instance; - - float br = tt->getBrightness(level, x, y, z); - int col = tt->getColor(level, x, y, z); - float r = ((col >> 16) & 0xff) / 255.0f; - float g = ((col >> 8) & 0xff) / 255.0f; - float b = ((col) & 0xff) / 255.0f; - - //if (GameRenderer::anaglyph3d) { - // float cr = (r * 30 + g * 59 + b * 11) / 100; - // float cg = (r * 30 + g * 70) / (100); - // float cb = (r * 30 + b * 70) / (100); - - // r = cr; - // g = cg; - // b = cb; - //} - t.color(br * r, br * g, br * b); - - int tex = 0; - int edgeTex = 0; - - if (fixedTexture >= 0) { - tex = fixedTexture; - edgeTex = fixedTexture; - } else { - int data = level->getData(x, y, z); - tex = tt->getTexture(0, data); - edgeTex = tt->getEdgeTexture(); - } - - const int xt = (tex & 0xf) << 4; - const int yt = tex & 0xf0; - float u0 = (xt) / 256.0f; - const float u1 = (xt + 7.99f) / 256.0f; - const float u2 = (xt + 15.99f) / 256.0f; - const float v0 = (yt) / 256.0f; - const float v2 = (yt + 15.99f) / 256.0f; - - const int xet = (edgeTex & 0xf) << 4; - const int yet = edgeTex & 0xf0; - - const float iu0 = (xet + 7) / 256.0f; - const float iu1 = (xet + 8.99f) / 256.0f; - const float iv0 = (yet) / 256.0f; - const float iv1 = (yet + 8) / 256.0f; - const float iv2 = (yet + 15.99f) / 256.0f; - - const float x0 = (float)x; - const float x1 = x0 + .5f; - const float x2 = x0 + 1; - const float y0 = (float)y + 0.001f; - const float y1 = y0 + 1 - 0.002f; - const float z0 = (float)z; - const float z1 = z0 + .5f; - const float z2 = z0 + 1; - const float ix0 = x0 + .5f - 1.0f / 16.0f; - const float ix1 = x0 + .5f + 1.0f / 16.0f; - const float iz0 = z0 + .5f - 1.0f / 16.0f; - const float iz1 = z0 + .5f + 1.0f / 16.0f; - - const bool n = tt->attachsTo(level->getTile(x, y, z - 1)); - const bool s = tt->attachsTo(level->getTile(x, y, z + 1)); - const bool w = tt->attachsTo(level->getTile(x - 1, y, z)); - const bool e = tt->attachsTo(level->getTile(x + 1, y, z)); - - const bool up = tt->shouldRenderFace(level, x, y + 1, z, Facing::UP); - const bool down = tt->shouldRenderFace(level, x, y - 1, z, Facing::DOWN); - - const float noZFightingOffset = 0.01f; - - if ((w && e) || (!w && !e && !n && !s)) { - t.vertexUV(x0, y1, z1, u0, v0); - t.vertexUV(x0, y0, z1, u0, v2); - t.vertexUV(x2, y0, z1, u2, v2); - t.vertexUV(x2, y1, z1, u2, v0); - - t.vertexUV(x2, y1, z1, u0, v0); - t.vertexUV(x2, y0, z1, u0, v2); - t.vertexUV(x0, y0, z1, u2, v2); - t.vertexUV(x0, y1, z1, u2, v0); - - if (up) { - // small edge texture - t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv0); - t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv2); - - t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv0); - t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv2); - } else { - if (y < (depth - 1) && level->isEmptyTile(x - 1, y + 1, z)) { - t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv1); - - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); - } - if (y < (depth - 1) && level->isEmptyTile(x + 1, y + 1, z)) { - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv0); - - t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv0); - } - } - if (down) { - // small edge texture - t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv0); - t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv2); - - t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv0); - t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv2); - } else { - if (y > 1 && level->isEmptyTile(x - 1, y - 1, z)) { - t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv1); - - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); - } - if (y > 1 && level->isEmptyTile(x + 1, y - 1, z)) { - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv0); - - t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv0); - } - } - - } else if (w && !e) { - // half-step towards west - t.vertexUV(x0, y1, z1, u0, v0); - t.vertexUV(x0, y0, z1, u0, v2); - t.vertexUV(x1, y0, z1, u1, v2); - t.vertexUV(x1, y1, z1, u1, v0); - - t.vertexUV(x1, y1, z1, u0, v0); - t.vertexUV(x1, y0, z1, u0, v2); - t.vertexUV(x0, y0, z1, u1, v2); - t.vertexUV(x0, y1, z1, u1, v0); - - // small edge texture - if (!s && !n) { - t.vertexUV(x1, y1, iz1, iu0, iv0); - t.vertexUV(x1, y0, iz1, iu0, iv2); - t.vertexUV(x1, y0, iz0, iu1, iv2); - t.vertexUV(x1, y1, iz0, iu1, iv0); - - t.vertexUV(x1, y1, iz0, iu0, iv0); - t.vertexUV(x1, y0, iz0, iu0, iv2); - t.vertexUV(x1, y0, iz1, iu1, iv2); - t.vertexUV(x1, y1, iz1, iu1, iv0); - } - - if (up || (y < (depth - 1) && level->isEmptyTile(x - 1, y + 1, z))) { - // small edge texture - t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv1); - - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); - } - if (down || (y > 1 && level->isEmptyTile(x - 1, y - 1, z))) { - // small edge texture - t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv1); - - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv2); - t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv2); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); - } - - } else if (!w && e) { - // half-step towards east - t.vertexUV(x1, y1, z1, u1, v0); - t.vertexUV(x1, y0, z1, u1, v2); - t.vertexUV(x2, y0, z1, u2, v2); - t.vertexUV(x2, y1, z1, u2, v0); - - t.vertexUV(x2, y1, z1, u1, v0); - t.vertexUV(x2, y0, z1, u1, v2); - t.vertexUV(x1, y0, z1, u2, v2); - t.vertexUV(x1, y1, z1, u2, v0); - - // small edge texture - if (!s && !n) { - t.vertexUV(x1, y1, iz0, iu0, iv0); - t.vertexUV(x1, y0, iz0, iu0, iv2); - t.vertexUV(x1, y0, iz1, iu1, iv2); - t.vertexUV(x1, y1, iz1, iu1, iv0); - - t.vertexUV(x1, y1, iz1, iu0, iv0); - t.vertexUV(x1, y0, iz1, iu0, iv2); - t.vertexUV(x1, y0, iz0, iu1, iv2); - t.vertexUV(x1, y1, iz0, iu1, iv0); - } - - if (up || (y < (depth - 1) && level->isEmptyTile(x + 1, y + 1, z))) { - // small edge texture - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv0); - - t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv0); - } - if (down || (y > 1 && level->isEmptyTile(x + 1, y - 1, z))) { - // small edge texture - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv0); - - t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv0); - t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); - t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); - t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv0); - } - - } - - if ((n && s) || (!w && !e && !n && !s)) { - // straight north-south - t.vertexUV(x1, y1, z2, u0, v0); - t.vertexUV(x1, y0, z2, u0, v2); - t.vertexUV(x1, y0, z0, u2, v2); - t.vertexUV(x1, y1, z0, u2, v0); - - t.vertexUV(x1, y1, z0, u0, v0); - t.vertexUV(x1, y0, z0, u0, v2); - t.vertexUV(x1, y0, z2, u2, v2); - t.vertexUV(x1, y1, z2, u2, v0); - - if (up) { - // small edge texture - t.vertexUV(ix1, y1, z2, iu1, iv2); - t.vertexUV(ix1, y1, z0, iu1, iv0); - t.vertexUV(ix0, y1, z0, iu0, iv0); - t.vertexUV(ix0, y1, z2, iu0, iv2); - - t.vertexUV(ix1, y1, z0, iu1, iv2); - t.vertexUV(ix1, y1, z2, iu1, iv0); - t.vertexUV(ix0, y1, z2, iu0, iv0); - t.vertexUV(ix0, y1, z0, iu0, iv2); - } else { - if (y < (depth - 1) && level->isEmptyTile(x, y + 1, z - 1)) { - t.vertexUV(ix0, y1, z0, iu1, iv0); - t.vertexUV(ix0, y1, z1, iu1, iv1); - t.vertexUV(ix1, y1, z1, iu0, iv1); - t.vertexUV(ix1, y1, z0, iu0, iv0); - - t.vertexUV(ix0, y1, z1, iu1, iv0); - t.vertexUV(ix0, y1, z0, iu1, iv1); - t.vertexUV(ix1, y1, z0, iu0, iv1); - t.vertexUV(ix1, y1, z1, iu0, iv0); - } - if (y < (depth - 1) && level->isEmptyTile(x, y + 1, z + 1)) { - t.vertexUV(ix0, y1, z1, iu0, iv1); - t.vertexUV(ix0, y1, z2, iu0, iv2); - t.vertexUV(ix1, y1, z2, iu1, iv2); - t.vertexUV(ix1, y1, z1, iu1, iv1); - - t.vertexUV(ix0, y1, z2, iu0, iv1); - t.vertexUV(ix0, y1, z1, iu0, iv2); - t.vertexUV(ix1, y1, z1, iu1, iv2); - t.vertexUV(ix1, y1, z2, iu1, iv1); - } - } - if (down) { - // small edge texture - t.vertexUV(ix1, y0, z2, iu1, iv2); - t.vertexUV(ix1, y0, z0, iu1, iv0); - t.vertexUV(ix0, y0, z0, iu0, iv0); - t.vertexUV(ix0, y0, z2, iu0, iv2); - - t.vertexUV(ix1, y0, z0, iu1, iv2); - t.vertexUV(ix1, y0, z2, iu1, iv0); - t.vertexUV(ix0, y0, z2, iu0, iv0); - t.vertexUV(ix0, y0, z0, iu0, iv2); - } else { - if (y > 1 && level->isEmptyTile(x, y - 1, z - 1)) { - // north half-step - t.vertexUV(ix0, y0, z0, iu1, iv0); - t.vertexUV(ix0, y0, z1, iu1, iv1); - t.vertexUV(ix1, y0, z1, iu0, iv1); - t.vertexUV(ix1, y0, z0, iu0, iv0); - - t.vertexUV(ix0, y0, z1, iu1, iv0); - t.vertexUV(ix0, y0, z0, iu1, iv1); - t.vertexUV(ix1, y0, z0, iu0, iv1); - t.vertexUV(ix1, y0, z1, iu0, iv0); - } - if (y > 1 && level->isEmptyTile(x, y - 1, z + 1)) { - // south half-step - t.vertexUV(ix0, y0, z1, iu0, iv1); - t.vertexUV(ix0, y0, z2, iu0, iv2); - t.vertexUV(ix1, y0, z2, iu1, iv2); - t.vertexUV(ix1, y0, z1, iu1, iv1); - - t.vertexUV(ix0, y0, z2, iu0, iv1); - t.vertexUV(ix0, y0, z1, iu0, iv2); - t.vertexUV(ix1, y0, z1, iu1, iv2); - t.vertexUV(ix1, y0, z2, iu1, iv1); - } - } - - } else if (n && !s) { - // half-step towards north - t.vertexUV(x1, y1, z0, u0, v0); - t.vertexUV(x1, y0, z0, u0, v2); - t.vertexUV(x1, y0, z1, u1, v2); - t.vertexUV(x1, y1, z1, u1, v0); - - t.vertexUV(x1, y1, z1, u0, v0); - t.vertexUV(x1, y0, z1, u0, v2); - t.vertexUV(x1, y0, z0, u1, v2); - t.vertexUV(x1, y1, z0, u1, v0); - - // small edge texture - if (!e && !w) { - t.vertexUV(ix0, y1, z1, iu0, iv0); - t.vertexUV(ix0, y0, z1, iu0, iv2); - t.vertexUV(ix1, y0, z1, iu1, iv2); - t.vertexUV(ix1, y1, z1, iu1, iv0); - - t.vertexUV(ix1, y1, z1, iu0, iv0); - t.vertexUV(ix1, y0, z1, iu0, iv2); - t.vertexUV(ix0, y0, z1, iu1, iv2); - t.vertexUV(ix0, y1, z1, iu1, iv0); - } - - if (up || (y < (depth - 1) && level->isEmptyTile(x, y + 1, z - 1))) { - // small edge texture - t.vertexUV(ix0, y1, z0, iu1, iv0); - t.vertexUV(ix0, y1, z1, iu1, iv1); - t.vertexUV(ix1, y1, z1, iu0, iv1); - t.vertexUV(ix1, y1, z0, iu0, iv0); - - t.vertexUV(ix0, y1, z1, iu1, iv0); - t.vertexUV(ix0, y1, z0, iu1, iv1); - t.vertexUV(ix1, y1, z0, iu0, iv1); - t.vertexUV(ix1, y1, z1, iu0, iv0); - } - - if (down || (y > 1 && level->isEmptyTile(x, y - 1, z - 1))) { - // small edge texture - t.vertexUV(ix0, y0, z0, iu1, iv0); - t.vertexUV(ix0, y0, z1, iu1, iv1); - t.vertexUV(ix1, y0, z1, iu0, iv1); - t.vertexUV(ix1, y0, z0, iu0, iv0); - - t.vertexUV(ix0, y0, z1, iu1, iv0); - t.vertexUV(ix0, y0, z0, iu1, iv1); - t.vertexUV(ix1, y0, z0, iu0, iv1); - t.vertexUV(ix1, y0, z1, iu0, iv0); - } - - } else if (!n && s) { - // half-step towards south - t.vertexUV(x1, y1, z1, u1, v0); - t.vertexUV(x1, y0, z1, u1, v2); - t.vertexUV(x1, y0, z2, u2, v2); - t.vertexUV(x1, y1, z2, u2, v0); - - t.vertexUV(x1, y1, z2, u1, v0); - t.vertexUV(x1, y0, z2, u1, v2); - t.vertexUV(x1, y0, z1, u2, v2); - t.vertexUV(x1, y1, z1, u2, v0); - - // small edge texture - if (!e && !w) { - t.vertexUV(ix1, y1, z1, iu0, iv0); - t.vertexUV(ix1, y0, z1, iu0, iv2); - t.vertexUV(ix0, y0, z1, iu1, iv2); - t.vertexUV(ix0, y1, z1, iu1, iv0); - - t.vertexUV(ix0, y1, z1, iu0, iv0); - t.vertexUV(ix0, y0, z1, iu0, iv2); - t.vertexUV(ix1, y0, z1, iu1, iv2); - t.vertexUV(ix1, y1, z1, iu1, iv0); - } - - if (up || (y < (depth - 1) && level->isEmptyTile(x, y + 1, z + 1))) { - // small edge texture - t.vertexUV(ix0, y1, z1, iu0, iv1); - t.vertexUV(ix0, y1, z2, iu0, iv2); - t.vertexUV(ix1, y1, z2, iu1, iv2); - t.vertexUV(ix1, y1, z1, iu1, iv1); - - t.vertexUV(ix0, y1, z2, iu0, iv1); - t.vertexUV(ix0, y1, z1, iu0, iv2); - t.vertexUV(ix1, y1, z1, iu1, iv2); - t.vertexUV(ix1, y1, z2, iu1, iv1); - } - if (down || (y > 1 && level->isEmptyTile(x, y - 1, z + 1))) { - // small edge texture - t.vertexUV(ix0, y0, z1, iu0, iv1); - t.vertexUV(ix0, y0, z2, iu0, iv2); - t.vertexUV(ix1, y0, z2, iu1, iv2); - t.vertexUV(ix1, y0, z1, iu1, iv1); - - t.vertexUV(ix0, y0, z2, iu0, iv1); - t.vertexUV(ix0, y0, z1, iu0, iv2); - t.vertexUV(ix1, y0, z1, iu1, iv2); - t.vertexUV(ix1, y0, z2, iu1, iv1); - } - - } - - return true; -} - -void TileRenderer::tesselateRowTexture( Tile* tt, int data, float x, float y, float z ) { - Tesselator& t = Tesselator::instance; - - int tex = tt->getTexture(0, data); - if(fixedTexture >= 0) - tex = fixedTexture; - - int xt = (tex & 0xf) << 4; - int yt = tex & 0xf0; - float u0 = (xt) / 256.0f; - float u1 = (xt + 15.99f) / 256.f; - float v0 = (yt) / 256.0f; - float v1 = (yt + 15.99f) / 256.0f; - - float x0 = x + 0.5f - 0.25f; - float x1 = x + 0.5f + 0.25f; - float z0 = z + 0.5f - 0.5f; - float z1 = z + 0.5f + 0.5f; - t.vertexUV(x0, y + 1, z0, u0, v0); - t.vertexUV(x0, y + 0, z0, u0, v1); - t.vertexUV(x0, y + 0, z1, u1, v1); - t.vertexUV(x0, y + 1, z1, u1, v0); - - t.vertexUV(x0, y + 1, z1, u0, v0); - t.vertexUV(x0, y + 0, z1, u0, v1); - t.vertexUV(x0, y + 0, z0, u1, v1); - t.vertexUV(x0, y + 1, z0, u1, v0); - - t.vertexUV(x1, y + 1, z1, u0, v0); - t.vertexUV(x1, y + 0, z1, u0, v1); - t.vertexUV(x1, y + 0, z0, u1, v1); - t.vertexUV(x1, y + 1, z0, u1, v0); - - t.vertexUV(x1, y + 1, z0, u0, v0); - t.vertexUV(x1, y + 0, z0, u0, v1); - t.vertexUV(x1, y + 0, z1, u1, v1); - t.vertexUV(x1, y + 1, z1, u1, v0); - - x0 = x + 0.5f - 0.5f; - x1 = x + 0.5f + 0.5f; - z0 = z + 0.5f - 0.25f; - z1 = z + 0.5f + 0.25f; - - t.vertexUV(x0, y + 1, z0, u0, v0); - t.vertexUV(x0, y + 0, z0, u0, v1); - t.vertexUV(x1, y + 0, z0, u1, v1); - t.vertexUV(x1, y + 1, z0, u1, v0); - - t.vertexUV(x1, y + 1, z0, u0, v0); - t.vertexUV(x1, y + 0, z0, u0, v1); - t.vertexUV(x0, y + 0, z0, u1, v1); - t.vertexUV(x0, y + 1, z0, u1, v0); - - t.vertexUV(x1, y + 1, z1, u0, v0); - t.vertexUV(x1, y + 0, z1, u0, v1); - t.vertexUV(x0, y + 0, z1, u1, v1); - t.vertexUV(x0, y + 1, z1, u1, v0); - - t.vertexUV(x0, y + 1, z1, u0, v0); - t.vertexUV(x0, y + 0, z1, u0, v1); - t.vertexUV(x1, y + 0, z1, u1, v1); - t.vertexUV(x1, y + 1, z1, u1, v0); -} +#include "TileRenderer.hpp" +#include "Chunk.hpp" +#include +#include "Tesselator.hpp" + +#include "world/level/LevelSource.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/DoorTile.hpp" +#include "world/level/tile/LiquidTile.hpp" +#include "world/level/tile/FenceTile.hpp" +#include "world/level/tile/FenceGateTile.hpp" +#include "world/level/tile/ThinFenceTile.hpp" +#include "world/level/tile/BedTile.hpp" +#include "world/level/tile/StemTile.hpp" +#include "world/level/tile/StairTile.hpp" +#include "world/Direction.hpp" +#include "world/Facing.hpp" +#include "tileentity/TileEntityRenderer.hpp" +#include "EntityTileRenderer.hpp" + +TileRenderer::TileRenderer( LevelSource* level /* = NULL */ ) +: level(level), + fixedTexture(-1), + xFlipTexture(false), + noCulling(false), + blsmooth(1), + applyAmbienceOcclusion(false) +{ +} + +bool TileRenderer::tesselateBlockInWorld(Tile* tt, int x, int y, int z) { + int col = tt->getColor(level, x, y, z); + float r = ((col >> 16) & 0xff) / 255.0f; + float g = ((col >> 8) & 0xff) / 255.0f; + float b = ((col) & 0xff) / 255.0f; // xFlipTexture = (x & 1) != (y & 1); + + if (Minecraft::useAmbientOcclusion) { + return tesselateBlockInWorldWithAmbienceOcclusion(tt, x, y, z, r, g, b); + } else + { + return tesselateBlockInWorld(tt, x, y, z, r, g, b); + } +} + +bool TileRenderer::tesselateBlockInWorld( Tile* tt, int x, int y, int z, float r, float g, float b ) +{ + applyAmbienceOcclusion = false; + float xf = (float)x; + float yf = (float)y; + float zf = (float)z; + + Tesselator& t = Tesselator::instance; + + bool changed = false; + float c10 = 0.5f; + float c11 = 1; + float c2 = 0.8f; + float c3 = 0.6f; + + + float r11 = c11 * r; + float g11 = c11 * g; + float b11 = c11 * b; + + if (tt == (Tile*)Tile::grass) { + r = g = b = 1.0f; + } + + float r10 = c10 * r; + float r2 = c2 * r; + float r3 = c3 * r; + + float g10 = c10 * g; + float g2 = c2 * g; + float g3 = c3 * g; + + float b10 = c10 * b; + float b2 = c2 * b; + float b3 = c3 * b; + + float centerBrightness = tt->getBrightness(level, x, y, z); + + if (noCulling || tt->shouldRenderFace(level, x, y - 1, z, Facing::DOWN)) { + float br = tt->getBrightness(level, x, y - 1, z); + t.color(r10 * br, g10 * br, b10 * br); + renderFaceDown(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 0)); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x, y + 1, z, Facing::UP)) { + float br = tt->getBrightness(level, x, y + 1, z); + if (tt->yy1 != 1 && !tt->material->isLiquid()) br = centerBrightness; + t.color(r11 * br, g11 * br, b11 * br); + renderFaceUp(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 1)); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x, y, z - 1, Facing::NORTH)) { + float br = tt->getBrightness(level, x, y, z - 1); + if (tt->zz0 > 0) br = centerBrightness; + t.color(r2 * br, g2 * br, b2 * br); + renderNorth(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 2)); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x, y, z + 1, Facing::SOUTH)) { + float br = tt->getBrightness(level, x, y, z + 1); + if (tt->zz1 < 1) br = centerBrightness; + t.color(r2 * br, g2 * br, b2 * br); + renderSouth(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 3)); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x - 1, y, z, Facing::WEST)) { + float br = tt->getBrightness(level, x - 1, y, z); + if (tt->xx0 > 0) br = centerBrightness; + t.color(r3 * br, g3 * br, b3 * br); + renderWest(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 4)); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x + 1, y, z, Facing::EAST)) { + float br = tt->getBrightness(level, x + 1, y, z); + if (tt->xx1 < 1) br = centerBrightness; + t.color(r3 * br, g3 * br, b3 * br); + renderEast(tt, xf, yf, zf, tt->getTexture(level, x, y, z, 5)); + changed = true; + } + + return changed; +} + + +void TileRenderer::tesselateInWorld( Tile* tile, int x, int y, int z, int fixedTexture ) +{ + this->fixedTexture = fixedTexture; + tesselateInWorld(tile, x, y, z); + this->fixedTexture = -1; +} + +bool TileRenderer::tesselateInWorld( Tile* tt, int x, int y, int z ) +{ + int shape = tt->getRenderShape(); + tt->updateShape(level, x, y, z); + + if (shape == Tile::SHAPE_BLOCK) { + return tesselateBlockInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_WATER) { + return tesselateWaterInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_CACTUS) { + return tesselateCactusInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_CROSS_TEXTURE) { + return tesselateCrossInWorld(tt, x, y, z); + } else if(shape == Tile::SHAPE_STEM) { + return tesselateStemInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_ROWS) { + return tesselateRowInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_TORCH) { + return tesselateTorchInWorld(tt, x, y, z); + //} else if (shape == Tile::SHAPE_FIRE) { + // return tesselateFireInWorld(tt, x, y, z); + //} else if (shape == Tile::SHAPE_RED_DUST) { + // return tesselateDustInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_LADDER) { + return tesselateLadderInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_DOOR) { + return tesselateDoorInWorld(tt, x, y, z); + //} else if (shape == Tile::SHAPE_RAIL) { + // return tesselateRailInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_STAIRS) { + return tesselateStairsInWorld((StairTile*)tt, x, y, z); + } else if (shape == Tile::SHAPE_FENCE) { + return tesselateFenceInWorld((FenceTile*)tt, x, y, z); + } else if (shape == Tile::SHAPE_FENCE_GATE) { + return tesselateFenceGateInWorld((FenceGateTile*) tt, x, y, z); + //} else if (shape == Tile::SHAPE_LEVER) { + // return tesselateLeverInWorld(tt, x, y, z); + //} else if (shape == Tile::SHAPE_BED) { + // return tesselateBedInWorld(tt, x, y, z); + //} else if (shape == Tile::SHAPE_DIODE) { + // return tesselateDiodeInWorld(tt, x, y, z); + } else if (shape == Tile::SHAPE_IRON_FENCE) { + return tesselateThinFenceInWorld((ThinFenceTile*) tt, x, y, z); + } else if(shape == Tile::SHAPE_BED) { + return tesselateBedInWorld(tt, x, y, z); + } else { + return false; + } +} + +void TileRenderer::tesselateInWorldNoCulling( Tile* tile, int x, int y, int z ) +{ + noCulling = true; + tesselateInWorld(tile, x, y, z); + noCulling = false; +} + +bool TileRenderer::tesselateTorchInWorld( Tile* tt, int x, int y, int z ) +{ + int dir = level->getData(x, y, z); + + Tesselator& t = Tesselator::instance; + + float br = tt->getBrightness(level, x, y, z); + if (Tile::lightEmission[tt->id] > 0) br = 1.0f; + t.color(br, br, br); + + float r = 0.40f; + float r2 = 0.5f - r; + float h = 0.20f; + if (dir == 1) { + tesselateTorch(tt, (float)x - r2, (float)y + h, (float)z, -r, 0); + } else if (dir == 2) { + tesselateTorch(tt, (float)x + r2, (float)y + h, (float)z, +r, 0); + } else if (dir == 3) { + tesselateTorch(tt, (float)x, (float)y + h, (float)z - r2, 0, -r); + } else if (dir == 4) { + tesselateTorch(tt, (float)x, (float)y + h, (float)z + r2, 0, +r); + } else { + tesselateTorch(tt, (float)x, (float)y, (float)z, 0, 0); + } + return true; +} + +bool TileRenderer::tesselateLadderInWorld( Tile* tt, int x, int y, int z ) +{ + Tesselator& t = Tesselator::instance; + + int tex = tt->getTexture(0); + + if (fixedTexture >= 0) tex = fixedTexture; + + float br = tt->getBrightness(level, x, y, z); + t.color(br, br, br); + int xt = ((tex & 0xf) << 4); + int yt = tex & 0xf0; + + float u0 = (xt) / 256.0f; + float u1 = (xt + 15.99f) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 15.99f) / 256.0f; + + int face = level->getData(x, y, z); + + float o = 0 / 16.0f; + float r = 0.05f; + if (face == 5) { + t.vertexUV(x + r, y + 1 + o, z + 1 + o, u0, v0); + t.vertexUV(x + r, y + 0 - o, z + 1 + o, u0, v1); + t.vertexUV(x + r, y + 0 - o, z + 0 - o, u1, v1); + t.vertexUV(x + r, y + 1 + o, z + 0 - o, u1, v0); + } + if (face == 4) { + t.vertexUV(x + 1 - r, y + 0 - o, z + 1 + o, u1, v1); + t.vertexUV(x + 1 - r, y + 1 + o, z + 1 + o, u1, v0); + t.vertexUV(x + 1 - r, y + 1 + o, z + 0 - o, u0, v0); + t.vertexUV(x + 1 - r, y + 0 - o, z + 0 - o, u0, v1); + } + if (face == 3) { + t.vertexUV(x + 1 + o, y + 0 - o, z + r, u1, v1); + t.vertexUV(x + 1 + o, y + 1 + o, z + r, u1, v0); + t.vertexUV(x + 0 - o, y + 1 + o, z + r, u0, v0); + t.vertexUV(x + 0 - o, y + 0 - o, z + r, u0, v1); + } + if (face == 2) { + t.vertexUV(x + 1 + o, y + 1 + o, z + 1 - r, u0, v0); + t.vertexUV(x + 1 + o, y + 0 - o, z + 1 - r, u0, v1); + t.vertexUV(x + 0 - o, y + 0 - o, z + 1 - r, u1, v1); + t.vertexUV(x + 0 - o, y + 1 + o, z + 1 - r, u1, v0); + } + + return true; +} + +bool TileRenderer::tesselateCrossInWorld( Tile* tt, int x, int y, int z ) +{ + Tesselator& t = Tesselator::instance; + + float br = tt->getBrightness(level, x, y, z); + int col = tt->getColor(level, x, y, z); + float r = ((col >> 16) & 0xff) / 255.0f; + float g = ((col >> 8) & 0xff) / 255.0f; + float b = ((col) & 0xff) / 255.0f; + t.color(br * r, br * g, br * b); + + float xt = float(x); + float yt = float(y); + float zt = float(z); + + if (tt == Tile::tallgrass) { + long seed = (x * 3129871) ^ (z * 116129781l) ^ (y); + seed = seed * seed * 42317861 + seed * 11; + + xt += ((((seed >> 16) & 0xf) / 15.0f) - 0.5f) * 0.5f; + yt += ((((seed >> 20) & 0xf) / 15.0f) - 1.0f) * 0.2f; + zt += ((((seed >> 24) & 0xf) / 15.0f) - 0.5f) * 0.5f; + } + + tesselateCrossTexture(tt, level->getData(x, y, z), xt, yt, zt); + return true; + //return true; + /*Tesselator& t = Tesselator::instance; + + float br = tt->getBrightness(level, x, y, z); + t.color(br, br, br); + + tesselateCrossTexture(tt, level->getData(x, y, z), (float)x, (float)y, (float)z); + return true;*/ +} +bool TileRenderer::tesselateStemInWorld( Tile* _tt, int x, int y, int z ) { + StemTile* tt = (StemTile*) _tt; + Tesselator& t = Tesselator::instance; + + float br = tt->getBrightness(level, x, y, z); + + int col = tt->getColor(level, x, y, z); + float r = ((col >> 16) & 0xff) / 255.0f; + float g = ((col >> 8) & 0xff) / 255.0f; + float b = ((col) & 0xff) / 255.0f; + + t.color(br * r, br * g, br * b); + + tt->updateShape(level, x, y, z); + int dir = tt->getConnectDir(level, x, y, z); + if (dir < 0) { + tesselateStemTexture(tt, level->getData(x, y, z), tt->yy1, float(x), float(y - 1 / 16.0f), float(z)); + } else { + tesselateStemTexture(tt, level->getData(x, y, z), 0.5f, float(x), float(y - 1 / 16.0f), float(z)); + tesselateStemDirTexture(tt, level->getData(x, y, z), dir, tt->yy1, float(x), float(y - 1 / 16.0f), float(z)); + } + return true; +} +void TileRenderer::tesselateTorch( Tile* tt, float x, float y, float z, float xxa, float zza ) +{ + Tesselator& t = Tesselator::instance; + int tex = tt->getTexture(0); + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + float u0 = (xt) / 256.0f; + float u1 = (xt + 15.99f) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 15.99f) / 256.0f; + + + float uc0 = u0 + 7 / 256.0f; + float vc0 = v0 + 6 / 256.0f; + float uc1 = u0 + 9 / 256.0f; + float vc1 = v0 + 8 / 256.0f; + x += 0.5f; + z += 0.5f; + + float x0 = x - 0.5f; + float x1 = x + 0.5f; + float z0 = z - 0.5f; + float z1 = z + 0.5f; + float r = 1 / 16.0f; + + float h = 10.0f / 16.0f; + t.vertexUV(x + xxa * (1 - h) - r, y + h, z + zza * (1 - h) - r, uc0, vc0); + t.vertexUV(x + xxa * (1 - h) - r, y + h, z + zza * (1 - h) + r, uc0, vc1); + t.vertexUV(x + xxa * (1 - h) + r, y + h, z + zza * (1 - h) + r, uc1, vc1); + t.vertexUV(x + xxa * (1 - h) + r, y + h, z + zza * (1 - h) - r, uc1, vc0); + + t.vertexUV(x - r, y + 1, z0, u0, v0); + t.vertexUV(x - r + xxa, y + 0, z0 + zza, u0, v1); + t.vertexUV(x - r + xxa, y + 0, z1 + zza, u1, v1); + t.vertexUV(x - r, y + 1, z1, u1, v0); + + t.vertexUV(x + r, y + 1, z1, u0, v0); + t.vertexUV(x + xxa + r, y + 0, z1 + zza, u0, v1); + t.vertexUV(x + xxa + r, y + 0, z0 + zza, u1, v1); + t.vertexUV(x + r, y + 1, z0, u1, v0); + + t.vertexUV(x0, y + 1, z + r, u0, v0); + t.vertexUV(x0 + xxa, y + 0, z + r + zza, u0, v1); + t.vertexUV(x1 + xxa, y + 0, z + r + zza, u1, v1); + t.vertexUV(x1, y + 1, z + r, u1, v0); + + t.vertexUV(x1, y + 1, z - r, u0, v0); + t.vertexUV(x1 + xxa, y + 0, z - r + zza, u0, v1); + t.vertexUV(x0 + xxa, y + 0, z - r + zza, u1, v1); + t.vertexUV(x0, y + 1, z - r, u1, v0); +} + +void TileRenderer::tesselateCrossTexture( Tile* tt, int data, float x, float y, float z ) +{ + Tesselator& t = Tesselator::instance; + + int tex = tt->getTexture(0, data); + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + float u0 = (xt) / 256.0f; + float u1 = (xt + 15.99f) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 15.99f) / 256.0f; + + float x0 = x + 0.5f - 0.45f; + float x1 = x + 0.5f + 0.45f; + float z0 = z + 0.5f - 0.45f; + float z1 = z + 0.5f + 0.45f; + + t.vertexUV(x0, y + 1, z0, u0, v0); + t.vertexUV(x0, y + 0, z0, u0, v1); + t.vertexUV(x1, y + 0, z1, u1, v1); + t.vertexUV(x1, y + 1, z1, u1, v0); + + t.vertexUV(x1, y + 1, z1, u0, v0); + t.vertexUV(x1, y + 0, z1, u0, v1); + t.vertexUV(x0, y + 0, z0, u1, v1); + t.vertexUV(x0, y + 1, z0, u1, v0); + + t.vertexUV(x0, y + 1, z1, u0, v0); + t.vertexUV(x0, y + 0, z1, u0, v1); + t.vertexUV(x1, y + 0, z0, u1, v1); + t.vertexUV(x1, y + 1, z0, u1, v0); + + t.vertexUV(x1, y + 1, z0, u0, v0); + t.vertexUV(x1, y + 0, z0, u0, v1); + t.vertexUV(x0, y + 0, z1, u1, v1); + t.vertexUV(x0, y + 1, z1, u1, v0); +} +void TileRenderer::tesselateStemTexture( Tile* tt, int data, float h, float x, float y, float z ) { + Tesselator& t = Tesselator::instance; + int tex = tt->getTexture(0, data); + if(fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + float u0 = (xt) / 256.0f; + float u1 = (xt + 15.99f) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 15.99f * h) / 256.0f; + + float x0 = x + 0.5f - 0.45f; + float x1 = x + 0.5f + 0.45f; + float z0 = z + 0.5f - 0.45f; + float z1 = z + 0.5f + 0.45f; + + t.vertexUV(x0, y + h, z0, u0, v0); + t.vertexUV(x0, y + 0, z0, u0, v1); + t.vertexUV(x1, y + 0, z1, u1, v1); + t.vertexUV(x1, y + h, z1, u1, v0); + + t.vertexUV(x1, y + h, z1, u0, v0); + t.vertexUV(x1, y + 0, z1, u0, v1); + t.vertexUV(x0, y + 0, z0, u1, v1); + t.vertexUV(x0, y + h, z0, u1, v0); + + t.vertexUV(x0, y + h, z1, u0, v0); + t.vertexUV(x0, y + 0, z1, u0, v1); + t.vertexUV(x1, y + 0, z0, u1, v1); + t.vertexUV(x1, y + h, z0, u1, v0); + + t.vertexUV(x1, y + h, z0, u0, v0); + t.vertexUV(x1, y + 0, z0, u0, v1); + t.vertexUV(x0, y + 0, z1, u1, v1); + t.vertexUV(x0, y + h, z1, u1, v0); +} +void TileRenderer::tesselateStemDirTexture( Tile* tt, int data, int dir, float h, float x, float y, float z ) { + Tesselator& t = Tesselator::instance; + + int tex = tt->getTexture(0, data) + 16; + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + float u0 = (xt) / 256.0f; + float u1 = (xt + 15.99f) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 15.99f * h) / 256.0f; + + float x0 = x + 0.5f - 0.5f; + float x1 = x + 0.5f + 0.5f; + float z0 = z + 0.5f - 0.5f; + float z1 = z + 0.5f + 0.5f; + + float xm = x + 0.5f; + float zm = z + 0.5f; + + if ((dir + 1) / 2 % 2 == 1) { + float tmp = u1; + u1 = u0; + u0 = tmp; + } + + if (dir < 2) { + t.vertexUV(x0, y + h, zm, u0, v0); + t.vertexUV(x0, y + 0, zm, u0, v1); + t.vertexUV(x1, y + 0, zm, u1, v1); + t.vertexUV(x1, y + h, zm, u1, v0); + + t.vertexUV(x1, y + h, zm, u1, v0); + t.vertexUV(x1, y + 0, zm, u1, v1); + t.vertexUV(x0, y + 0, zm, u0, v1); + t.vertexUV(x0, y + h, zm, u0, v0); + } else { + + t.vertexUV(xm, y + h, z1, u0, v0); + t.vertexUV(xm, y + 0, z1, u0, v1); + t.vertexUV(xm, y + 0, z0, u1, v1); + t.vertexUV(xm, y + h, z0, u1, v0); + + t.vertexUV(xm, y + h, z0, u1, v0); + t.vertexUV(xm, y + 0, z0, u1, v1); + t.vertexUV(xm, y + 0, z1, u0, v1); + t.vertexUV(xm, y + h, z1, u0, v0); + } +} + +bool TileRenderer::tesselateWaterInWorld( Tile* tt, int x, int y, int z ) +{ + Tesselator& t = Tesselator::instance; + + bool up = tt->shouldRenderFace(level, x, y + 1, z, 1); + bool down = tt->shouldRenderFace(level, x, y - 1, z, 0); + + bool dirs[4]; // static? + dirs[0] = tt->shouldRenderFace(level, x, y, z - 1, 2); + dirs[1] = tt->shouldRenderFace(level, x, y, z + 1, 3); + dirs[2] = tt->shouldRenderFace(level, x - 1, y, z, 4); + dirs[3] = tt->shouldRenderFace(level, x + 1, y, z, 5); + + if (!up && !down && !dirs[0] && !dirs[1] && !dirs[2] && !dirs[3]) return false; + + bool changed = false; + float c10 = 0.5f; + float c11 = 1; + float c2 = 0.8f; + float c3 = 0.6f; + + const float yo0 = 0; + const float yo1 = 1; + + const Material* m = tt->material; + int data = level->getData(x, y, z); + + float h0 = getWaterHeight(x, y, z, m); + float h1 = getWaterHeight(x, y, z + 1, m); + float h2 = getWaterHeight(x + 1, y, z + 1, m); + float h3 = getWaterHeight(x + 1, y, z, m); + + // renderFaceUp(tt, x, y, z, tt->getTexture(0)); + if (noCulling || up) { + changed = true; + int tex = tt->getTexture(1, data); + float angle = (float) LiquidTile::getSlopeAngle(level, x, y, z, m); + if (angle > -999) { + tex = tt->getTexture(2, data); + } + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float uc = (xt + 0.5f * 16) / 256.0f; + float vc = (yt + 0.5f * 16) / 256.0f; + if (angle < -999) { + angle = 0; + } else { + uc = (xt + 1 * 16) / 256.0f; + vc = (yt + 1 * 16) / 256.0f; + } + float s = (Mth::sin(angle) * 8) / 256.5f; // @attn: to get rid of "jitter" (caused + float c = (Mth::cos(angle) * 8) / 256.5f; // of fp rounding errors) in big oceans) + + float br = tt->getBrightness(level, x, y, z); + t.color(c11 * br, c11 * br, c11 * br); + t.vertexUV((float)x + 0, (float)y + h0, (float)z + 0, uc - c - s, vc - c + s); + t.vertexUV((float)x + 0, (float)y + h1, (float)z + 1, uc - c + s, vc + c + s); + t.vertexUV((float)x + 1, (float)y + h2, (float)z + 1, uc + c + s, vc + c - s); + t.vertexUV((float)x + 1, (float)y + h3, (float)z + 0, uc + c - s, vc - c - s); + } + + if (noCulling || down) { + float br = tt->getBrightness(level, x, y - 1, z); + t.color(c10 * br, c10 * br, c10 * br); + renderFaceDown(tt, (float)x, (float)y, (float)z, tt->getTexture(0)); + changed = true; + } + + for (int face = 0; face < 4; face++) { + int xt = x; + int yt = y; + int zt = z; + + if (face == 0) zt--; + if (face == 1) zt++; + if (face == 2) xt--; + if (face == 3) xt++; + + int tex = tt->getTexture(face + 2, data); + int xTex = (tex & 0xf) << 4; + int yTex = tex & 0xf0; + + if (noCulling || dirs[face]) { + float hh0; + float hh1; + float x0, z0, x1, z1; + if (face == 0) { + hh0 = h0; + hh1 = h3; + x0 = (float)(x ); + x1 = (float)(x + 1); + z0 = (float)(z ); + z1 = (float)(z ); + } else if (face == 1) { + hh0 = h2; + hh1 = h1; + x0 = (float)(x + 1); + x1 = (float)(x ); + z0 = (float)(z + 1); + z1 = (float)(z + 1); + } else if (face == 2) { + hh0 = h1; + hh1 = h0; + x0 = (float)(x ); + x1 = (float)(x ); + z0 = (float)(z + 1); + z1 = (float)(z ); + } else { + hh0 = h3; + hh1 = h2; + x0 = (float)(x + 1); + x1 = (float)(x + 1); + z0 = (float)(z ); + z1 = (float)(z + 1); + } + + changed = true; + float u0 = (xTex + 0 * 16) / 256.0f; + float u1 = (xTex + 1 * 16 - 0.01f) / 256.0f; + + float v01 = (yTex + (1 - hh0) * 16) / 256.0f; + float v02 = (yTex + (1 - hh1) * 16) / 256.0f; + float v1 = (yTex + 1 * 16 - 0.01f) / 256.0f; + + float br = tt->getBrightness(level, xt, yt, zt); + if (face < 2) br *= c2; + else br *= c3; + + float yf = (float)y; + t.color(c11 * br, c11 * br, c11 * br); + t.vertexUV(x0, yf + hh0, z0, u0, v01); + t.vertexUV(x1, yf + hh1, z1, u1, v02); + t.vertexUV(x1, yf + 0, z1, u1, v1); + t.vertexUV(x0, yf + 0, z0, u0, v1); + } + } + + //printf("w: %d ", (dirs[0] + dirs[1] + dirs[2] + dirs[3] + up + down)); + + tt->yy0 = yo0; + tt->yy1 = yo1; + + return changed; +} + +float TileRenderer::getWaterHeight( int x, int y, int z, const Material* m ) +{ + int count = 0; + float h = 0; + for (int i = 0; i < 4; i++) { + int xx = x - (i & 1); + int yy = y; + int zz = z - ((i >> 1) & 1); + if (level->getMaterial(xx, yy + 1, zz) == m) { + return 1; + } + const Material* tm = level->getMaterial(xx, yy, zz); + if (tm == m) { + int d = level->getData(xx, yy, zz); + if (d >= 8 || d == 0) { + h += (LiquidTile::getHeight(d)) * 10; + count += 10; + } + h += LiquidTile::getHeight(d); + count++; + } else if (!tm->isSolid()) { + h += 1; + count++; + } + } + return 1 - h / count; +} + +void TileRenderer::renderBlock(Tile* tt, LevelSource* level, int x, int y, int z) { + float c10 = 0.5f; + float c11 = 1; + float c2 = 0.8f; + float c3 = 0.6f; + + Tesselator& t = Tesselator::instance; + t.begin(); + + float center = tt->getBrightness(level, x, y, z); + float br = tt->getBrightness(level, x, y - 1, z); + if (br < center) br = center; + + t.color(c10 * br, c10 * br, c10 * br); + renderFaceDown(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(0)); + + br = tt->getBrightness(level, x, y + 1, z); + if (br < center) br = center; + t.color(c11 * br, c11 * br, c11 * br); + renderFaceUp(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(1)); + + br = tt->getBrightness(level, x, y, z - 1); + if (br < center) br = center; + t.color(c2 * br, c2 * br, c2 * br); + renderNorth(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(2)); + + br = tt->getBrightness(level, x, y, z + 1); + if (br < center) br = center; + t.color(c2 * br, c2 * br, c2 * br); + renderSouth(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(3)); + + br = tt->getBrightness(level, x - 1, y, z); + if (br < center) br = center; + t.color(c3 * br, c3 * br, c3 * br); + renderWest(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(4)); + + br = tt->getBrightness(level, x + 1, y, z); + if (br < center) br = center; + t.color(c3 * br, c3 * br, c3 * br); + renderEast(tt, -0.5f, -0.5f, -0.5f, tt->getTexture(5)); + t.draw(); +} + +bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusion( Tile* tt, int pX, int pY, int pZ, float pBaseRed, float pBaseGreen, float pBaseBlue ) +{ + applyAmbienceOcclusion = true; + bool i = false; + float ll1 = ll000; + float ll2 = ll000; + float ll3 = ll000; + float ll4 = ll000; + bool tint0 = true; + bool tint1 = true; + bool tint2 = true; + bool tint3 = true; + bool tint4 = true; + bool tint5 = true; + + ll000 = tt->getBrightness(level, pX, pY, pZ); + llx00 = tt->getBrightness(level, pX - 1, pY, pZ); + ll0y0 = tt->getBrightness(level, pX, pY - 1, pZ); + ll00z = tt->getBrightness(level, pX, pY, pZ - 1); + llX00 = tt->getBrightness(level, pX + 1, pY, pZ); + ll0Y0 = tt->getBrightness(level, pX, pY + 1, pZ); + ll00Z = tt->getBrightness(level, pX, pY, pZ + 1); + + llTransXY0 = Tile::translucent[level->getTile(pX + 1, pY + 1, pZ)]; + llTransXy0 = Tile::translucent[level->getTile(pX + 1, pY - 1, pZ)]; + llTransX0Z = Tile::translucent[level->getTile(pX + 1, pY, pZ + 1)]; + llTransX0z = Tile::translucent[level->getTile(pX + 1, pY, pZ - 1)]; + llTransxY0 = Tile::translucent[level->getTile(pX - 1, pY + 1, pZ)]; + llTransxy0 = Tile::translucent[level->getTile(pX - 1, pY - 1, pZ)]; + llTransx0z = Tile::translucent[level->getTile(pX - 1, pY, pZ - 1)]; + llTransx0Z = Tile::translucent[level->getTile(pX - 1, pY, pZ + 1)]; + llTrans0YZ = Tile::translucent[level->getTile(pX, pY + 1, pZ + 1)]; + llTrans0Yz = Tile::translucent[level->getTile(pX, pY + 1, pZ - 1)]; + llTrans0yZ = Tile::translucent[level->getTile(pX, pY - 1, pZ + 1)]; + llTrans0yz = Tile::translucent[level->getTile(pX, pY - 1, pZ - 1)]; + + if (tt->tex == 3) tint0 = tint2 = tint3 = tint4 = tint5 = false; + + if ((noCulling) || (tt->shouldRenderFace(level, pX, pY - 1, pZ, 0))) { + if (blsmooth > 0) { + pY--; + + llxy0 = tt->getBrightness(level, pX - 1, pY, pZ); + ll0yz = tt->getBrightness(level, pX, pY, pZ - 1); + ll0yZ = tt->getBrightness(level, pX, pY, pZ + 1); + llXy0 = tt->getBrightness(level, pX + 1, pY, pZ); + + if (llTrans0yz || llTransxy0) { + llxyz = tt->getBrightness(level, pX - 1, pY, pZ - 1); + } else { + llxyz = llxy0; + } + if (llTrans0yZ || llTransxy0) { + llxyZ = tt->getBrightness(level, pX - 1, pY, pZ + 1); + } else { + llxyZ = llxy0; + } + if (llTrans0yz || llTransXy0) { + llXyz = tt->getBrightness(level, pX + 1, pY, pZ - 1); + } else { + llXyz = llXy0; + } + if (llTrans0yZ || llTransXy0) { + llXyZ = tt->getBrightness(level, pX + 1, pY, pZ + 1); + } else { + llXyZ = llXy0; + } + + pY++; + ll1 = (llxyZ + llxy0 + ll0yZ + ll0y0) / 4.0f; + ll4 = (ll0yZ + ll0y0 + llXyZ + llXy0) / 4.0f; + ll3 = (ll0y0 + ll0yz + llXy0 + llXyz) / 4.0f; + ll2 = (llxy0 + llxyz + ll0y0 + ll0yz) / 4.0f; + } else ll1 = ll2 = ll3 = ll4 = ll0y0; + c1r = c2r = c3r = c4r = (tint0 ? pBaseRed : 1.0f) * 0.5f; + c1g = c2g = c3g = c4g = (tint0 ? pBaseGreen : 1.0f) * 0.5f; + c1b = c2b = c3b = c4b = (tint0 ? pBaseBlue : 1.0f) * 0.5f; + c1r *= ll1; + c1g *= ll1; + c1b *= ll1; + c2r *= ll2; + c2g *= ll2; + c2b *= ll2; + c3r *= ll3; + c3g *= ll3; + c3b *= ll3; + c4r *= ll4; + c4g *= ll4; + c4b *= ll4; + + renderFaceDown(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 0)); + i = true; + } + if ((noCulling) || (tt->shouldRenderFace(level, pX, pY + 1, pZ, 1))) { + if (blsmooth > 0) { + pY++; + + llxY0 = tt->getBrightness(level, pX - 1, pY, pZ); + llXY0 = tt->getBrightness(level, pX + 1, pY, pZ); + ll0Yz = tt->getBrightness(level, pX, pY, pZ - 1); + ll0YZ = tt->getBrightness(level, pX, pY, pZ + 1); + + if (llTrans0Yz || llTransxY0) { + llxYz = tt->getBrightness(level, pX - 1, pY, pZ - 1); + } else { + llxYz = llxY0; + } + if (llTrans0Yz || llTransXY0) { + llXYz = tt->getBrightness(level, pX + 1, pY, pZ - 1); + } else { + llXYz = llXY0; + } + if (llTrans0YZ || llTransxY0) { + llxYZ = tt->getBrightness(level, pX - 1, pY, pZ + 1); + } else { + llxYZ = llxY0; + } + if (llTrans0YZ || llTransXY0) { + llXYZ = tt->getBrightness(level, pX + 1, pY, pZ + 1); + } else { + llXYZ = llXY0; + } + pY--; + + ll4 = (llxYZ + llxY0 + ll0YZ + ll0Y0) / 4.0f; + ll1 = (ll0YZ + ll0Y0 + llXYZ + llXY0) / 4.0f; + ll2 = (ll0Y0 + ll0Yz + llXY0 + llXYz) / 4.0f; + ll3 = (llxY0 + llxYz + ll0Y0 + ll0Yz) / 4.0f; + } else ll1 = ll2 = ll3 = ll4 = ll0Y0; + c1r = c2r = c3r = c4r = (tint1 ? pBaseRed : 1.0f); + c1g = c2g = c3g = c4g = (tint1 ? pBaseGreen : 1.0f); + c1b = c2b = c3b = c4b = (tint1 ? pBaseBlue : 1.0f); + c1r *= ll1; + c1g *= ll1; + c1b *= ll1; + c2r *= ll2; + c2g *= ll2; + c2b *= ll2; + c3r *= ll3; + c3g *= ll3; + c3b *= ll3; + c4r *= ll4; + c4g *= ll4; + c4b *= ll4; + renderFaceUp(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 1)); + i = true; + } + if ((noCulling) || (tt->shouldRenderFace(level, pX, pY, pZ - 1, 2))) { + if (blsmooth > 0) { + pZ--; + llx0z = tt->getBrightness(level, pX - 1, pY, pZ); + ll0yz = tt->getBrightness(level, pX, pY - 1, pZ); + ll0Yz = tt->getBrightness(level, pX, pY + 1, pZ); + llX0z = tt->getBrightness(level, pX + 1, pY, pZ); + + if (llTransx0z || llTrans0yz) { + llxyz = tt->getBrightness(level, pX - 1, pY - 1, pZ); + } else { + llxyz = llx0z; + } + if (llTransx0z || llTrans0Yz) { + llxYz = tt->getBrightness(level, pX - 1, pY + 1, pZ); + } else { + llxYz = llx0z; + } + if (llTransX0z || llTrans0yz) { + llXyz = tt->getBrightness(level, pX + 1, pY - 1, pZ); + } else { + llXyz = llX0z; + } + if (llTransX0z || llTrans0Yz) { + llXYz = tt->getBrightness(level, pX + 1, pY + 1, pZ); + } else { + llXYz = llX0z; + } + pZ++; + ll1 = (llx0z + llxYz + ll00z + ll0Yz) / 4.0f; + ll2 = (ll00z + ll0Yz + llX0z + llXYz) / 4.0f; + ll3 = (ll0yz + ll00z + llXyz + llX0z) / 4.0f; + ll4 = (llxyz + llx0z + ll0yz + ll00z) / 4.0f; + } else ll1 = ll2 = ll3 = ll4 = ll00z; + c1r = c2r = c3r = c4r = (tint2 ? pBaseRed : 1.0f) * 0.8f; + c1g = c2g = c3g = c4g = (tint2 ? pBaseGreen : 1.0f) * 0.8f; + c1b = c2b = c3b = c4b = (tint2 ? pBaseBlue : 1.0f) * 0.8f; + c1r *= ll1; + c1g *= ll1; + c1b *= ll1; + c2r *= ll2; + c2g *= ll2; + c2b *= ll2; + c3r *= ll3; + c3g *= ll3; + c3b *= ll3; + c4r *= ll4; + c4g *= ll4; + c4b *= ll4; + renderNorth(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 2)); + i = true; + } + if ((noCulling) || (tt->shouldRenderFace(level, pX, pY, pZ + 1, 3))) { + if (blsmooth > 0) { + pZ++; + + llx0Z = tt->getBrightness(level, pX - 1, pY, pZ); + llX0Z = tt->getBrightness(level, pX + 1, pY, pZ); + ll0yZ = tt->getBrightness(level, pX, pY - 1, pZ); + ll0YZ = tt->getBrightness(level, pX, pY + 1, pZ); + + if (llTransx0Z || llTrans0yZ) { + llxyZ = tt->getBrightness(level, pX - 1, pY - 1, pZ); + } else { + llxyZ = llx0Z; + } + if (llTransx0Z || llTrans0YZ) { + llxYZ = tt->getBrightness(level, pX - 1, pY + 1, pZ); + } else { + llxYZ = llx0Z; + } + if (llTransX0Z || llTrans0yZ) { + llXyZ = tt->getBrightness(level, pX + 1, pY - 1, pZ); + } else { + llXyZ = llX0Z; + } + if (llTransX0Z || llTrans0YZ) { + llXYZ = tt->getBrightness(level, pX + 1, pY + 1, pZ); + } else { + llXYZ = llX0Z; + } + pZ--; + ll1 = (llx0Z + llxYZ + ll00Z + ll0YZ) / 4.0f; + ll4 = (ll00Z + ll0YZ + llX0Z + llXYZ) / 4.0f; + ll3 = (ll0yZ + ll00Z + llXyZ + llX0Z) / 4.0f; + ll2 = (llxyZ + llx0Z + ll0yZ + ll00Z) / 4.0f; + } else ll1 = ll2 = ll3 = ll4 = ll00Z; + c1r = c2r = c3r = c4r = (tint3 ? pBaseRed : 1.0f) * 0.8f; + c1g = c2g = c3g = c4g = (tint3 ? pBaseGreen : 1.0f) * 0.8f; + c1b = c2b = c3b = c4b = (tint3 ? pBaseBlue : 1.0f) * 0.8f; + c1r *= ll1; + c1g *= ll1; + c1b *= ll1; + c2r *= ll2; + c2g *= ll2; + c2b *= ll2; + c3r *= ll3; + c3g *= ll3; + c3b *= ll3; + c4r *= ll4; + c4g *= ll4; + c4b *= ll4; + renderSouth(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 3)); + i = true; + } + if ((noCulling) || (tt->shouldRenderFace(level, pX - 1, pY, pZ, 4))) { + if (blsmooth > 0) { + pX--; + llxy0 = tt->getBrightness(level, pX, pY - 1, pZ); + llx0z = tt->getBrightness(level, pX, pY, pZ - 1); + llx0Z = tt->getBrightness(level, pX, pY, pZ + 1); + llxY0 = tt->getBrightness(level, pX, pY + 1, pZ); + + if (llTransx0z || llTransxy0) { + llxyz = tt->getBrightness(level, pX, pY - 1, pZ - 1); + } else { + llxyz = llx0z; + } + if (llTransx0Z || llTransxy0) { + llxyZ = tt->getBrightness(level, pX, pY - 1, pZ + 1); + } else { + llxyZ = llx0Z; + } + if (llTransx0z || llTransxY0) { + llxYz = tt->getBrightness(level, pX, pY + 1, pZ - 1); + } else { + llxYz = llx0z; + } + if (llTransx0Z || llTransxY0) { + llxYZ = tt->getBrightness(level, pX, pY + 1, pZ + 1); + } else { + llxYZ = llx0Z; + } + pX++; + ll4 = (llxy0 + llxyZ + llx00 + llx0Z) / 4.0f; + ll1 = (llx00 + llx0Z + llxY0 + llxYZ) / 4.0f; + ll2 = (llx0z + llx00 + llxYz + llxY0) / 4.0f; + ll3 = (llxyz + llxy0 + llx0z + llx00) / 4.0f; + } else ll1 = ll2 = ll3 = ll4 = llx00; + c1r = c2r = c3r = c4r = (tint4 ? pBaseRed : 1.0f) * 0.6f; + c1g = c2g = c3g = c4g = (tint4 ? pBaseGreen : 1.0f) * 0.6f; + c1b = c2b = c3b = c4b = (tint4 ? pBaseBlue : 1.0f) * 0.6f; + c1r *= ll1; + c1g *= ll1; + c1b *= ll1; + c2r *= ll2; + c2g *= ll2; + c2b *= ll2; + c3r *= ll3; + c3g *= ll3; + c3b *= ll3; + c4r *= ll4; + c4g *= ll4; + c4b *= ll4; + renderWest(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 4)); + i = true; + } + if ((noCulling) || (tt->shouldRenderFace(level, pX + 1, pY, pZ, 5))) { + if (blsmooth > 0) { + pX++; + llXy0 = tt->getBrightness(level, pX, pY - 1, pZ); + llX0z = tt->getBrightness(level, pX, pY, pZ - 1); + llX0Z = tt->getBrightness(level, pX, pY, pZ + 1); + llXY0 = tt->getBrightness(level, pX, pY + 1, pZ); + + if (llTransXy0 || llTransX0z) { + llXyz = tt->getBrightness(level, pX, pY - 1, pZ - 1); + } else { + llXyz = llX0z; + } + if (llTransXy0 || llTransX0Z) { + llXyZ = tt->getBrightness(level, pX, pY - 1, pZ + 1); + } else { + llXyZ = llX0Z; + } + if (llTransXY0 || llTransX0z) { + llXYz = tt->getBrightness(level, pX, pY + 1, pZ - 1); + } else { + llXYz = llX0z; + } + if (llTransXY0 || llTransX0Z) { + llXYZ = tt->getBrightness(level, pX, pY + 1, pZ + 1); + } else { + llXYZ = llX0Z; + } + pX--; + ll1 = (llXy0 + llXyZ + llX00 + llX0Z) / 4.0f; + ll4 = (llX00 + llX0Z + llXY0 + llXYZ) / 4.0f; + ll3 = (llX0z + llX00 + llXYz + llXY0) / 4.0f; + ll2 = (llXyz + llXy0 + llX0z + llX00) / 4.0f; + } else ll1 = ll2 = ll3 = ll4 = llX00; + c1r = c2r = c3r = c4r = (tint5 ? pBaseRed : 1.0f) * 0.6f; + c1g = c2g = c3g = c4g = (tint5 ? pBaseGreen : 1.0f) * 0.6f; + c1b = c2b = c3b = c4b = (tint5 ? pBaseBlue : 1.0f) * 0.6f; + c1r *= ll1; + c1g *= ll1; + c1b *= ll1; + c2r *= ll2; + c2g *= ll2; + c2b *= ll2; + c3r *= ll3; + c3g *= ll3; + c3b *= ll3; + c4r *= ll4; + c4g *= ll4; + c4b *= ll4; + + renderEast(tt, (float) pX, (float) pY, (float) pZ, tt->getTexture(level, pX, pY, pZ, 5)); + i = true; + } + applyAmbienceOcclusion = false; + return i; +} + +bool TileRenderer::tesselateCactusInWorld(Tile* tt, int x, int y, int z) { + int col = tt->getColor(level, x, y, z); + float r = ((col >> 16) & 0xff) / 255.0f; + float g = ((col >> 8) & 0xff) / 255.0f; + float b = ((col) & 0xff) / 255.0f; + return tesselateCactusInWorld(tt, x, y, z, r, g, b); +} + +bool TileRenderer::tesselateCactusInWorld(Tile* tt, int x, int y, int z, float r, float g, float b) { + Tesselator& t = Tesselator::instance; + + bool changed = false; + float c10 = 0.5f; + float c11 = 1; + float c2 = 0.8f; + float c3 = 0.6f; + + float r10 = c10 * r; + float r11 = c11 * r; + float r2 = c2 * r; + float r3 = c3 * r; + + float g10 = c10 * g; + float g11 = c11 * g; + float g2 = c2 * g; + float g3 = c3 * g; + + float b10 = c10 * b; + float b11 = c11 * b; + float b2 = c2 * b; + float b3 = c3 * b; + + float s = 1 / 16.0f; + const float X = (float)x; + const float Y = (float)y; + const float Z = (float)z; + + float centerBrightness = tt->getBrightness(level, x, y, z); + + if (noCulling || tt->shouldRenderFace(level, x, y - 1, z, 0)) { + float br = tt->getBrightness(level, x, y - 1, z); + // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = +// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; + t.color(r10 * br, g10 * br, b10 * br); + renderFaceDown(tt, X, Y, Z, tt->getTexture(level, x, y, z, 0)); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x, y + 1, z, 1)) { + float br = tt->getBrightness(level, x, y + 1, z); + if (tt->yy1 != 1 && !tt->material->isLiquid()) br = centerBrightness; + // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = +// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; + t.color(r11 * br, g11 * br, b11 * br); + renderFaceUp(tt, X, Y, Z, tt->getTexture(level, x, y, z, 1)); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x, y, z - 1, 2)) { + float br = tt->getBrightness(level, x, y, z - 1); + if (tt->zz0 > 0) br = centerBrightness; + // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = +// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; + t.color(r2 * br, g2 * br, b2 * br); + t.addOffset(0, 0, s); + renderNorth(tt, X, Y, Z, tt->getTexture(level, x, y, z, 2)); + t.addOffset(0, 0, -s); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x, y, z + 1, 3)) { + float br = tt->getBrightness(level, x, y, z + 1); + if (tt->zz1 < 1) br = centerBrightness; + // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = +// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; + t.color(r2 * br, g2 * br, b2 * br); + t.addOffset(0, 0, -s); + renderSouth(tt, X, Y, Z, tt->getTexture(level, x, y, z, 3)); + t.addOffset(0, 0, s); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x - 1, y, z, 4)) { + float br = tt->getBrightness(level, x - 1, y, z); + if (tt->xx0 > 0) br = centerBrightness; + // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = +// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; + t.color(r3 * br, g3 * br, b3 * br); + t.addOffset(s, 0, 0); + renderWest(tt, X, Y, Z, tt->getTexture(level, x, y, z, 4)); + t.addOffset(-s, 0, 0); + changed = true; + } + + if (noCulling || tt->shouldRenderFace(level, x + 1, y, z, 5)) { + float br = tt->getBrightness(level, x + 1, y, z); + if (tt->xx1 < 1) br = centerBrightness; + // if (Tile::lightEmission[tt->id] > br*Level.MAX_BRIGHTNESS) br = +// Tile::lightEmission[tt->id]/Level.MAX_BRIGHTNESS; + t.color(r3 * br, g3 * br, b3 * br); + t.addOffset(-s, 0, 0); + renderEast(tt, X, Y, Z, tt->getTexture(level, x, y, z, 5)); + t.addOffset(s, 0, 0); + changed = true; + } + + return changed; +} + +bool TileRenderer::tesselateFenceInWorld(FenceTile* tt, int x, int y, int z) { + bool changed = true; + + float a = 6 / 16.0f; + float b = 10 / 16.0f; + tt->setShape(a, 0, a, b, 1, b); + tesselateBlockInWorld(tt, x, y, z); + + bool vertical = false; + bool horizontal = false; + + bool l = tt->connectsTo(level, x - 1, y, z); + bool r = tt->connectsTo(level, x + 1, y, z); + bool u = tt->connectsTo(level, x, y, z - 1); + bool d = tt->connectsTo(level, x, y, z + 1); + + if (l || r) vertical = true; + if (u || d) horizontal = true; + + if (!vertical && !horizontal) vertical = true; + + a = 7 / 16.0f; + b = 9 / 16.0f; + float h0 = 12 / 16.0f; + float h1 = 15 / 16.0f; + + float x0 = l ? 0 : a; + float x1 = r ? 1 : b; + float z0 = u ? 0 : a; + float z1 = d ? 1 : b; + + if (vertical) { + tt->setShape(x0, h0, a, x1, h1, b); + tesselateBlockInWorld(tt, x, y, z); + } + if (horizontal) { + tt->setShape(a, h0, z0, b, h1, z1); + tesselateBlockInWorld(tt, x, y, z); + } + + h0 = 6 / 16.0f; + h1 = 9 / 16.0f; + if (vertical) { + tt->setShape(x0, h0, a, x1, h1, b); + tesselateBlockInWorld(tt, x, y, z); + } + if (horizontal) { + tt->setShape(a, h0, z0, b, h1, z1); + tesselateBlockInWorld(tt, x, y, z); + } + + tt->setShape(0, 0, 0, 1, 1, 1); + return changed; +} + +bool TileRenderer::tesselateFenceGateInWorld(FenceGateTile* tt, int x, int y, int z) { + bool changed = true; + + int data = level->getData(x, y, z); + bool isOpen = FenceGateTile::isOpen(data); + int direction = FenceGateTile::getDirection(data); + + const float h00 = 6 / 16.0f; + const float h01 = 9 / 16.0f; + const float h10 = 12 / 16.0f; + const float h11 = 15 / 16.0f; + const float h20 = 5 / 16.0f; + const float h21 = 16 / 16.0f; + + // edge sticks + if (direction == Direction::EAST || direction == Direction::WEST) { + float x0 = 7 / 16.0f; + float x1 = 9 / 16.0f; + float z0 = 0 / 16.0f; + float z1 = 2 / 16.0f; + tt->setShape(x0, h20, z0, x1, h21, z1); + tesselateBlockInWorld(tt, x, y, z); + + z0 = 14 / 16.0f; + z1 = 16 / 16.0f; + tt->setShape(x0, h20, z0, x1, h21, z1); + tesselateBlockInWorld(tt, x, y, z); + } else { + float x0 = 0 / 16.0f; + float x1 = 2 / 16.0f; + float z0 = 7 / 16.0f; + float z1 = 9 / 16.0f; + tt->setShape(x0, h20, z0, x1, h21, z1); + tesselateBlockInWorld(tt, x, y, z); + + x0 = 14 / 16.0f; + x1 = 16 / 16.0f; + tt->setShape(x0, h20, z0, x1, h21, z1); + tesselateBlockInWorld(tt, x, y, z); + } + if (!isOpen) { + if (direction == Direction::EAST || direction == Direction::WEST) { + float x0 = 7 / 16.0f; + float x1 = 9 / 16.0f; + float z0 = 6 / 16.0f; + float z1 = 8 / 16.0f; + tt->setShape(x0, h00, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + z0 = 8 / 16.0f; + z1 = 10 / 16.0f; + tt->setShape(x0, h00, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + z0 = 10 / 16.0f; + z1 = 14 / 16.0f; + tt->setShape(x0, h00, z0, x1, h01, z1); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x0, h10, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + z0 = 2 / 16.0f; + z1 = 6 / 16.0f; + tt->setShape(x0, h00, z0, x1, h01, z1); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x0, h10, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + } else { + float x0 = 6 / 16.0f; + float x1 = 8 / 16.0f; + float z0 = 7 / 16.0f; + float z1 = 9 / 16.0f; + tt->setShape(x0, h00, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + x0 = 8 / 16.0f; + x1 = 10 / 16.0f; + tt->setShape(x0, h00, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + x0 = 10 / 16.0f; + x1 = 14 / 16.0f; + tt->setShape(x0, h00, z0, x1, h01, z1); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x0, h10, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + x0 = 2 / 16.0f; + x1 = 6 / 16.0f; + tt->setShape(x0, h00, z0, x1, h01, z1); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x0, h10, z0, x1, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + + } + } else { + if (direction == Direction::EAST) { + + const float z00 = 0 / 16.0f; + const float z01 = 2 / 16.0f; + const float z10 = 14 / 16.0f; + const float z11 = 16 / 16.0f; + + const float x0 = 9 / 16.0f; + const float x1 = 13 / 16.0f; + const float x2 = 15 / 16.0f; + + tt->setShape(x1, h00, z00, x2, h11, z01); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x1, h00, z10, x2, h11, z11); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x0, h00, z00, x1, h01, z01); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x0, h00, z10, x1, h01, z11); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x0, h10, z00, x1, h11, z01); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x0, h10, z10, x1, h11, z11); + tesselateBlockInWorld(tt, x, y, z); + } else if (direction == Direction::WEST) { + const float z00 = 0 / 16.0f; + const float z01 = 2 / 16.0f; + const float z10 = 14 / 16.0f; + const float z11 = 16 / 16.0f; + + const float x0 = 1 / 16.0f; + const float x1 = 3 / 16.0f; + const float x2 = 7 / 16.0f; + + tt->setShape(x0, h00, z00, x1, h11, z01); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x0, h00, z10, x1, h11, z11); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x1, h00, z00, x2, h01, z01); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x1, h00, z10, x2, h01, z11); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x1, h10, z00, x2, h11, z01); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x1, h10, z10, x2, h11, z11); + tesselateBlockInWorld(tt, x, y, z); + } else if (direction == Direction::SOUTH) { + + const float x00 = 0 / 16.0f; + const float x01 = 2 / 16.0f; + const float x10 = 14 / 16.0f; + const float x11 = 16 / 16.0f; + + const float z0 = 9 / 16.0f; + const float z1 = 13 / 16.0f; + const float z2 = 15 / 16.0f; + + tt->setShape(x00, h00, z1, x01, h11, z2); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x10, h00, z1, x11, h11, z2); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x00, h00, z0, x01, h01, z1); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x10, h00, z0, x11, h01, z1); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x00, h10, z0, x01, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x10, h10, z0, x11, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + } else if (direction == Direction::NORTH) { + const float x00 = 0 / 16.0f; + const float x01 = 2 / 16.0f; + const float x10 = 14 / 16.0f; + const float x11 = 16 / 16.0f; + + const float z0 = 1 / 16.0f; + const float z1 = 3 / 16.0f; + const float z2 = 7 / 16.0f; + + tt->setShape(x00, h00, z0, x01, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x10, h00, z0, x11, h11, z1); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x00, h00, z1, x01, h01, z2); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x10, h00, z1, x11, h01, z2); + tesselateBlockInWorld(tt, x, y, z); + + tt->setShape(x00, h10, z1, x01, h11, z2); + tesselateBlockInWorld(tt, x, y, z); + tt->setShape(x10, h10, z1, x11, h11, z2); + tesselateBlockInWorld(tt, x, y, z); + } + } + + tt->setShape(0, 0, 0, 1, 1, 1); + return changed; +} + +bool TileRenderer::tesselateBedInWorld(Tile *tt, int x, int y, int z) { + Tesselator& t = Tesselator::instance; + int data = level->getData(x, y, z); + int direction = BedTile::getDirection(data); + bool isHead = BedTile::isHeadPiece(data); + + float c10 = 0.5f; + float c11 = 1; + float c2 = 0.8f; + float c3 = 0.6f; + + float r11 = c11; + float g11 = c11; + float b11 = c11; + + float r10 = c10; + float r2 = c2; + float r3 = c3; + + float g10 = c10; + float g2 = c2; + float g3 = c3; + + float b10 = c10; + float b2 = c2; + float b3 = c3; + + float centerBrightness = tt->getBrightness(level, x, y, z); + // render wooden underside + { + t.color(r10 * centerBrightness, g10 * centerBrightness, b10 * centerBrightness); + int tex = tt->getTexture(level, x, y, z, Facing::DOWN); + + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt) / 256.0f; + float u1 = (xt + 16 - 0.01f) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 16 - 0.01f) / 256.0f; + + float x0 = x + tt->xx0; + float x1 = x + tt->xx1; + float y0 = y + tt->yy0 + 3.0f / 16.0f; + float z0 = z + tt->zz0; + float z1 = z + tt->zz1; + + t.vertexUV(x0, y0, z1, u0, v1); + t.vertexUV(x0, y0, z0, u0, v0); + t.vertexUV(x1, y0, z0, u1, v0); + t.vertexUV(x1, y0, z1, u1, v1); + } + + // render bed top + + float brightness = tt->getBrightness(level, x, y + 1, z); + t.color(r11 * brightness, g11 * brightness, b11 * brightness); + + int tex = tt->getTexture(level, x, y, z, Facing::UP); + + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt) / 256.0f; + float u1 = (xt + 16 ) / 256.0f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 16) / 256.0f; + + // Default is west + float topLeftU = u0; + float topRightU = u1; + float topLeftV = v0; + float topRightV = v0; + float bottomLeftU = u0; + float bottomRightU = u1; + float bottomLeftV = v1; + float bottomRightV = v1; + + if (direction == Direction::SOUTH) { + // rotate 90 degrees clockwise + topRightU = u0; + topLeftV = v1; + bottomLeftU = u1; + bottomRightV = v0; + } else if (direction == Direction::NORTH) { + // rotate 90 degrees counter-clockwise + topLeftU = u1; + topRightV = v1; + bottomRightU = u0; + bottomLeftV = v0; + } else if (direction == Direction::EAST) { + // rotate 180 degrees + topLeftU = u1; + topRightV = v1; + bottomRightU = u0; + bottomLeftV = v0; + topRightU = u0; + topLeftV = v1; + bottomLeftU = u1; + bottomRightV = v0; + } + + float x0 = x + tt->xx0; + float x1 = x + tt->xx1; + float y1 = y + tt->yy1; + float z0 = z + tt->zz0; + float z1 = z + tt->zz1; + + t.vertexUV(x1, y1, z1, bottomLeftU, bottomLeftV); + t.vertexUV(x1, y1, z0, topLeftU, topLeftV); + t.vertexUV(x0, y1, z0, topRightU, topRightV); + t.vertexUV(x0, y1, z1, bottomRightU, bottomRightV); + + // determine which edge to skip (the one between foot and head piece) + int skipEdge = Direction::DIRECTION_FACING[direction]; + if (isHead) { + skipEdge = Direction::DIRECTION_FACING[Direction::DIRECTION_OPPOSITE[direction]]; + } + // and which edge to x-flip + int flipEdge = Facing::WEST; + switch (direction) { + case Direction::NORTH: + break; + case Direction::SOUTH: + flipEdge = Facing::EAST; + break; + case Direction::EAST: + flipEdge = Facing::NORTH; + break; + case Direction::WEST: + flipEdge = Facing::SOUTH; + break; + } + + if ((skipEdge != Facing::NORTH) && (noCulling || tt->shouldRenderFace(level, x, y, z - 1, Facing::NORTH))) { + float br = tt->getBrightness(level, x, y, z - 1); + if (tt->zz0 > 0) br = centerBrightness; + + t.color(r2 * br, g2 * br, b2 * br); + xFlipTexture = flipEdge == Facing::NORTH; + renderNorth(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 2)); + } + + if ((skipEdge != Facing::SOUTH) && (noCulling || tt->shouldRenderFace(level, x, y, z + 1, Facing::SOUTH))) { + float br = tt->getBrightness(level, x, y, z + 1); + if (tt->zz1 < 1) br = centerBrightness; + + t.color(r2 * br, g2 * br, b2 * br); + + xFlipTexture = flipEdge == Facing::SOUTH; + renderSouth(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 3)); + } + + if ((skipEdge != Facing::WEST) && (noCulling || tt->shouldRenderFace(level, x - 1, y, z, Facing::WEST))) { + float br = tt->getBrightness(level, x - 1, y, z); + if (tt->xx0 > 0) br = centerBrightness; + + t.color(r3 * br, g3 * br, b3 * br); + xFlipTexture = flipEdge == Facing::WEST; + renderWest(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 4)); + } + + if ((skipEdge != Facing::EAST) && (noCulling || tt->shouldRenderFace(level, x + 1, y, z, Facing::EAST))) { + float br = tt->getBrightness(level, x + 1, y, z); + if (tt->xx1 < 1) br = centerBrightness; + + t.color(r3 * br, g3 * br, b3 * br); + xFlipTexture = flipEdge == Facing::EAST; + renderEast(tt, float(x), float(y), float(z), tt->getTexture(level, x, y, z, 5)); + } + xFlipTexture = false; + return true; +} + +bool TileRenderer::tesselateStairsInWorld( StairTile* tt, int x, int y, int z ) +{ + + tt->setBaseShape(level, x, y, z); + tesselateBlockInWorld(tt, x, y, z); + + bool checkInnerPiece = tt->setStepShape(level, x, y, z); + tesselateBlockInWorld(tt, x, y, z); + + if (checkInnerPiece) { + if (tt->setInnerPieceShape(level, x, y, z)) { + tesselateBlockInWorld(tt, x, y, z); + } + } + + // setShape(0, 0, 0, 1, 1, 1); + return true; +} + +bool TileRenderer::tesselateDoorInWorld( Tile* tt, int x, int y, int z ) +{ + Tesselator& t = Tesselator::instance; + + DoorTile* dt = (DoorTile*) tt; + + bool changed = false; + float c10 = 0.5f; + float c11 = 1; + float c2 = 0.8f; + float c3 = 0.6f; + + float centerBrightness = tt->getBrightness(level, x, y, z); + + { + float br = tt->getBrightness(level, x, y - 1, z); + if (dt->yy0 > 0) br = centerBrightness; + if (Tile::lightEmission[tt->id] > 0) br = 1.0f; + t.color(c10 * br, c10 * br, c10 * br); + renderFaceDown(tt, (float)x, (float)y, (float)z, tt->getTexture(level, x, y, z, 0)); + changed = true; + } + + { + float br = tt->getBrightness(level, x, y + 1, z); + if (dt->yy1 < 1) br = centerBrightness; + if (Tile::lightEmission[tt->id] > 0) br = 1.0f; + t.color(c11 * br, c11 * br, c11 * br); + renderFaceUp(tt, (float)x, (float)y, (float)z, tt->getTexture(level, x, y, z, 1)); + changed = true; + } + + { + float br = tt->getBrightness(level, x, y, z - 1); + if (dt->zz0 > 0) br = centerBrightness; + if (Tile::lightEmission[tt->id] > 0) br = 1.0f; + t.color(c2 * br, c2 * br, c2 * br); + int tex = tt->getTexture(level, x, y, z, 2); + if (tex < 0) { + xFlipTexture = true; + tex = -tex; + } + renderNorth(tt, (float)x, (float)y, (float)z, tex); + changed = true; + xFlipTexture = false; + } + + { + float br = tt->getBrightness(level, x, y, z + 1); + if (dt->zz1 < 1) br = centerBrightness; + if (Tile::lightEmission[tt->id] > 0) br = 1.0f; + t.color(c2 * br, c2 * br, c2 * br); + int tex = tt->getTexture(level, x, y, z, 3); + if (tex < 0) { + xFlipTexture = true; + tex = -tex; + } + renderSouth(tt, (float)x, (float)y, (float)z, tex); + changed = true; + xFlipTexture = false; + } + + { + float br = tt->getBrightness(level, x - 1, y, z); + if (dt->xx0 > 0) br = centerBrightness; + if (Tile::lightEmission[tt->id] > 0) br = 1.0f; + t.color(c3 * br, c3 * br, c3 * br); + int tex = tt->getTexture(level, x, y, z, 4); + if (tex < 0) { + xFlipTexture = true; + tex = -tex; + } + renderWest(tt, (float)x, (float)y, (float)z, tex); + changed = true; + xFlipTexture = false; + } + + { + float br = tt->getBrightness(level, x + 1, y, z); + if (dt->xx1 < 1) br = centerBrightness; + if (Tile::lightEmission[tt->id] > 0) br = 1.0f; + t.color(c3 * br, c3 * br, c3 * br); + int tex = tt->getTexture(level, x, y, z, 5); + if (tex < 0) { + xFlipTexture = true; + tex = -tex; + } + renderEast(tt, (float)x, (float)y, (float)z, tex); + changed = true; + xFlipTexture = false; + } + + return changed; +} + +bool TileRenderer::tesselateRowInWorld( Tile* tt, int x, int y, int z ) { + Tesselator& t = Tesselator::instance; + float br = tt->getBrightness(level, x, y, z); + t.color(br, br, br); + tesselateRowTexture(tt, level->getData(x, y, z), float(x), y - 1 / 16.0f, float(z)); + return true; +} + +void TileRenderer::renderFaceDown( Tile* tt, float x, float y, float z, int tex ) +{ + Tesselator& t = Tesselator::instance; + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt + tt->xx0 * 16) / 256.0f; + float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; + float v0 = (yt + tt->zz0 * 16) / 256.0f; + float v1 = (yt + tt->zz1 * 16 - 0.01f) / 256.0f; + + if (tt->xx0 < 0 || tt->xx1 > 1) { + u0 = (xt + 0 * 15.99f) / 256.0f; + u1 = (xt + 1 * 15.99f) / 256.0f; + } + if (tt->zz0 < 0 || tt->zz1 > 1) { + v0 = (yt + 0 * 15.99f) / 256.0f; + v1 = (yt + 1 * 15.99f) / 256.0f; + } + + float x0 = x + tt->xx0; + float x1 = x + tt->xx1; + float y0 = y + tt->yy0; + float z0 = z + tt->zz0; + float z1 = z + tt->zz1; + + if (applyAmbienceOcclusion) { + t.color(c1r, c1g, c1b); + t.vertexUV(x0, y0, z1, u0, v1); + t.color(c2r, c2g, c2b); + t.vertexUV(x0, y0, z0, u0, v0); + t.color(c3r, c3g, c3b); + t.vertexUV(x1, y0, z0, u1, v0); + t.color(c4r, c4g, c4b); + t.vertexUV(x1, y0, z1, u1, v1); + } else { + t.vertexUV(x0, y0, z1, u0, v1); + t.vertexUV(x0, y0, z0, u0, v0); + t.vertexUV(x1, y0, z0, u1, v0); + t.vertexUV(x1, y0, z1, u1, v1); + } +} + +void TileRenderer::renderFaceUp( Tile* tt, float x, float y, float z, int tex ) +{ + Tesselator& t = Tesselator::instance; + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt + tt->xx0 * 16) / 256.0f; + float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; + float v0 = (yt + tt->zz0 * 16) / 256.0f; + float v1 = (yt + tt->zz1 * 16 - 0.01f) / 256.0f; + + if (tt->xx0 < 0 || tt->xx1 > 1) { + u0 = (xt + 0 * 15.99f) / 256.0f; + u1 = (xt + 1 * 15.99f) / 256.0f; + } + if (tt->zz0 < 0 || tt->zz1 > 1) { + v0 = (yt + 0 * 15.99f) / 256.0f; + v1 = (yt + 1 * 15.99f) / 256.0f; + } + + float x0 = x + tt->xx0; + float x1 = x + tt->xx1; + float y1 = y + tt->yy1; + float z0 = z + tt->zz0; + float z1 = z + tt->zz1; + + if (applyAmbienceOcclusion) { + t.color(c1r, c1g, c1b); + t.vertexUV(x1, y1, z1, u1, v1); + t.color(c2r, c2g, c2b); + t.vertexUV(x1, y1, z0, u1, v0); + t.color(c3r, c3g, c3b); + t.vertexUV(x0, y1, z0, u0, v0); + t.color(c4r, c4g, c4b); + t.vertexUV(x0, y1, z1, u0, v1); + } else { + t.vertexUV(x1, y1, z1, u1, v1); + t.vertexUV(x1, y1, z0, u1, v0); + t.vertexUV(x0, y1, z0, u0, v0); + t.vertexUV(x0, y1, z1, u0, v1); + } +} + +void TileRenderer::renderNorth( Tile* tt, float x, float y, float z, int tex ) +{ + Tesselator& t = Tesselator::instance; + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + float u0 = (xt + tt->xx0 * 16) / 256.0f; + float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; + float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; + float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; + if (xFlipTexture) { + float tmp = u0; + u0 = u1; + u1 = tmp; + } + + if (tt->xx0 < 0 || tt->xx1 > 1) { + u0 = (xt + 0 * 15.99f) / 256.0f; + u1 = (xt + 1 * 15.99f) / 256.0f; + } + if (tt->yy0 < 0 || tt->yy1 > 1) { + v0 = (yt + 0 * 15.99f) / 256.0f; + v1 = (yt + 1 * 15.99f) / 256.0f; + } + + float x0 = x + tt->xx0; + float x1 = x + tt->xx1; + float y0 = y + tt->yy0; + float y1 = y + tt->yy1; + float z0 = z + tt->zz0; + + if (applyAmbienceOcclusion) { + t.color(c1r, c1g, c1b); + t.vertexUV(x0, y1, z0, u1, v0); + t.color(c2r, c2g, c2b); + t.vertexUV(x1, y1, z0, u0, v0); + t.color(c3r, c3g, c3b); + t.vertexUV(x1, y0, z0, u0, v1); + t.color(c4r, c4g, c4b); + t.vertexUV(x0, y0, z0, u1, v1); + } else { + t.vertexUV(x0, y1, z0, u1, v0); + t.vertexUV(x1, y1, z0, u0, v0); + t.vertexUV(x1, y0, z0, u0, v1); + t.vertexUV(x0, y0, z0, u1, v1); + } +} + +void TileRenderer::renderSouth( Tile* tt, float x, float y, float z, int tex ) +{ + Tesselator& t = Tesselator::instance; + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt + tt->xx0 * 16) / 256.0f; + float u1 = (xt + tt->xx1 * 16 - 0.01f) / 256.0f; + float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; + float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; + if (xFlipTexture) { + float tmp = u0; + u0 = u1; + u1 = tmp; + } + + if (tt->xx0 < 0 || tt->xx1 > 1) { + u0 = (xt + 0 * 15.99f) / 256.0f; + u1 = (xt + 1 * 15.99f) / 256.0f; + } + if (tt->yy0 < 0 || tt->yy1 > 1) { + v0 = (yt + 0 * 15.99f) / 256.0f; + v1 = (yt + 1 * 15.99f) / 256.0f; + } + + float x0 = x + tt->xx0; + float x1 = x + tt->xx1; + float y0 = y + tt->yy0; + float y1 = y + tt->yy1; + float z1 = z + tt->zz1; + + if (applyAmbienceOcclusion) { + t.color(c1r, c1g, c1b); + t.vertexUV(x0, y1, z1, u0, v0); + t.color(c2r, c2g, c2b); + t.vertexUV(x0, y0, z1, u0, v1); + t.color(c3r, c3g, c3b); + t.vertexUV(x1, y0, z1, u1, v1); + t.color(c4r, c4g, c4b); + t.vertexUV(x1, y1, z1, u1, v0); + } else { + t.vertexUV(x0, y1, z1, u0, v0); + t.vertexUV(x0, y0, z1, u0, v1); + t.vertexUV(x1, y0, z1, u1, v1); + t.vertexUV(x1, y1, z1, u1, v0); + } +} + +void TileRenderer::renderWest( Tile* tt, float x, float y, float z, int tex ) +{ + Tesselator& t = Tesselator::instance; + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt + tt->zz0 * 16) / 256.0f; + float u1 = (xt + tt->zz1 * 16 - 0.01f) / 256.0f; + float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; + float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; + if (xFlipTexture) { + float tmp = u0; + u0 = u1; + u1 = tmp; + } + + if (tt->zz0 < 0 || tt->zz1 > 1) { + u0 = (xt + 0 * 15.99f) / 256.0f; + u1 = (xt + 1 * 15.99f) / 256.0f; + } + if (tt->yy0 < 0 || tt->yy1 > 1) { + v0 = (yt + 0 * 15.99f) / 256.0f; + v1 = (yt + 1 * 15.99f) / 256.0f; + } + + float x0 = x + tt->xx0; + float y0 = y + tt->yy0; + float y1 = y + tt->yy1; + float z0 = z + tt->zz0; + float z1 = z + tt->zz1; + + if (applyAmbienceOcclusion) { + t.color(c1r, c1g, c1b); + t.vertexUV(x0, y1, z1, u1, v0); + t.color(c2r, c2g, c2b); + t.vertexUV(x0, y1, z0, u0, v0); + t.color(c3r, c3g, c3b); + t.vertexUV(x0, y0, z0, u0, v1); + t.color(c4r, c4g, c4b); + t.vertexUV(x0, y0, z1, u1, v1); + } else { + t.vertexUV(x0, y1, z1, u1, v0); + t.vertexUV(x0, y1, z0, u0, v0); + t.vertexUV(x0, y0, z0, u0, v1); + t.vertexUV(x0, y0, z1, u1, v1); + } +} + +void TileRenderer::renderEast( Tile* tt, float x, float y, float z, int tex ) +{ + Tesselator& t = Tesselator::instance; + + if (fixedTexture >= 0) tex = fixedTexture; + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + + float u0 = (xt + tt->zz0 * 16) / 256.0f; + float u1 = (xt + tt->zz1 * 16 - 0.01f) / 256.0f; + float v0 = (yt + 16 - tt->yy1 * 16) / 256.0f; + float v1 = (yt + 16 - tt->yy0 * 16 - 0.01f) / 256.0f; + if (xFlipTexture) { + float tmp = u0; + u0 = u1; + u1 = tmp; + } + + if (tt->zz0 < 0 || tt->zz1 > 1) { + u0 = (xt + 0 * 15.99f) / 256.0f; + u1 = (xt + 1 * 15.99f) / 256.0f; + } + if (tt->yy0 < 0 || tt->yy1 > 1) { + v0 = (yt + 0 * 15.99f) / 256.0f; + v1 = (yt + 1 * 15.99f) / 256.0f; + } + + float x1 = x + tt->xx1; + float y0 = y + tt->yy0; + float y1 = y + tt->yy1; + float z0 = z + tt->zz0; + float z1 = z + tt->zz1; + + if (applyAmbienceOcclusion) { + t.color(c1r, c1g, c1b); + t.vertexUV(x1, y0, z1, u0, v1); + t.color(c2r, c2g, c2b); + t.vertexUV(x1, y0, z0, u1, v1); + t.color(c3r, c3g, c3b); + t.vertexUV(x1, y1, z0, u1, v0); + t.color(c4r, c4g, c4b); + t.vertexUV(x1, y1, z1, u0, v0); + } else { + t.vertexUV(x1, y0, z1, u0, v1); + t.vertexUV(x1, y0, z0, u1, v1); + t.vertexUV(x1, y1, z0, u1, v0); + t.vertexUV(x1, y1, z1, u0, v0); + } +} + +void TileRenderer::renderTile( Tile* tile, int data ) +{ + Tesselator& t = Tesselator::instance; + + t.color(0xff, 0xff, 0xff); + int shape = tile->getRenderShape(); + + if (shape == Tile::SHAPE_BLOCK) { + tile->updateDefaultShape(); + t.addOffset(-0.5f, -0.5f, -0.5f); + t.begin(); + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0, data)); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1, data)); + renderNorth(tile, 0, 0, 0, tile->getTexture(2, data)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3, data)); + renderWest(tile, 0, 0, 0, tile->getTexture(4, data)); + renderEast(tile, 0, 0, 0, tile->getTexture(5, data)); + t.draw(); + + t.addOffset(0.5f, 0.5f, 0.5f); + + } else if (shape == Tile::SHAPE_CROSS_TEXTURE) { + t.begin(); + tesselateCrossTexture(tile, data, -0.5f, -0.5f, -0.5f); + t.draw(); + } else if(shape == Tile::SHAPE_STEM) { + t.begin(); + tile->updateDefaultShape(); + tesselateStemTexture(tile, data, tile->yy1, -0.5f, -0.5f, -0.5f); + t.draw(); + } else if (shape == Tile::SHAPE_CACTUS) { + tile->updateDefaultShape(); + t.offset(-0.5f, -0.5f, -0.5f); + float s = 1 / 16.0f; + t.begin(); + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); + t.addOffset(0, 0, s); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + t.addOffset(0, 0, -s); + t.addOffset(0, 0, -s); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + t.addOffset(0, 0, s); + t.addOffset(s, 0, 0); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + t.addOffset(-s, 0, 0); + t.addOffset(-s, 0, 0); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + t.addOffset(s, 0, 0); + t.draw(); + t.offset(0, 0, 0);//0.5f, 0.5f, 0.5f); + } else if (shape == Tile::SHAPE_ROWS) { + t.begin(); + t.normal(0, -1, 0); + tesselateRowTexture(tile, data, -0.5f, -0.5f, -0.5f); + //} else if (shape == Tile::SHAPE_TORCH) { + //// t.begin(); + //// t.normal(0, -1, 0); + //// tesselateTorch(tile, -0.5f, -0.5f, -0.5f, 0, 0); + //// t.end(); + } else if (shape == Tile::SHAPE_ENTITYTILE_ANIMATED) { + EntityTileRenderer::instance->render(tile, data, 1.0f); + //glEnable(GL_RESCALE_NORMAL); + } else if (shape == Tile::SHAPE_STAIRS) { + t.addOffset(-0.5f, -0.5f, -0.5f); + t.begin(); + for (int i = 0; i < 2; i++) { + if (i == 0) tile->setShape(0, 0, 0, 1, 1, 0.5f); + if (i == 1) tile->setShape(0, 0, 0.5f, 1, 0.5f, 1); + + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + } + t.draw(); + t.addOffset(0.5f, 0.5f, 0.5f); + } + else if (shape == Tile::SHAPE_FENCE) { + t.addOffset(-0.5f, -0.5f, -0.5f); + t.begin(); + for (int i = 0; i < 4; i++) { + float w = 2 / 16.0f; + if (i == 0) tile->setShape(0.5f - w, 0, 0, 0.5f + w, 1, w * 2); + if (i == 1) tile->setShape(0.5f - w, 0, 1 - w * 2, 0.5f + w, 1, 1); + w = 1 / 16.0f; + if (i == 2) tile->setShape(0.5f - w, 1 - w * 3, -w * 2, 0.5f + w, 1 - w, 1 + w * 2); + if (i == 3) tile->setShape(0.5f - w, 0.5f - w * 3, -w * 2, 0.5f + w, 0.5f - w, 1 + w * 2); + + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + } + t.draw(); + t.addOffset(0.5f, 0.5f, 0.5f); + tile->setShape(0, 0, 0, 1, 1, 1); + } else if (shape == Tile::SHAPE_FENCE_GATE) { + t.addOffset(-0.5f, -0.5f, -0.5f); + t.begin(); + for (int i = 0; i < 3; i++) { + float w = 1 / 16.0f; + if (i == 0) tile->setShape(0.5f - w, .3f, 0, 0.5f + w, 1, w * 2); + if (i == 1) tile->setShape(0.5f - w, .3f, 1 - w * 2, 0.5f + w, 1, 1); + if (i == 2) tile->setShape(0.5f - w, .5f, w * 2, 0.5f + w, 1 - w, 1 - w * 2); + + renderFaceUp(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceDown(tile, 0, 0, 0, tile->getTexture(1)); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + } + t.draw(); + t.addOffset(0.5f, 0.5f, 0.5f); + tile->setShape(0, 0, 0, 1, 1, 1); + } + +} + +bool TileRenderer::canRender( int renderShape ) +{ + if (renderShape == Tile::SHAPE_BLOCK) return true; + if (renderShape == Tile::SHAPE_CACTUS) return true; + if (renderShape == Tile::SHAPE_STAIRS) return true; + if (renderShape == Tile::SHAPE_FENCE) return true; + if (renderShape == Tile::SHAPE_FENCE_GATE) return true; + //if (renderShape == Tile::SHAPE_CROSS_TEXTURE) return true; + //if (renderShape == Tile::SHAPE_ENTITYTILE_ANIMATED) return true; + + return false; +} + +void TileRenderer::renderGuiTile( Tile* tile, int data ) +{ + Tesselator& t = Tesselator::instance; + + int shape = tile->getRenderShape(); + + if (shape == Tile::SHAPE_BLOCK) { + tile->updateDefaultShape(); + + t.begin(); + t.addOffset(-0.5f, -0.5f, -0.5f); + t.color(0xff, 0xff, 0xff); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1, data)); + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0, data)); + + t.color(0x80, 0x80, 0x80); + renderNorth(tile, 0, 0, 0, tile->getTexture(2, data)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3, data)); + + t.color(0xbb, 0xbb, 0xbb); + renderEast(tile, 0, 0, 0, tile->getTexture(5, data)); + renderWest(tile, 0, 0, 0, tile->getTexture(4, data)); + t.draw(); + t.addOffset(0.5f, 0.5f, 0.5f); + + } else if (shape == Tile::SHAPE_CROSS_TEXTURE) { + t.begin(); + //t.normal(0, -1, 0); + tesselateCrossTexture(tile, data, -0.5f, -0.5f, -0.5f); + //t.end(); + t.draw(); + } else if (shape == Tile::SHAPE_CACTUS) { + tile->updateDefaultShape(); + t.begin(); + t.offset(-0.5f, -0.5f, -0.5f); + float s = 1 / 16.0f; + t.color(0xff, 0xff, 0xff); + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); + + t.color(0x80, 0x80, 0x80); + t.addOffset(0, 0, s); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + t.addOffset(0, 0, -s-s); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + + t.color(0xbb, 0xbb, 0xbb); + t.addOffset(s, 0, s); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + t.addOffset(-s-s, 0, 0); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + + t.draw(); + t.addOffset(s+0.5f, 0.5f, 0.5f); + } else if (shape == Tile::SHAPE_STAIRS) { + t.offset(-0.5f, -0.5f, -0.5f); + t.begin(); + for (int i = 0; i < 2; i++) { + if (i == 0) tile->setShape(0, 0, 0, 1, 1, 0.5f); + if (i == 1) tile->setShape(0, 0, 0.5f, 1, 0.5f, 1); + + t.color(0xff, 0xff, 0xff); + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); + + t.color(0x80, 0x80, 0x80); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + + t.color(0xbb, 0xbb, 0xbb); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + } + t.draw(); + t.offset(0, 0, 0); + } + else if (shape == Tile::SHAPE_FENCE) { + t.addOffset(-0.5f, -0.5f, -0.5f); + t.begin(); + for (int i = 0; i < 4; i++) { + float w = 2 / 16.0f; + if (i == 0) tile->setShape(0.5f - w, 0, 0, 0.5f + w, 1, w * 2); + if (i == 1) tile->setShape(0.5f - w, 0, 1 - w * 2, 0.5f + w, 1, 1); + w = 1 / 16.0f; + if (i == 2) tile->setShape(0.5f - w, 1 - w * 3, -w * 2, 0.5f + w, 1 - w, 1 + w * 2); + if (i == 3) tile->setShape(0.5f - w, 0.5f - w * 3, -w * 2, 0.5f + w, 0.5f - w, 1 + w * 2); + + t.color(0xff, 0xff, 0xff); + + renderFaceDown(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(1)); + + t.color(0x80, 0x80, 0x80); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + + t.color(0xbb, 0xbb, 0xbb); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + } + t.draw(); + t.addOffset(0.5f, 0.5f, 0.5f); + tile->setShape(0, 0, 0, 1, 1, 1); + } + else if (shape == Tile::SHAPE_FENCE_GATE) { + t.addOffset(-0.5f, -0.5f, -0.5f); + t.begin(); + for (int i = 0; i < 3; i++) { + float w = 1 / 16.0f; + if (i == 0) tile->setShape(0.5f - w, .3f, 0, 0.5f + w, 1, w * 2); + if (i == 1) tile->setShape(0.5f - w, .3f, 1 - w * 2, 0.5f + w, 1, 1); + w = 1 / 16.0f; + if (i == 2) tile->setShape(0.5f - w, .5f, 0, 0.5f + w, 1 - w, 1); + + t.color(0xff, 0xff, 0xff); + renderFaceUp(tile, 0, 0, 0, tile->getTexture(0)); + renderFaceDown(tile, 0, 0, 0, tile->getTexture(1)); + + t.color(0x80, 0x80, 0x80); + renderNorth(tile, 0, 0, 0, tile->getTexture(2)); + renderSouth(tile, 0, 0, 0, tile->getTexture(3)); + + t.color(0xbb, 0xbb, 0xbb); + renderWest(tile, 0, 0, 0, tile->getTexture(4)); + renderEast(tile, 0, 0, 0, tile->getTexture(5)); + } + t.draw(); + tile->setShape(0, 0, 0, 1, 1, 1); + t.addOffset(0.5f, 0.5f, 0.5f); + } +} + +bool TileRenderer::tesselateThinFenceInWorld(ThinFenceTile* tt, int x, int y, int z) { + const int depth = 128; + Tesselator& t = Tesselator::instance; + + float br = tt->getBrightness(level, x, y, z); + int col = tt->getColor(level, x, y, z); + float r = ((col >> 16) & 0xff) / 255.0f; + float g = ((col >> 8) & 0xff) / 255.0f; + float b = ((col) & 0xff) / 255.0f; + + //if (GameRenderer::anaglyph3d) { + // float cr = (r * 30 + g * 59 + b * 11) / 100; + // float cg = (r * 30 + g * 70) / (100); + // float cb = (r * 30 + b * 70) / (100); + + // r = cr; + // g = cg; + // b = cb; + //} + t.color(br * r, br * g, br * b); + + int tex = 0; + int edgeTex = 0; + + if (fixedTexture >= 0) { + tex = fixedTexture; + edgeTex = fixedTexture; + } else { + int data = level->getData(x, y, z); + tex = tt->getTexture(0, data); + edgeTex = tt->getEdgeTexture(); + } + + const int xt = (tex & 0xf) << 4; + const int yt = tex & 0xf0; + float u0 = (xt) / 256.0f; + const float u1 = (xt + 7.99f) / 256.0f; + const float u2 = (xt + 15.99f) / 256.0f; + const float v0 = (yt) / 256.0f; + const float v2 = (yt + 15.99f) / 256.0f; + + const int xet = (edgeTex & 0xf) << 4; + const int yet = edgeTex & 0xf0; + + const float iu0 = (xet + 7) / 256.0f; + const float iu1 = (xet + 8.99f) / 256.0f; + const float iv0 = (yet) / 256.0f; + const float iv1 = (yet + 8) / 256.0f; + const float iv2 = (yet + 15.99f) / 256.0f; + + const float x0 = (float)x; + const float x1 = x0 + .5f; + const float x2 = x0 + 1; + const float y0 = (float)y + 0.001f; + const float y1 = y0 + 1 - 0.002f; + const float z0 = (float)z; + const float z1 = z0 + .5f; + const float z2 = z0 + 1; + const float ix0 = x0 + .5f - 1.0f / 16.0f; + const float ix1 = x0 + .5f + 1.0f / 16.0f; + const float iz0 = z0 + .5f - 1.0f / 16.0f; + const float iz1 = z0 + .5f + 1.0f / 16.0f; + + const bool n = tt->attachsTo(level->getTile(x, y, z - 1)); + const bool s = tt->attachsTo(level->getTile(x, y, z + 1)); + const bool w = tt->attachsTo(level->getTile(x - 1, y, z)); + const bool e = tt->attachsTo(level->getTile(x + 1, y, z)); + + const bool up = tt->shouldRenderFace(level, x, y + 1, z, Facing::UP); + const bool down = tt->shouldRenderFace(level, x, y - 1, z, Facing::DOWN); + + const float noZFightingOffset = 0.01f; + + if ((w && e) || (!w && !e && !n && !s)) { + t.vertexUV(x0, y1, z1, u0, v0); + t.vertexUV(x0, y0, z1, u0, v2); + t.vertexUV(x2, y0, z1, u2, v2); + t.vertexUV(x2, y1, z1, u2, v0); + + t.vertexUV(x2, y1, z1, u0, v0); + t.vertexUV(x2, y0, z1, u0, v2); + t.vertexUV(x0, y0, z1, u2, v2); + t.vertexUV(x0, y1, z1, u2, v0); + + if (up) { + // small edge texture + t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv0); + t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv2); + + t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv0); + t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv2); + } else { + if (y < (depth - 1) && level->isEmptyTile(x - 1, y + 1, z)) { + t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv1); + + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); + } + if (y < (depth - 1) && level->isEmptyTile(x + 1, y + 1, z)) { + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv0); + + t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv0); + } + } + if (down) { + // small edge texture + t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv0); + t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv2); + + t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv0); + t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv2); + } else { + if (y > 1 && level->isEmptyTile(x - 1, y - 1, z)) { + t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv1); + + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); + } + if (y > 1 && level->isEmptyTile(x + 1, y - 1, z)) { + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv0); + + t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv0); + } + } + + } else if (w && !e) { + // half-step towards west + t.vertexUV(x0, y1, z1, u0, v0); + t.vertexUV(x0, y0, z1, u0, v2); + t.vertexUV(x1, y0, z1, u1, v2); + t.vertexUV(x1, y1, z1, u1, v0); + + t.vertexUV(x1, y1, z1, u0, v0); + t.vertexUV(x1, y0, z1, u0, v2); + t.vertexUV(x0, y0, z1, u1, v2); + t.vertexUV(x0, y1, z1, u1, v0); + + // small edge texture + if (!s && !n) { + t.vertexUV(x1, y1, iz1, iu0, iv0); + t.vertexUV(x1, y0, iz1, iu0, iv2); + t.vertexUV(x1, y0, iz0, iu1, iv2); + t.vertexUV(x1, y1, iz0, iu1, iv0); + + t.vertexUV(x1, y1, iz0, iu0, iv0); + t.vertexUV(x1, y0, iz0, iu0, iv2); + t.vertexUV(x1, y0, iz1, iu1, iv2); + t.vertexUV(x1, y1, iz1, iu1, iv0); + } + + if (up || (y < (depth - 1) && level->isEmptyTile(x - 1, y + 1, z))) { + // small edge texture + t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv1); + + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x0, y1 + noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x0, y1 + noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); + } + if (down || (y > 1 && level->isEmptyTile(x - 1, y - 1, z))) { + // small edge texture + t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv1); + + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x0, y0 - noZFightingOffset, iz1, iu1, iv2); + t.vertexUV(x0, y0 - noZFightingOffset, iz0, iu0, iv2); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); + } + + } else if (!w && e) { + // half-step towards east + t.vertexUV(x1, y1, z1, u1, v0); + t.vertexUV(x1, y0, z1, u1, v2); + t.vertexUV(x2, y0, z1, u2, v2); + t.vertexUV(x2, y1, z1, u2, v0); + + t.vertexUV(x2, y1, z1, u1, v0); + t.vertexUV(x2, y0, z1, u1, v2); + t.vertexUV(x1, y0, z1, u2, v2); + t.vertexUV(x1, y1, z1, u2, v0); + + // small edge texture + if (!s && !n) { + t.vertexUV(x1, y1, iz0, iu0, iv0); + t.vertexUV(x1, y0, iz0, iu0, iv2); + t.vertexUV(x1, y0, iz1, iu1, iv2); + t.vertexUV(x1, y1, iz1, iu1, iv0); + + t.vertexUV(x1, y1, iz1, iu0, iv0); + t.vertexUV(x1, y0, iz1, iu0, iv2); + t.vertexUV(x1, y0, iz0, iu1, iv2); + t.vertexUV(x1, y1, iz0, iu1, iv0); + } + + if (up || (y < (depth - 1) && level->isEmptyTile(x + 1, y + 1, z))) { + // small edge texture + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv0); + + t.vertexUV(x2, y1 + noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x1, y1 + noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y1 + noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x2, y1 + noZFightingOffset, iz0, iu0, iv0); + } + if (down || (y > 1 && level->isEmptyTile(x + 1, y - 1, z))) { + // small edge texture + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv0); + + t.vertexUV(x2, y0 - noZFightingOffset, iz1, iu1, iv0); + t.vertexUV(x1, y0 - noZFightingOffset, iz1, iu1, iv1); + t.vertexUV(x1, y0 - noZFightingOffset, iz0, iu0, iv1); + t.vertexUV(x2, y0 - noZFightingOffset, iz0, iu0, iv0); + } + + } + + if ((n && s) || (!w && !e && !n && !s)) { + // straight north-south + t.vertexUV(x1, y1, z2, u0, v0); + t.vertexUV(x1, y0, z2, u0, v2); + t.vertexUV(x1, y0, z0, u2, v2); + t.vertexUV(x1, y1, z0, u2, v0); + + t.vertexUV(x1, y1, z0, u0, v0); + t.vertexUV(x1, y0, z0, u0, v2); + t.vertexUV(x1, y0, z2, u2, v2); + t.vertexUV(x1, y1, z2, u2, v0); + + if (up) { + // small edge texture + t.vertexUV(ix1, y1, z2, iu1, iv2); + t.vertexUV(ix1, y1, z0, iu1, iv0); + t.vertexUV(ix0, y1, z0, iu0, iv0); + t.vertexUV(ix0, y1, z2, iu0, iv2); + + t.vertexUV(ix1, y1, z0, iu1, iv2); + t.vertexUV(ix1, y1, z2, iu1, iv0); + t.vertexUV(ix0, y1, z2, iu0, iv0); + t.vertexUV(ix0, y1, z0, iu0, iv2); + } else { + if (y < (depth - 1) && level->isEmptyTile(x, y + 1, z - 1)) { + t.vertexUV(ix0, y1, z0, iu1, iv0); + t.vertexUV(ix0, y1, z1, iu1, iv1); + t.vertexUV(ix1, y1, z1, iu0, iv1); + t.vertexUV(ix1, y1, z0, iu0, iv0); + + t.vertexUV(ix0, y1, z1, iu1, iv0); + t.vertexUV(ix0, y1, z0, iu1, iv1); + t.vertexUV(ix1, y1, z0, iu0, iv1); + t.vertexUV(ix1, y1, z1, iu0, iv0); + } + if (y < (depth - 1) && level->isEmptyTile(x, y + 1, z + 1)) { + t.vertexUV(ix0, y1, z1, iu0, iv1); + t.vertexUV(ix0, y1, z2, iu0, iv2); + t.vertexUV(ix1, y1, z2, iu1, iv2); + t.vertexUV(ix1, y1, z1, iu1, iv1); + + t.vertexUV(ix0, y1, z2, iu0, iv1); + t.vertexUV(ix0, y1, z1, iu0, iv2); + t.vertexUV(ix1, y1, z1, iu1, iv2); + t.vertexUV(ix1, y1, z2, iu1, iv1); + } + } + if (down) { + // small edge texture + t.vertexUV(ix1, y0, z2, iu1, iv2); + t.vertexUV(ix1, y0, z0, iu1, iv0); + t.vertexUV(ix0, y0, z0, iu0, iv0); + t.vertexUV(ix0, y0, z2, iu0, iv2); + + t.vertexUV(ix1, y0, z0, iu1, iv2); + t.vertexUV(ix1, y0, z2, iu1, iv0); + t.vertexUV(ix0, y0, z2, iu0, iv0); + t.vertexUV(ix0, y0, z0, iu0, iv2); + } else { + if (y > 1 && level->isEmptyTile(x, y - 1, z - 1)) { + // north half-step + t.vertexUV(ix0, y0, z0, iu1, iv0); + t.vertexUV(ix0, y0, z1, iu1, iv1); + t.vertexUV(ix1, y0, z1, iu0, iv1); + t.vertexUV(ix1, y0, z0, iu0, iv0); + + t.vertexUV(ix0, y0, z1, iu1, iv0); + t.vertexUV(ix0, y0, z0, iu1, iv1); + t.vertexUV(ix1, y0, z0, iu0, iv1); + t.vertexUV(ix1, y0, z1, iu0, iv0); + } + if (y > 1 && level->isEmptyTile(x, y - 1, z + 1)) { + // south half-step + t.vertexUV(ix0, y0, z1, iu0, iv1); + t.vertexUV(ix0, y0, z2, iu0, iv2); + t.vertexUV(ix1, y0, z2, iu1, iv2); + t.vertexUV(ix1, y0, z1, iu1, iv1); + + t.vertexUV(ix0, y0, z2, iu0, iv1); + t.vertexUV(ix0, y0, z1, iu0, iv2); + t.vertexUV(ix1, y0, z1, iu1, iv2); + t.vertexUV(ix1, y0, z2, iu1, iv1); + } + } + + } else if (n && !s) { + // half-step towards north + t.vertexUV(x1, y1, z0, u0, v0); + t.vertexUV(x1, y0, z0, u0, v2); + t.vertexUV(x1, y0, z1, u1, v2); + t.vertexUV(x1, y1, z1, u1, v0); + + t.vertexUV(x1, y1, z1, u0, v0); + t.vertexUV(x1, y0, z1, u0, v2); + t.vertexUV(x1, y0, z0, u1, v2); + t.vertexUV(x1, y1, z0, u1, v0); + + // small edge texture + if (!e && !w) { + t.vertexUV(ix0, y1, z1, iu0, iv0); + t.vertexUV(ix0, y0, z1, iu0, iv2); + t.vertexUV(ix1, y0, z1, iu1, iv2); + t.vertexUV(ix1, y1, z1, iu1, iv0); + + t.vertexUV(ix1, y1, z1, iu0, iv0); + t.vertexUV(ix1, y0, z1, iu0, iv2); + t.vertexUV(ix0, y0, z1, iu1, iv2); + t.vertexUV(ix0, y1, z1, iu1, iv0); + } + + if (up || (y < (depth - 1) && level->isEmptyTile(x, y + 1, z - 1))) { + // small edge texture + t.vertexUV(ix0, y1, z0, iu1, iv0); + t.vertexUV(ix0, y1, z1, iu1, iv1); + t.vertexUV(ix1, y1, z1, iu0, iv1); + t.vertexUV(ix1, y1, z0, iu0, iv0); + + t.vertexUV(ix0, y1, z1, iu1, iv0); + t.vertexUV(ix0, y1, z0, iu1, iv1); + t.vertexUV(ix1, y1, z0, iu0, iv1); + t.vertexUV(ix1, y1, z1, iu0, iv0); + } + + if (down || (y > 1 && level->isEmptyTile(x, y - 1, z - 1))) { + // small edge texture + t.vertexUV(ix0, y0, z0, iu1, iv0); + t.vertexUV(ix0, y0, z1, iu1, iv1); + t.vertexUV(ix1, y0, z1, iu0, iv1); + t.vertexUV(ix1, y0, z0, iu0, iv0); + + t.vertexUV(ix0, y0, z1, iu1, iv0); + t.vertexUV(ix0, y0, z0, iu1, iv1); + t.vertexUV(ix1, y0, z0, iu0, iv1); + t.vertexUV(ix1, y0, z1, iu0, iv0); + } + + } else if (!n && s) { + // half-step towards south + t.vertexUV(x1, y1, z1, u1, v0); + t.vertexUV(x1, y0, z1, u1, v2); + t.vertexUV(x1, y0, z2, u2, v2); + t.vertexUV(x1, y1, z2, u2, v0); + + t.vertexUV(x1, y1, z2, u1, v0); + t.vertexUV(x1, y0, z2, u1, v2); + t.vertexUV(x1, y0, z1, u2, v2); + t.vertexUV(x1, y1, z1, u2, v0); + + // small edge texture + if (!e && !w) { + t.vertexUV(ix1, y1, z1, iu0, iv0); + t.vertexUV(ix1, y0, z1, iu0, iv2); + t.vertexUV(ix0, y0, z1, iu1, iv2); + t.vertexUV(ix0, y1, z1, iu1, iv0); + + t.vertexUV(ix0, y1, z1, iu0, iv0); + t.vertexUV(ix0, y0, z1, iu0, iv2); + t.vertexUV(ix1, y0, z1, iu1, iv2); + t.vertexUV(ix1, y1, z1, iu1, iv0); + } + + if (up || (y < (depth - 1) && level->isEmptyTile(x, y + 1, z + 1))) { + // small edge texture + t.vertexUV(ix0, y1, z1, iu0, iv1); + t.vertexUV(ix0, y1, z2, iu0, iv2); + t.vertexUV(ix1, y1, z2, iu1, iv2); + t.vertexUV(ix1, y1, z1, iu1, iv1); + + t.vertexUV(ix0, y1, z2, iu0, iv1); + t.vertexUV(ix0, y1, z1, iu0, iv2); + t.vertexUV(ix1, y1, z1, iu1, iv2); + t.vertexUV(ix1, y1, z2, iu1, iv1); + } + if (down || (y > 1 && level->isEmptyTile(x, y - 1, z + 1))) { + // small edge texture + t.vertexUV(ix0, y0, z1, iu0, iv1); + t.vertexUV(ix0, y0, z2, iu0, iv2); + t.vertexUV(ix1, y0, z2, iu1, iv2); + t.vertexUV(ix1, y0, z1, iu1, iv1); + + t.vertexUV(ix0, y0, z2, iu0, iv1); + t.vertexUV(ix0, y0, z1, iu0, iv2); + t.vertexUV(ix1, y0, z1, iu1, iv2); + t.vertexUV(ix1, y0, z2, iu1, iv1); + } + + } + + return true; +} + +void TileRenderer::tesselateRowTexture( Tile* tt, int data, float x, float y, float z ) { + Tesselator& t = Tesselator::instance; + + int tex = tt->getTexture(0, data); + if(fixedTexture >= 0) + tex = fixedTexture; + + int xt = (tex & 0xf) << 4; + int yt = tex & 0xf0; + float u0 = (xt) / 256.0f; + float u1 = (xt + 15.99f) / 256.f; + float v0 = (yt) / 256.0f; + float v1 = (yt + 15.99f) / 256.0f; + + float x0 = x + 0.5f - 0.25f; + float x1 = x + 0.5f + 0.25f; + float z0 = z + 0.5f - 0.5f; + float z1 = z + 0.5f + 0.5f; + t.vertexUV(x0, y + 1, z0, u0, v0); + t.vertexUV(x0, y + 0, z0, u0, v1); + t.vertexUV(x0, y + 0, z1, u1, v1); + t.vertexUV(x0, y + 1, z1, u1, v0); + + t.vertexUV(x0, y + 1, z1, u0, v0); + t.vertexUV(x0, y + 0, z1, u0, v1); + t.vertexUV(x0, y + 0, z0, u1, v1); + t.vertexUV(x0, y + 1, z0, u1, v0); + + t.vertexUV(x1, y + 1, z1, u0, v0); + t.vertexUV(x1, y + 0, z1, u0, v1); + t.vertexUV(x1, y + 0, z0, u1, v1); + t.vertexUV(x1, y + 1, z0, u1, v0); + + t.vertexUV(x1, y + 1, z0, u0, v0); + t.vertexUV(x1, y + 0, z0, u0, v1); + t.vertexUV(x1, y + 0, z1, u1, v1); + t.vertexUV(x1, y + 1, z1, u1, v0); + + x0 = x + 0.5f - 0.5f; + x1 = x + 0.5f + 0.5f; + z0 = z + 0.5f - 0.25f; + z1 = z + 0.5f + 0.25f; + + t.vertexUV(x0, y + 1, z0, u0, v0); + t.vertexUV(x0, y + 0, z0, u0, v1); + t.vertexUV(x1, y + 0, z0, u1, v1); + t.vertexUV(x1, y + 1, z0, u1, v0); + + t.vertexUV(x1, y + 1, z0, u0, v0); + t.vertexUV(x1, y + 0, z0, u0, v1); + t.vertexUV(x0, y + 0, z0, u1, v1); + t.vertexUV(x0, y + 1, z0, u1, v0); + + t.vertexUV(x1, y + 1, z1, u0, v0); + t.vertexUV(x1, y + 0, z1, u0, v1); + t.vertexUV(x0, y + 0, z1, u1, v1); + t.vertexUV(x0, y + 1, z1, u1, v0); + + t.vertexUV(x0, y + 1, z1, u0, v0); + t.vertexUV(x0, y + 0, z1, u0, v1); + t.vertexUV(x1, y + 0, z1, u1, v1); + t.vertexUV(x1, y + 1, z1, u1, v0); +} diff --git a/src/client/renderer/TileRenderer.h b/src/client/renderer/TileRenderer.hpp similarity index 100% rename from src/client/renderer/TileRenderer.h rename to src/client/renderer/TileRenderer.hpp diff --git a/src/client/renderer/VertecDecl.h b/src/client/renderer/VertecDecl.hpp similarity index 100% rename from src/client/renderer/VertecDecl.h rename to src/client/renderer/VertecDecl.hpp diff --git a/src/client/renderer/culling/AllowAllCuller.h b/src/client/renderer/culling/AllowAllCuller.hpp similarity index 95% rename from src/client/renderer/culling/AllowAllCuller.h rename to src/client/renderer/culling/AllowAllCuller.hpp index 09a664e..4816694 100755 --- a/src/client/renderer/culling/AllowAllCuller.h +++ b/src/client/renderer/culling/AllowAllCuller.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.culling; -#include "Culler.h" +#include "Culler.hpp" class AABB; diff --git a/src/client/renderer/culling/Culler.h b/src/client/renderer/culling/Culler.hpp similarity index 100% rename from src/client/renderer/culling/Culler.h rename to src/client/renderer/culling/Culler.hpp diff --git a/src/client/renderer/culling/Frustum.cpp b/src/client/renderer/culling/Frustum.cpp index e5a3832..8be08db 100755 --- a/src/client/renderer/culling/Frustum.cpp +++ b/src/client/renderer/culling/Frustum.cpp @@ -1,3 +1,3 @@ -#include "Frustum.h" - -Frustum Frustum::frustum; +#include "Frustum.hpp" + +Frustum Frustum::frustum; diff --git a/src/client/renderer/culling/Frustum.h b/src/client/renderer/culling/Frustum.hpp similarity index 98% rename from src/client/renderer/culling/Frustum.h rename to src/client/renderer/culling/Frustum.hpp index 74d1104..404f178 100755 --- a/src/client/renderer/culling/Frustum.h +++ b/src/client/renderer/culling/Frustum.hpp @@ -22,11 +22,11 @@ // // //***********************************************************************// -//#include "main.h" +//#include "main.hpp" -#include "FrustumData.h" -#include "../../../util/Mth.h" -#include "../gles.h" +#include "FrustumData.hpp" +#include "util/Mth.hpp" +#include "client/renderer/gles.hpp" class Frustum: public FrustumData { diff --git a/src/client/renderer/culling/FrustumCuller.h b/src/client/renderer/culling/FrustumCuller.hpp similarity index 94% rename from src/client/renderer/culling/FrustumCuller.h rename to src/client/renderer/culling/FrustumCuller.hpp index 8429494..b162b21 100755 --- a/src/client/renderer/culling/FrustumCuller.h +++ b/src/client/renderer/culling/FrustumCuller.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer.culling; -#include "FrustumData.h" -#include "Frustum.h" +#include "FrustumData.hpp" +#include "Frustum.hpp" class FrustumCuller: public Culler { diff --git a/src/client/renderer/culling/FrustumData.h b/src/client/renderer/culling/FrustumData.hpp similarity index 99% rename from src/client/renderer/culling/FrustumData.h rename to src/client/renderer/culling/FrustumData.hpp index 5f2c4b6..9f6c5e0 100755 --- a/src/client/renderer/culling/FrustumData.h +++ b/src/client/renderer/culling/FrustumData.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.culling; -#include "../../../world/phys/AABB.h" +#include "world/phys/AABB.hpp" // We create an enum of the sides so we don't have to call each side 0 or 1. // This way it makes it more understandable and readable when dealing with frustum sides. diff --git a/src/client/renderer/culling/tmp/Frustum.h b/src/client/renderer/culling/tmp/Frustum.hpp similarity index 98% rename from src/client/renderer/culling/tmp/Frustum.h rename to src/client/renderer/culling/tmp/Frustum.hpp index e8be6e8..6f7d4e4 100755 --- a/src/client/renderer/culling/tmp/Frustum.h +++ b/src/client/renderer/culling/tmp/Frustum.hpp @@ -4,9 +4,9 @@ /* import static org.lwjgl.opengl.GL11.* */ -#include "java/nio/FloatBuffer.h" +#include "java/nio/FloatBuffer.hpp" -#include "client/MemoryTracker.h" +#include "client/MemoryTracker.hpp" // Stolen and ported to java from the web somewhere. @@ -25,7 +25,7 @@ // // //***********************************************************************// -//#include "main.h" +//#include "main.hpp" // We create an enum of the sides so we don't have to call each side 0 or 1. // This way it makes it more understandable and readable when dealing with frustum sides. diff --git a/src/client/renderer/culling/tmp/FrustumCuller.h b/src/client/renderer/culling/tmp/FrustumCuller.hpp similarity index 99% rename from src/client/renderer/culling/tmp/FrustumCuller.h rename to src/client/renderer/culling/tmp/FrustumCuller.hpp index b23fd61..26e155f 100755 --- a/src/client/renderer/culling/tmp/FrustumCuller.h +++ b/src/client/renderer/culling/tmp/FrustumCuller.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer.culling; -#include "Culler.h" -#include "../../../world/phys/AABB.h" +#include "Culler.hpp" +#include "client/world/phys/AABB.hpp" class FrustumCuller: public Culler { diff --git a/src/client/renderer/culling/tmp/FrustumData.h b/src/client/renderer/culling/tmp/FrustumData.hpp similarity index 99% rename from src/client/renderer/culling/tmp/FrustumData.h rename to src/client/renderer/culling/tmp/FrustumData.hpp index 3a6d9ba..7ff8085 100755 --- a/src/client/renderer/culling/tmp/FrustumData.h +++ b/src/client/renderer/culling/tmp/FrustumData.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.culling; -#include "world/phys/AABB.h" +#include "world/phys/AABB.hpp" /*public*/ class FrustumData diff --git a/src/client/renderer/culling/tmp/_FrustumCuller.h b/src/client/renderer/culling/tmp/_FrustumCuller.hpp similarity index 96% rename from src/client/renderer/culling/tmp/_FrustumCuller.h rename to src/client/renderer/culling/tmp/_FrustumCuller.hpp index 6202855..3f5befa 100755 --- a/src/client/renderer/culling/tmp/_FrustumCuller.h +++ b/src/client/renderer/culling/tmp/_FrustumCuller.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.culling; -#include "world/phys/AABB.h" +#include "world/phys/AABB.hpp" /*public*/ class FrustumCuller: /*implements-interface*/ public Culler { diff --git a/src/client/renderer/entity/ArrowRenderer.cpp b/src/client/renderer/entity/ArrowRenderer.cpp index f24edfb..8f29c3b 100755 --- a/src/client/renderer/entity/ArrowRenderer.cpp +++ b/src/client/renderer/entity/ArrowRenderer.cpp @@ -1,63 +1,63 @@ -#include "ArrowRenderer.h" - -#include "../Tesselator.h" -#include "../Textures.h" -#include "../gles.h" -#include "../../../world/entity/Entity.h" -#include "../../../world/entity/projectile/Arrow.h" - -void ArrowRenderer::render(Entity* entity, float x, float y, float z, float rot, float a) { - bindTexture("item/arrows.png"); - Arrow* arrow = (Arrow*) entity; - glPushMatrix2(); - glTranslatef(x, y, z); - glRotatef(arrow->yRotO + (arrow->yRot - arrow->yRotO) * a - 90, 0, 1, 0); - glRotatef(arrow->xRotO + (arrow->xRot - arrow->xRotO) * a, 0, 0, 1); - Tesselator& t = Tesselator::instance; - - int type = 0; - - float u0 = 0 / 32.0f; - float u1 = 16 / 32.0f; - float v0 = (0 + type * 10) / 32.0f; - float v1 = (5 + type * 10) / 32.0f; - - float u02 = 0 / 32.0f; - float u12 = 5 / 32.0f; - float v02 = (5 + type * 10) / 32.0f; - float v12 = (10 + type * 10) / 32.0f; - float ss = 0.9f / 16.0f; - float shake = arrow->shakeTime - a; - if (shake > 0) { - float pow = -Mth::sin(shake * 3) * shake; - glRotatef(pow, 0, 0, 1); - } - glRotatef(45, 1, 0, 0); - glScalef(ss, ss, ss); - - glTranslatef(-4, 0, 0); - - t.begin(); - t.vertexUV(-7, -2, -2, u02, v02); - t.vertexUV(-7, -2, +2, u12, v02); - t.vertexUV(-7, +2, +2, u12, v12); - t.vertexUV(-7, +2, -2, u02, v12); - - t.vertexUV(-7, +2, -2, u02, v02); - t.vertexUV(-7, +2, +2, u12, v02); - t.vertexUV(-7, -2, +2, u12, v12); - t.vertexUV(-7, -2, -2, u02, v12); - t.draw(); - - for (int i = 0; i < 4; i++) { - glRotatef(90, 1, 0, 0); - t.begin(); - t.vertexUV(-8, -2, 0, u0, v0); - t.vertexUV(+8, -2, 0, u1, v0); - t.vertexUV(+8, +2, 0, u1, v1); - t.vertexUV(-8, +2, 0, u0, v1); - t.endOverrideAndDraw(); - } - - glPopMatrix2(); +#include "ArrowRenderer.hpp" + +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "client/renderer/gles.hpp" +#include "world/entity/Entity.hpp" +#include "world/entity/projectile/Arrow.hpp" + +void ArrowRenderer::render(Entity* entity, float x, float y, float z, float rot, float a) { + bindTexture("item/arrows.png"); + Arrow* arrow = (Arrow*) entity; + glPushMatrix2(); + glTranslatef(x, y, z); + glRotatef(arrow->yRotO + (arrow->yRot - arrow->yRotO) * a - 90, 0, 1, 0); + glRotatef(arrow->xRotO + (arrow->xRot - arrow->xRotO) * a, 0, 0, 1); + Tesselator& t = Tesselator::instance; + + int type = 0; + + float u0 = 0 / 32.0f; + float u1 = 16 / 32.0f; + float v0 = (0 + type * 10) / 32.0f; + float v1 = (5 + type * 10) / 32.0f; + + float u02 = 0 / 32.0f; + float u12 = 5 / 32.0f; + float v02 = (5 + type * 10) / 32.0f; + float v12 = (10 + type * 10) / 32.0f; + float ss = 0.9f / 16.0f; + float shake = arrow->shakeTime - a; + if (shake > 0) { + float pow = -Mth::sin(shake * 3) * shake; + glRotatef(pow, 0, 0, 1); + } + glRotatef(45, 1, 0, 0); + glScalef(ss, ss, ss); + + glTranslatef(-4, 0, 0); + + t.begin(); + t.vertexUV(-7, -2, -2, u02, v02); + t.vertexUV(-7, -2, +2, u12, v02); + t.vertexUV(-7, +2, +2, u12, v12); + t.vertexUV(-7, +2, -2, u02, v12); + + t.vertexUV(-7, +2, -2, u02, v02); + t.vertexUV(-7, +2, +2, u12, v02); + t.vertexUV(-7, -2, +2, u12, v12); + t.vertexUV(-7, -2, -2, u02, v12); + t.draw(); + + for (int i = 0; i < 4; i++) { + glRotatef(90, 1, 0, 0); + t.begin(); + t.vertexUV(-8, -2, 0, u0, v0); + t.vertexUV(+8, -2, 0, u1, v0); + t.vertexUV(+8, +2, 0, u1, v1); + t.vertexUV(-8, +2, 0, u0, v1); + t.endOverrideAndDraw(); + } + + glPopMatrix2(); } \ No newline at end of file diff --git a/src/client/renderer/entity/ArrowRenderer.h b/src/client/renderer/entity/ArrowRenderer.hpp similarity index 82% rename from src/client/renderer/entity/ArrowRenderer.h rename to src/client/renderer/entity/ArrowRenderer.hpp index a220122..0c50afd 100755 --- a/src/client/renderer/entity/ArrowRenderer.h +++ b/src/client/renderer/entity/ArrowRenderer.hpp @@ -1,5 +1,5 @@ #pragma once -#include "EntityRenderer.h" +#include "EntityRenderer.hpp" class ArrowRenderer : public EntityRenderer { void render(Entity* arrow, float x, float y, float z, float rot, float a); diff --git a/src/client/renderer/entity/ChickenRenderer.cpp b/src/client/renderer/entity/ChickenRenderer.cpp index 3cc7eff..8a44e9d 100755 --- a/src/client/renderer/entity/ChickenRenderer.cpp +++ b/src/client/renderer/entity/ChickenRenderer.cpp @@ -1,23 +1,23 @@ -#include "ChickenRenderer.h" -#include "../../../util/Mth.h" -#include "../../../world/entity/animal/Chicken.h" - - -ChickenRenderer::ChickenRenderer( Model* model, float shadow ) -: super(model, shadow) -{ -} - -void ChickenRenderer::render( Entity* mob, float x, float y, float z, float rot, float a ) -{ - super::render(mob, x, y, z, rot, a); -} - -float ChickenRenderer::getBob( Mob* mob_, float a ) -{ - Chicken* mob = (Chicken*) mob_; - float flap = mob->oFlap+(mob->flap-mob->oFlap)*a; - float flapSpeed = mob->oFlapSpeed+(mob->flapSpeed-mob->oFlapSpeed)*a; - - return (Mth::sin(flap)+1)*flapSpeed; -} +#include "ChickenRenderer.hpp" +#include "util/Mth.hpp" +#include "world/entity/animal/Chicken.hpp" + + +ChickenRenderer::ChickenRenderer( Model* model, float shadow ) +: super(model, shadow) +{ +} + +void ChickenRenderer::render( Entity* mob, float x, float y, float z, float rot, float a ) +{ + super::render(mob, x, y, z, rot, a); +} + +float ChickenRenderer::getBob( Mob* mob_, float a ) +{ + Chicken* mob = (Chicken*) mob_; + float flap = mob->oFlap+(mob->flap-mob->oFlap)*a; + float flapSpeed = mob->oFlapSpeed+(mob->flapSpeed-mob->oFlapSpeed)*a; + + return (Mth::sin(flap)+1)*flapSpeed; +} diff --git a/src/client/renderer/entity/ChickenRenderer.h b/src/client/renderer/entity/ChickenRenderer.hpp similarity index 92% rename from src/client/renderer/entity/ChickenRenderer.h rename to src/client/renderer/entity/ChickenRenderer.hpp index 1e9dc1a..f2bf22a 100755 --- a/src/client/renderer/entity/ChickenRenderer.h +++ b/src/client/renderer/entity/ChickenRenderer.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.entity; -#include "MobRenderer.h" +#include "MobRenderer.hpp" class Mob; diff --git a/src/client/renderer/entity/CreeperRenderer.h b/src/client/renderer/entity/CreeperRenderer.hpp similarity index 92% rename from src/client/renderer/entity/CreeperRenderer.h rename to src/client/renderer/entity/CreeperRenderer.hpp index 077d832..87a187f 100755 --- a/src/client/renderer/entity/CreeperRenderer.h +++ b/src/client/renderer/entity/CreeperRenderer.hpp @@ -2,12 +2,12 @@ //package net.minecraft.client.renderer.entity; -#include "MobRenderer.h" +#include "MobRenderer.hpp" -#include "../../model/CreeperModel.h" -#include "../../model/Model.h" -#include "../../../world/entity/monster/Creeper.h" -#include "../../../util/Mth.h" +#include "client/model/CreeperModel.hpp" +#include "client/model/Model.hpp" +#include "world/entity/monster/Creeper.hpp" +#include "util/Mth.hpp" class CreeperRenderer: public MobRenderer { diff --git a/src/client/renderer/entity/EntityRenderDispatcher.cpp b/src/client/renderer/entity/EntityRenderDispatcher.cpp index a3148fc..fa62a30 100755 --- a/src/client/renderer/entity/EntityRenderDispatcher.cpp +++ b/src/client/renderer/entity/EntityRenderDispatcher.cpp @@ -1,194 +1,194 @@ -#include "EntityRenderDispatcher.h" - -#include "../../Options.h" -#include "../../../world/entity/player/Player.h" -#include "../../../world/item/Item.h" -#include "../../../world/level/Level.h" -#include "../../../world/level/tile/Tile.h" -#include "../../model/ModelInclude.h" - -#include "ItemSpriteRenderer.h" -#include "FallingTileRenderer.h" - -#include "HumanoidMobRenderer.h" -#include "ItemRenderer.h" -#include "TntRenderer.h" -#include "TripodCameraRenderer.h" -#include "PigRenderer.h" -#include "MobRenderer.h" -#include "PlayerRenderer.h" - -#include "CreeperRenderer.h" -#include "SpiderRenderer.h" - -#include "ChickenRenderer.h" -#include "SheepRenderer.h" -#include "ArrowRenderer.h" -#include "PaintingRenderer.h" - - -/*static*/ -EntityRenderDispatcher* EntityRenderDispatcher::instance = NULL; - -/*static*/ -float EntityRenderDispatcher::xOff = 0, - EntityRenderDispatcher::yOff = 0, - EntityRenderDispatcher::zOff = 0; - -EntityRenderDispatcher::EntityRenderDispatcher() -: itemInHandRenderer(NULL) -{ - //@note: The Models (model/armor) will be deleted by resp. MobRenderer - assign( ER_ITEM_RENDERER, new ItemRenderer()); - assign( ER_HUMANOID_RENDERER, new HumanoidMobRenderer(new HumanoidModel(), 0)); - assign( ER_PIG_RENDERER, new PigRenderer(new PigModel(), NULL/*new PigModel(0.5f)*/, 0)); - assign( ER_COW_RENDERER, new MobRenderer(new CowModel(), 0)); - assign( ER_CHICKEN_RENDERER, new ChickenRenderer( new ChickenModel(), 0)); - assign( ER_SHEEP_RENDERER, new SheepRenderer(new SheepModel(), new SheepFurModel(), 0)); - assign( ER_SKELETON_RENDERER, new HumanoidMobRenderer(new SkeletonModel(), 0.5f)); - assign( ER_ZOMBIE_RENDERER, new HumanoidMobRenderer(new ZombieModel(), 0.5f)); - assign( ER_CREEPER_RENDERER, new CreeperRenderer()); - assign( ER_SPIDER_RENDERER, new SpiderRenderer()); - assign( ER_TNT_RENDERER, new TntRenderer()); - assign( ER_ARROW_RENDERER, new ArrowRenderer()); - assign( ER_PLAYER_RENDERER, new PlayerRenderer(new HumanoidModel(0, 0, 64, 64), 0)); - assign( ER_THROWNEGG_RENDERER, new ItemSpriteRenderer(Item::egg->getIcon(0))); - assign( ER_SNOWBALL_RENDERER, new ItemSpriteRenderer(Item::snowBall->getIcon(0))); - assign( ER_PAINTING_RENDERER, new PaintingRenderer()); - assign( ER_FALLINGTILE_RENDERER,new FallingTileRenderer()); - - for (RendererIterator it = _renderers.begin(); it != _renderers.end(); ++it) { - it->second->init(this); - } -} - -void EntityRenderDispatcher::destroy() -{ - if (instance) { - delete instance; - instance = NULL; - } -} - -EntityRenderDispatcher* EntityRenderDispatcher::getInstance() -{ - if (!instance) - instance = new EntityRenderDispatcher(); - - return instance; -} - -EntityRenderDispatcher::~EntityRenderDispatcher() -{ - std::set destroyed; - for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) { - if (destroyed.find(cit->second) == destroyed.end()) { - destroyed.insert(cit->second); - delete cit->second; - } - } -} - -void EntityRenderDispatcher::prepare( Level* level, Font* font, Mob* player, Options* options, float a ) -{ - this->level = level; - this->options = options; - this->cameraEntity = player; - this->_font = font; - if(player->isSleeping()) { - int t = level->getTile(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); - if (t == Tile::bed->id) { - int data = level->getData(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); - - int direction = data & 3; - playerRotY = float(direction * 90 + 180); - playerRotX = 0; - } - } - else { - playerRotY = player->yRotO + (player->yRot - player->yRotO) * a; - playerRotX = player->xRotO + (player->xRot - player->xRotO) * a; - } - - xPlayer = player->xOld + (player->x - player->xOld) * a; - yPlayer = player->yOld + (player->y - player->yOld) * a; - zPlayer = player->zOld + (player->z - player->zOld) * a; -} - -void EntityRenderDispatcher::render( Entity* entity, float a ) -{ - float x = entity->xOld + (entity->x - entity->xOld) * a; - float y = entity->yOld + (entity->y - entity->yOld) * a; - float z = entity->zOld + (entity->z - entity->zOld) * a; - float r = entity->yRotO + (entity->yRot - entity->yRotO) * a; - - float br = entity->getBrightness(a); - glColor4f2(br, br, br, 1); - - render(entity, x - xOff, y - yOff, z - zOff, r, a); -} - -void EntityRenderDispatcher::render( Entity* entity, float x, float y, float z, float rot, float a ) -{ - EntityRenderer* renderer = getRenderer(entity); - if (renderer != NULL) { - renderer->render(entity, x, y, z, rot, a); - //renderer->postRender(entity, x, y, z, rot, a); - } -} - -EntityRenderer* EntityRenderDispatcher::getRenderer( Entity* entity ) -{ - EntityRendererId rendererId = entity->entityRendererId; - - if (rendererId == ER_QUERY_RENDERER) - rendererId = entity->queryEntityRenderer(); - - return getRenderer(rendererId); -} - -EntityRenderer* EntityRenderDispatcher::getRenderer( EntityRendererId rendererId ) -{ - - EntityRenderer* renderer = NULL; - RendererCIterator cit = _renderers.find(rendererId); - if (cit != _renderers.end()) { - renderer = cit->second; - } - return renderer; -} - -void EntityRenderDispatcher::setLevel( Level* level ) -{ - this->level = level; -} - -void EntityRenderDispatcher::setMinecraft( Minecraft* minecraft ) -{ - this->minecraft = minecraft; -} - -float EntityRenderDispatcher::distanceToSqr( float x, float y, float z ) -{ - float xd = x - xPlayer; - float yd = y - yPlayer; - float zd = z - zPlayer; - return xd * xd + yd * yd + zd * zd; -} - -Font* EntityRenderDispatcher::getFont() -{ - return _font; -} - -void EntityRenderDispatcher::onGraphicsReset() -{ - for (RendererIterator it = _renderers.begin(); it != _renderers.end(); ++it) { - it->second->onGraphicsReset(); - } -} - -void EntityRenderDispatcher::assign( EntityRendererId id, EntityRenderer* renderer ) -{ - _renderers.insert(std::make_pair(id, renderer)); -} +#include "EntityRenderDispatcher.hpp" + +#include "client/Options.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "client/model/ModelInclude.hpp" + +#include "ItemSpriteRenderer.hpp" +#include "FallingTileRenderer.hpp" + +#include "HumanoidMobRenderer.hpp" +#include "ItemRenderer.hpp" +#include "TntRenderer.hpp" +#include "TripodCameraRenderer.hpp" +#include "PigRenderer.hpp" +#include "MobRenderer.hpp" +#include "PlayerRenderer.hpp" + +#include "CreeperRenderer.hpp" +#include "SpiderRenderer.hpp" + +#include "ChickenRenderer.hpp" +#include "SheepRenderer.hpp" +#include "ArrowRenderer.hpp" +#include "PaintingRenderer.hpp" + + +/*static*/ +EntityRenderDispatcher* EntityRenderDispatcher::instance = NULL; + +/*static*/ +float EntityRenderDispatcher::xOff = 0, + EntityRenderDispatcher::yOff = 0, + EntityRenderDispatcher::zOff = 0; + +EntityRenderDispatcher::EntityRenderDispatcher() +: itemInHandRenderer(NULL) +{ + //@note: The Models (model/armor) will be deleted by resp. MobRenderer + assign( ER_ITEM_RENDERER, new ItemRenderer()); + assign( ER_HUMANOID_RENDERER, new HumanoidMobRenderer(new HumanoidModel(), 0)); + assign( ER_PIG_RENDERER, new PigRenderer(new PigModel(), NULL/*new PigModel(0.5f)*/, 0)); + assign( ER_COW_RENDERER, new MobRenderer(new CowModel(), 0)); + assign( ER_CHICKEN_RENDERER, new ChickenRenderer( new ChickenModel(), 0)); + assign( ER_SHEEP_RENDERER, new SheepRenderer(new SheepModel(), new SheepFurModel(), 0)); + assign( ER_SKELETON_RENDERER, new HumanoidMobRenderer(new SkeletonModel(), 0.5f)); + assign( ER_ZOMBIE_RENDERER, new HumanoidMobRenderer(new ZombieModel(), 0.5f)); + assign( ER_CREEPER_RENDERER, new CreeperRenderer()); + assign( ER_SPIDER_RENDERER, new SpiderRenderer()); + assign( ER_TNT_RENDERER, new TntRenderer()); + assign( ER_ARROW_RENDERER, new ArrowRenderer()); + assign( ER_PLAYER_RENDERER, new PlayerRenderer(new HumanoidModel(0, 0, 64, 64), 0)); + assign( ER_THROWNEGG_RENDERER, new ItemSpriteRenderer(Item::egg->getIcon(0))); + assign( ER_SNOWBALL_RENDERER, new ItemSpriteRenderer(Item::snowBall->getIcon(0))); + assign( ER_PAINTING_RENDERER, new PaintingRenderer()); + assign( ER_FALLINGTILE_RENDERER,new FallingTileRenderer()); + + for (RendererIterator it = _renderers.begin(); it != _renderers.end(); ++it) { + it->second->init(this); + } +} + +void EntityRenderDispatcher::destroy() +{ + if (instance) { + delete instance; + instance = NULL; + } +} + +EntityRenderDispatcher* EntityRenderDispatcher::getInstance() +{ + if (!instance) + instance = new EntityRenderDispatcher(); + + return instance; +} + +EntityRenderDispatcher::~EntityRenderDispatcher() +{ + std::set destroyed; + for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) { + if (destroyed.find(cit->second) == destroyed.end()) { + destroyed.insert(cit->second); + delete cit->second; + } + } +} + +void EntityRenderDispatcher::prepare( Level* level, Font* font, Mob* player, Options* options, float a ) +{ + this->level = level; + this->options = options; + this->cameraEntity = player; + this->_font = font; + if(player->isSleeping()) { + int t = level->getTile(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); + if (t == Tile::bed->id) { + int data = level->getData(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); + + int direction = data & 3; + playerRotY = float(direction * 90 + 180); + playerRotX = 0; + } + } + else { + playerRotY = player->yRotO + (player->yRot - player->yRotO) * a; + playerRotX = player->xRotO + (player->xRot - player->xRotO) * a; + } + + xPlayer = player->xOld + (player->x - player->xOld) * a; + yPlayer = player->yOld + (player->y - player->yOld) * a; + zPlayer = player->zOld + (player->z - player->zOld) * a; +} + +void EntityRenderDispatcher::render( Entity* entity, float a ) +{ + float x = entity->xOld + (entity->x - entity->xOld) * a; + float y = entity->yOld + (entity->y - entity->yOld) * a; + float z = entity->zOld + (entity->z - entity->zOld) * a; + float r = entity->yRotO + (entity->yRot - entity->yRotO) * a; + + float br = entity->getBrightness(a); + glColor4f2(br, br, br, 1); + + render(entity, x - xOff, y - yOff, z - zOff, r, a); +} + +void EntityRenderDispatcher::render( Entity* entity, float x, float y, float z, float rot, float a ) +{ + EntityRenderer* renderer = getRenderer(entity); + if (renderer != NULL) { + renderer->render(entity, x, y, z, rot, a); + //renderer->postRender(entity, x, y, z, rot, a); + } +} + +EntityRenderer* EntityRenderDispatcher::getRenderer( Entity* entity ) +{ + EntityRendererId rendererId = entity->entityRendererId; + + if (rendererId == ER_QUERY_RENDERER) + rendererId = entity->queryEntityRenderer(); + + return getRenderer(rendererId); +} + +EntityRenderer* EntityRenderDispatcher::getRenderer( EntityRendererId rendererId ) +{ + + EntityRenderer* renderer = NULL; + RendererCIterator cit = _renderers.find(rendererId); + if (cit != _renderers.end()) { + renderer = cit->second; + } + return renderer; +} + +void EntityRenderDispatcher::setLevel( Level* level ) +{ + this->level = level; +} + +void EntityRenderDispatcher::setMinecraft( Minecraft* minecraft ) +{ + this->minecraft = minecraft; +} + +float EntityRenderDispatcher::distanceToSqr( float x, float y, float z ) +{ + float xd = x - xPlayer; + float yd = y - yPlayer; + float zd = z - zPlayer; + return xd * xd + yd * yd + zd * zd; +} + +Font* EntityRenderDispatcher::getFont() +{ + return _font; +} + +void EntityRenderDispatcher::onGraphicsReset() +{ + for (RendererIterator it = _renderers.begin(); it != _renderers.end(); ++it) { + it->second->onGraphicsReset(); + } +} + +void EntityRenderDispatcher::assign( EntityRendererId id, EntityRenderer* renderer ) +{ + _renderers.insert(std::make_pair(id, renderer)); +} diff --git a/src/client/renderer/entity/EntityRenderDispatcher.h b/src/client/renderer/entity/EntityRenderDispatcher.hpp similarity index 96% rename from src/client/renderer/entity/EntityRenderDispatcher.h rename to src/client/renderer/entity/EntityRenderDispatcher.hpp index 1536370..90e7412 100755 --- a/src/client/renderer/entity/EntityRenderDispatcher.h +++ b/src/client/renderer/entity/EntityRenderDispatcher.hpp @@ -3,7 +3,7 @@ //package net.minecraft.client.renderer.entity; #include -#include "../../../world/entity/EntityRendererId.h" +#include "world/entity/EntityRendererId.hpp" class EntityRenderer; class Level; diff --git a/src/client/renderer/entity/EntityRenderer.cpp b/src/client/renderer/entity/EntityRenderer.cpp index 641581b..bea04f4 100755 --- a/src/client/renderer/entity/EntityRenderer.cpp +++ b/src/client/renderer/entity/EntityRenderer.cpp @@ -1,249 +1,249 @@ -#include "EntityRenderer.h" - -#include "../Tesselator.h" -#include "../Textures.h" -#include "../gles.h" -#include "../../../world/phys/AABB.h" -#include "EntityRenderDispatcher.h" - -EntityRenderDispatcher* EntityRenderer::entityRenderDispatcher = NULL; - -EntityRenderer::EntityRenderer() -: shadowRadius(0), - shadowStrength(1.0f) -{} - -void EntityRenderer::bindTexture(const std::string& resourceName) { - entityRenderDispatcher->textures->loadAndBindTexture(resourceName); -} - -//bool bindTexture(std::string urlTexture, std::string backupTexture) { -// Textures t = entityRenderDispatcher.textures; - -// int id = t.loadHttpTexture(urlTexture, backupTexture); -// if (id >= 0) { -// t.bind(id); -// return true; -// } else { -// return false; -// } -//} - -/*static*/ -void EntityRenderer::render(const AABB& bb, float xo, float yo, float zo) { - glDisable2(GL_TEXTURE_2D); - Tesselator& t = Tesselator::instance; - glColor4f2(1, 1, 1, 1); - t.begin(); - t.offset(xo, yo, zo); - //t.normal(0, 0, -1); - t.vertex(bb.x0, bb.y1, bb.z0); - t.vertex(bb.x1, bb.y1, bb.z0); - t.vertex(bb.x1, bb.y0, bb.z0); - t.vertex(bb.x0, bb.y0, bb.z0); - - //t.normal(0, 0, 1); - t.vertex(bb.x0, bb.y0, bb.z1); - t.vertex(bb.x1, bb.y0, bb.z1); - t.vertex(bb.x1, bb.y1, bb.z1); - t.vertex(bb.x0, bb.y1, bb.z1); - - //t.normal(0, -1, 0); - t.vertex(bb.x0, bb.y0, bb.z0); - t.vertex(bb.x1, bb.y0, bb.z0); - t.vertex(bb.x1, bb.y0, bb.z1); - t.vertex(bb.x0, bb.y0, bb.z1); - - //t.normal(0, 1, 0); - t.vertex(bb.x0, bb.y1, bb.z1); - t.vertex(bb.x1, bb.y1, bb.z1); - t.vertex(bb.x1, bb.y1, bb.z0); - t.vertex(bb.x0, bb.y1, bb.z0); - - //t.normal(-1, 0, 0); - t.vertex(bb.x0, bb.y0, bb.z1); - t.vertex(bb.x0, bb.y1, bb.z1); - t.vertex(bb.x0, bb.y1, bb.z0); - t.vertex(bb.x0, bb.y0, bb.z0); - - //t.normal(1, 0, 0); - t.vertex(bb.x1, bb.y0, bb.z0); - t.vertex(bb.x1, bb.y1, bb.z0); - t.vertex(bb.x1, bb.y1, bb.z1); - t.vertex(bb.x1, bb.y0, bb.z1); - t.offset(0, 0, 0); - t.draw(); - glEnable2(GL_TEXTURE_2D); - // model.render(0, 1) -} - -/*static*/ -void EntityRenderer::renderFlat(const AABB& bb) { - Tesselator& t = Tesselator::instance; - t.begin(); - t.vertex(bb.x0, bb.y1, bb.z0); - t.vertex(bb.x1, bb.y1, bb.z0); - t.vertex(bb.x1, bb.y0, bb.z0); - t.vertex(bb.x0, bb.y0, bb.z0); - t.vertex(bb.x0, bb.y0, bb.z1); - t.vertex(bb.x1, bb.y0, bb.z1); - t.vertex(bb.x1, bb.y1, bb.z1); - t.vertex(bb.x0, bb.y1, bb.z1); - t.vertex(bb.x0, bb.y0, bb.z0); - t.vertex(bb.x1, bb.y0, bb.z0); - t.vertex(bb.x1, bb.y0, bb.z1); - t.vertex(bb.x0, bb.y0, bb.z1); - t.vertex(bb.x0, bb.y1, bb.z1); - t.vertex(bb.x1, bb.y1, bb.z1); - t.vertex(bb.x1, bb.y1, bb.z0); - t.vertex(bb.x0, bb.y1, bb.z0); - t.vertex(bb.x0, bb.y0, bb.z1); - t.vertex(bb.x0, bb.y1, bb.z1); - t.vertex(bb.x0, bb.y1, bb.z0); - t.vertex(bb.x0, bb.y0, bb.z0); - t.vertex(bb.x1, bb.y0, bb.z0); - t.vertex(bb.x1, bb.y1, bb.z0); - t.vertex(bb.x1, bb.y1, bb.z1); - t.vertex(bb.x1, bb.y0, bb.z1); - t.draw(); -} - -void EntityRenderer::init(EntityRenderDispatcher* entityRenderDispatcher) { - this->entityRenderDispatcher = entityRenderDispatcher; -} - -Font* EntityRenderer::getFont() { - return entityRenderDispatcher->getFont(); -} - -//void postRender(Entity entity, float x, float y, float z, float rot, float a) { -// if (entityRenderDispatcher.options.fancyGraphics && shadowRadius > 0) { -// float dist = entityRenderDispatcher.distanceToSqr(entity.x, entity.y, entity.z); -// float pow = (float) ((1 - dist / (16.0f * 16.0f)) * shadowStrength); -// if (pow > 0) { -// renderShadow(entity, x, y, z, pow, a); -// } -// } -// if (entity.isOnFire()) renderFlame(entity, x, y, z, a); -//} - -//void renderFlame(Entity e, float x, float y, float z, float a) { -// glDisable2(GL_LIGHTING); -// int tex = Tile.fire.tex; - -// int xt = (tex & 0xf) << 4; -// int yt = tex & 0xf0; - -// float u0 = (xt) / 256.0f; -// float u1 = (xt + 15.99f) / 256.0f; -// float v0 = (yt) / 256.0f; -// float v1 = (yt + 15.99f) / 256.0f; - -// glPushMatrix2(); -// glTranslatef2((float) x, (float) y, (float) z); - -// float s = e.bbWidth * 1.4f; -// glScalef2(s, s, s); -// bindTexture("terrain.png"); -// Tesselator t = Tesselator.instance; - -// float r = 1.0f; -// float xo = 0.5f; -// float yo = 0.0f; - -// float h = e.bbHeight / e.bbWidth; - -// glRotatef2(-entityRenderDispatcher.playerRotY, 0, 1, 0); -// glTranslatef2(0, 0, -0.4f + ((int) h) * 0.02f); -// glColor4f2(1, 1, 1, 1); -// // glRotatef2(-playerRotX, 1, 0, 0); -// t.begin(); -// while (h > 0) { -// t.vertexUV(r - xo, 0 - yo, 0, u1, v1); -// t.vertexUV(0 - xo, 0 - yo, 0, u0, v1); -// t.vertexUV(0 - xo, 1.4f - yo, 0, u0, v0); -// t.vertexUV(r - xo, 1.4f - yo, 0, u1, v0); -// h -= 1; -// yo -= 1; -// r *= 0.9f; -// glTranslatef2(0, 0, -0.04f); -// } -// t.end(); -// glPopMatrix2(); -// glEnable2(GL_LIGHTING); -//} - -//void renderShadow(Entity e, float x, float y, float z, float pow, float a) { -// glEnable2(GL_BLEND); -// glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - -// Textures textures = entityRenderDispatcher.textures; -// textures.bind(textures.loadTexture("%clamp%/misc/shadow.png")); - -// Level level = getLevel(); - -// glDepthMask(false); -// float r = shadowRadius; - -// float ex = e.xOld + (e.x - e.xOld) * a; -// float ey = e.yOld + (e.y - e.yOld) * a + e.getShadowHeightOffs(); -// float ez = e.zOld + (e.z - e.zOld) * a; - -// int x0 = Mth.floor(ex - r); -// int x1 = Mth.floor(ex + r); -// int y0 = Mth.floor(ey - r); -// int y1 = Mth.floor(ey); -// int z0 = Mth.floor(ez - r); -// int z1 = Mth.floor(ez + r); - -// float xo = x - ex; -// float yo = y - ey; -// float zo = z - ez; - -// Tesselator tt = Tesselator.instance; -// tt.begin(); -// for (int xt = x0; xt <= x1; xt++) -// for (int yt = y0; yt <= y1; yt++) -// for (int zt = z0; zt <= z1; zt++) { -// int t = level.getTile(xt, yt - 1, zt); -// if (t > 0 && level.getRawBrightness(xt, yt, zt) > 3) { -// renderTileShadow(Tile.tiles[t], x, y + e.getShadowHeightOffs(), z, xt, yt, zt, pow, r, xo, yo + e.getShadowHeightOffs(), zo); -// } -// } -// tt.end(); - -// glColor4f2(1, 1, 1, 1); -// glDisable2(GL_BLEND); -// glDepthMask(true); -//} - -//Level* getLevel() { -// return entityRenderDispatcher.level; -//} - -//void renderTileShadow(Tile tt, float x, float y, float z, int xt, int yt, int zt, float pow, float r, float xo, float yo, float zo) { -// Tesselator t = Tesselator.instance; -// if (!tt.isCubeShaped()) return; - -// float a = ((pow - (y - (yt + yo)) / 2) * 0.5f) * getLevel().getBrightness(xt, yt, zt); -// if (a < 0) return; -// if (a > 1) a = 1; -// t.color(1, 1, 1, (float) a); -// // glColor4f2(1, 1, 1, (float) a); - -// float x0 = xt + tt.xx0 + xo; -// float x1 = xt + tt.xx1 + xo; -// float y0 = yt + tt.yy0 + yo + 1.0 / 64.0f; -// float z0 = zt + tt.zz0 + zo; -// float z1 = zt + tt.zz1 + zo; - -// float u0 = (float) ((x - (x0)) / 2 / r + 0.5f); -// float u1 = (float) ((x - (x1)) / 2 / r + 0.5f); -// float v0 = (float) ((z - (z0)) / 2 / r + 0.5f); -// float v1 = (float) ((z - (z1)) / 2 / r + 0.5f); - -// t.vertexUV(x0, y0, z0, u0, v0); -// t.vertexUV(x0, y0, z1, u0, v1); -// t.vertexUV(x1, y0, z1, u1, v1); -// t.vertexUV(x1, y0, z0, u1, v0); -//} +#include "EntityRenderer.hpp" + +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "client/renderer/gles.hpp" +#include "world/phys/AABB.hpp" +#include "EntityRenderDispatcher.hpp" + +EntityRenderDispatcher* EntityRenderer::entityRenderDispatcher = NULL; + +EntityRenderer::EntityRenderer() +: shadowRadius(0), + shadowStrength(1.0f) +{} + +void EntityRenderer::bindTexture(const std::string& resourceName) { + entityRenderDispatcher->textures->loadAndBindTexture(resourceName); +} + +//bool bindTexture(std::string urlTexture, std::string backupTexture) { +// Textures t = entityRenderDispatcher.textures; + +// int id = t.loadHttpTexture(urlTexture, backupTexture); +// if (id >= 0) { +// t.bind(id); +// return true; +// } else { +// return false; +// } +//} + +/*static*/ +void EntityRenderer::render(const AABB& bb, float xo, float yo, float zo) { + glDisable2(GL_TEXTURE_2D); + Tesselator& t = Tesselator::instance; + glColor4f2(1, 1, 1, 1); + t.begin(); + t.offset(xo, yo, zo); + //t.normal(0, 0, -1); + t.vertex(bb.x0, bb.y1, bb.z0); + t.vertex(bb.x1, bb.y1, bb.z0); + t.vertex(bb.x1, bb.y0, bb.z0); + t.vertex(bb.x0, bb.y0, bb.z0); + + //t.normal(0, 0, 1); + t.vertex(bb.x0, bb.y0, bb.z1); + t.vertex(bb.x1, bb.y0, bb.z1); + t.vertex(bb.x1, bb.y1, bb.z1); + t.vertex(bb.x0, bb.y1, bb.z1); + + //t.normal(0, -1, 0); + t.vertex(bb.x0, bb.y0, bb.z0); + t.vertex(bb.x1, bb.y0, bb.z0); + t.vertex(bb.x1, bb.y0, bb.z1); + t.vertex(bb.x0, bb.y0, bb.z1); + + //t.normal(0, 1, 0); + t.vertex(bb.x0, bb.y1, bb.z1); + t.vertex(bb.x1, bb.y1, bb.z1); + t.vertex(bb.x1, bb.y1, bb.z0); + t.vertex(bb.x0, bb.y1, bb.z0); + + //t.normal(-1, 0, 0); + t.vertex(bb.x0, bb.y0, bb.z1); + t.vertex(bb.x0, bb.y1, bb.z1); + t.vertex(bb.x0, bb.y1, bb.z0); + t.vertex(bb.x0, bb.y0, bb.z0); + + //t.normal(1, 0, 0); + t.vertex(bb.x1, bb.y0, bb.z0); + t.vertex(bb.x1, bb.y1, bb.z0); + t.vertex(bb.x1, bb.y1, bb.z1); + t.vertex(bb.x1, bb.y0, bb.z1); + t.offset(0, 0, 0); + t.draw(); + glEnable2(GL_TEXTURE_2D); + // model.render(0, 1) +} + +/*static*/ +void EntityRenderer::renderFlat(const AABB& bb) { + Tesselator& t = Tesselator::instance; + t.begin(); + t.vertex(bb.x0, bb.y1, bb.z0); + t.vertex(bb.x1, bb.y1, bb.z0); + t.vertex(bb.x1, bb.y0, bb.z0); + t.vertex(bb.x0, bb.y0, bb.z0); + t.vertex(bb.x0, bb.y0, bb.z1); + t.vertex(bb.x1, bb.y0, bb.z1); + t.vertex(bb.x1, bb.y1, bb.z1); + t.vertex(bb.x0, bb.y1, bb.z1); + t.vertex(bb.x0, bb.y0, bb.z0); + t.vertex(bb.x1, bb.y0, bb.z0); + t.vertex(bb.x1, bb.y0, bb.z1); + t.vertex(bb.x0, bb.y0, bb.z1); + t.vertex(bb.x0, bb.y1, bb.z1); + t.vertex(bb.x1, bb.y1, bb.z1); + t.vertex(bb.x1, bb.y1, bb.z0); + t.vertex(bb.x0, bb.y1, bb.z0); + t.vertex(bb.x0, bb.y0, bb.z1); + t.vertex(bb.x0, bb.y1, bb.z1); + t.vertex(bb.x0, bb.y1, bb.z0); + t.vertex(bb.x0, bb.y0, bb.z0); + t.vertex(bb.x1, bb.y0, bb.z0); + t.vertex(bb.x1, bb.y1, bb.z0); + t.vertex(bb.x1, bb.y1, bb.z1); + t.vertex(bb.x1, bb.y0, bb.z1); + t.draw(); +} + +void EntityRenderer::init(EntityRenderDispatcher* entityRenderDispatcher) { + this->entityRenderDispatcher = entityRenderDispatcher; +} + +Font* EntityRenderer::getFont() { + return entityRenderDispatcher->getFont(); +} + +//void postRender(Entity entity, float x, float y, float z, float rot, float a) { +// if (entityRenderDispatcher.options.fancyGraphics && shadowRadius > 0) { +// float dist = entityRenderDispatcher.distanceToSqr(entity.x, entity.y, entity.z); +// float pow = (float) ((1 - dist / (16.0f * 16.0f)) * shadowStrength); +// if (pow > 0) { +// renderShadow(entity, x, y, z, pow, a); +// } +// } +// if (entity.isOnFire()) renderFlame(entity, x, y, z, a); +//} + +//void renderFlame(Entity e, float x, float y, float z, float a) { +// glDisable2(GL_LIGHTING); +// int tex = Tile.fire.tex; + +// int xt = (tex & 0xf) << 4; +// int yt = tex & 0xf0; + +// float u0 = (xt) / 256.0f; +// float u1 = (xt + 15.99f) / 256.0f; +// float v0 = (yt) / 256.0f; +// float v1 = (yt + 15.99f) / 256.0f; + +// glPushMatrix2(); +// glTranslatef2((float) x, (float) y, (float) z); + +// float s = e.bbWidth * 1.4f; +// glScalef2(s, s, s); +// bindTexture("terrain.png"); +// Tesselator t = Tesselator.instance; + +// float r = 1.0f; +// float xo = 0.5f; +// float yo = 0.0f; + +// float h = e.bbHeight / e.bbWidth; + +// glRotatef2(-entityRenderDispatcher.playerRotY, 0, 1, 0); +// glTranslatef2(0, 0, -0.4f + ((int) h) * 0.02f); +// glColor4f2(1, 1, 1, 1); +// // glRotatef2(-playerRotX, 1, 0, 0); +// t.begin(); +// while (h > 0) { +// t.vertexUV(r - xo, 0 - yo, 0, u1, v1); +// t.vertexUV(0 - xo, 0 - yo, 0, u0, v1); +// t.vertexUV(0 - xo, 1.4f - yo, 0, u0, v0); +// t.vertexUV(r - xo, 1.4f - yo, 0, u1, v0); +// h -= 1; +// yo -= 1; +// r *= 0.9f; +// glTranslatef2(0, 0, -0.04f); +// } +// t.end(); +// glPopMatrix2(); +// glEnable2(GL_LIGHTING); +//} + +//void renderShadow(Entity e, float x, float y, float z, float pow, float a) { +// glEnable2(GL_BLEND); +// glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +// Textures textures = entityRenderDispatcher.textures; +// textures.bind(textures.loadTexture("%clamp%/misc/shadow.png")); + +// Level level = getLevel(); + +// glDepthMask(false); +// float r = shadowRadius; + +// float ex = e.xOld + (e.x - e.xOld) * a; +// float ey = e.yOld + (e.y - e.yOld) * a + e.getShadowHeightOffs(); +// float ez = e.zOld + (e.z - e.zOld) * a; + +// int x0 = Mth.floor(ex - r); +// int x1 = Mth.floor(ex + r); +// int y0 = Mth.floor(ey - r); +// int y1 = Mth.floor(ey); +// int z0 = Mth.floor(ez - r); +// int z1 = Mth.floor(ez + r); + +// float xo = x - ex; +// float yo = y - ey; +// float zo = z - ez; + +// Tesselator tt = Tesselator.instance; +// tt.begin(); +// for (int xt = x0; xt <= x1; xt++) +// for (int yt = y0; yt <= y1; yt++) +// for (int zt = z0; zt <= z1; zt++) { +// int t = level.getTile(xt, yt - 1, zt); +// if (t > 0 && level.getRawBrightness(xt, yt, zt) > 3) { +// renderTileShadow(Tile.tiles[t], x, y + e.getShadowHeightOffs(), z, xt, yt, zt, pow, r, xo, yo + e.getShadowHeightOffs(), zo); +// } +// } +// tt.end(); + +// glColor4f2(1, 1, 1, 1); +// glDisable2(GL_BLEND); +// glDepthMask(true); +//} + +//Level* getLevel() { +// return entityRenderDispatcher.level; +//} + +//void renderTileShadow(Tile tt, float x, float y, float z, int xt, int yt, int zt, float pow, float r, float xo, float yo, float zo) { +// Tesselator t = Tesselator.instance; +// if (!tt.isCubeShaped()) return; + +// float a = ((pow - (y - (yt + yo)) / 2) * 0.5f) * getLevel().getBrightness(xt, yt, zt); +// if (a < 0) return; +// if (a > 1) a = 1; +// t.color(1, 1, 1, (float) a); +// // glColor4f2(1, 1, 1, (float) a); + +// float x0 = xt + tt.xx0 + xo; +// float x1 = xt + tt.xx1 + xo; +// float y0 = yt + tt.yy0 + yo + 1.0 / 64.0f; +// float z0 = zt + tt.zz0 + zo; +// float z1 = zt + tt.zz1 + zo; + +// float u0 = (float) ((x - (x0)) / 2 / r + 0.5f); +// float u1 = (float) ((x - (x1)) / 2 / r + 0.5f); +// float v0 = (float) ((z - (z0)) / 2 / r + 0.5f); +// float v1 = (float) ((z - (z1)) / 2 / r + 0.5f); + +// t.vertexUV(x0, y0, z0, u0, v0); +// t.vertexUV(x0, y0, z1, u0, v1); +// t.vertexUV(x1, y0, z1, u1, v1); +// t.vertexUV(x1, y0, z0, u1, v0); +//} diff --git a/src/client/renderer/entity/EntityRenderer.h b/src/client/renderer/entity/EntityRenderer.hpp similarity index 94% rename from src/client/renderer/entity/EntityRenderer.h rename to src/client/renderer/entity/EntityRenderer.hpp index dde97fe..5a771ae 100755 --- a/src/client/renderer/entity/EntityRenderer.h +++ b/src/client/renderer/entity/EntityRenderer.hpp @@ -3,7 +3,7 @@ //package net.minecraft.client.renderer.entity; #include -#include "../../model/HumanoidModel.h" +#include "client/model/HumanoidModel.hpp" class Textures; class Tesselator; diff --git a/src/client/renderer/entity/FallingTileRenderer.cpp b/src/client/renderer/entity/FallingTileRenderer.cpp index 0cf9eb4..a760529 100755 --- a/src/client/renderer/entity/FallingTileRenderer.cpp +++ b/src/client/renderer/entity/FallingTileRenderer.cpp @@ -1,32 +1,32 @@ -#include "FallingTileRenderer.h" -#include "../TileRenderer.h" -#include "../../../world/entity/item/FallingTile.h" -#include "../../../world/level/tile/Tile.h" -#include "../../../world/level/Level.h" - -FallingTileRenderer::FallingTileRenderer() { - this->shadowRadius = 0.5f; - tileRenderer = new TileRenderer(); -} - -FallingTileRenderer::~FallingTileRenderer() { - delete tileRenderer; -} - -void FallingTileRenderer::render( Entity* e, float x, float y, float z, float rot, float a ) { - FallingTile* tile = (FallingTile*) e; - - glPushMatrix(); - glTranslatef(x, y, z); - - bindTexture("terrain.png"); - Tile* tt = Tile::tiles[tile->tile]; - - Level* level = tile->getLevel(); - - if (tt != NULL) { - tileRenderer->renderBlock(tt, level, Mth::floor(tile->x), Mth::floor(tile->y), Mth::floor(tile->z)); - - } - glPopMatrix(); -} +#include "FallingTileRenderer.hpp" +#include "client/renderer/TileRenderer.hpp" +#include "world/entity/item/FallingTile.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/Level.hpp" + +FallingTileRenderer::FallingTileRenderer() { + this->shadowRadius = 0.5f; + tileRenderer = new TileRenderer(); +} + +FallingTileRenderer::~FallingTileRenderer() { + delete tileRenderer; +} + +void FallingTileRenderer::render( Entity* e, float x, float y, float z, float rot, float a ) { + FallingTile* tile = (FallingTile*) e; + + glPushMatrix(); + glTranslatef(x, y, z); + + bindTexture("terrain.png"); + Tile* tt = Tile::tiles[tile->tile]; + + Level* level = tile->getLevel(); + + if (tt != NULL) { + tileRenderer->renderBlock(tt, level, Mth::floor(tile->x), Mth::floor(tile->y), Mth::floor(tile->z)); + + } + glPopMatrix(); +} diff --git a/src/client/renderer/entity/FallingTileRenderer.h b/src/client/renderer/entity/FallingTileRenderer.hpp similarity index 92% rename from src/client/renderer/entity/FallingTileRenderer.h rename to src/client/renderer/entity/FallingTileRenderer.hpp index e987f4b..237bb55 100755 --- a/src/client/renderer/entity/FallingTileRenderer.h +++ b/src/client/renderer/entity/FallingTileRenderer.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.entity; -#include "EntityRenderer.h" +#include "EntityRenderer.hpp" class TileRenderer; diff --git a/src/client/renderer/entity/HumanoidMobRenderer.cpp b/src/client/renderer/entity/HumanoidMobRenderer.cpp index 0922767..236648a 100755 --- a/src/client/renderer/entity/HumanoidMobRenderer.cpp +++ b/src/client/renderer/entity/HumanoidMobRenderer.cpp @@ -1,223 +1,223 @@ -#include "HumanoidMobRenderer.h" -#include "EntityRenderDispatcher.h" -#include "../ItemInHandRenderer.h" -#include "../TileRenderer.h" -#include "../Tesselator.h" -#include "../../model/HumanoidModel.h" -#include "../../../world/level/tile/Tile.h" -#include "../../../world/entity/player/Player.h" -#include "../../../world/entity/player/Inventory.h" -#include "../../../world/item/ItemInstance.h" -#include "../../../world/item/Item.h" -#include "../../../world/item/BowItem.h" - -HumanoidMobRenderer::HumanoidMobRenderer(HumanoidModel* humanoidModel, float shadow) -: super(humanoidModel, shadow), - humanoidModel(humanoidModel), - lastCapeXRot(0), - lastCapeZRot(0) -{ -} - -void HumanoidMobRenderer::renderHand() { - humanoidModel->attackTime = 0; - humanoidModel->setupAnim(0, 0, 0, 0, 0, 1 / 16.0f); - - //@attn @cuberender @enableClientState @vertexarray - glEnableClientState2(GL_VERTEX_ARRAY); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - //glEnableClientState2(GL_COLOR_ARRAY); - humanoidModel->arm0.render(1 / 16.0f); - glDisableClientState2(GL_VERTEX_ARRAY); - glDisableClientState2(GL_TEXTURE_COORD_ARRAY); - //glDisableClientState2(GL_COLOR_ARRAY); -} - -void HumanoidMobRenderer::additionalRendering(Mob* mob, float a) { - ItemInstance* item = mob->getCarriedItem(); - if (item != NULL && item->count > 0) { - glPushMatrix2(); - humanoidModel->arm0.translateTo(1 / 16.0f); - glTranslatef2(-1.0f / 16.0f, 7.0f / 16.0f, 1.0f / 16.0f); - - if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) { - float s = 8.0f / 16.0f; - glTranslatef2(0.0f, 3.0f / 16.0f, -5 / 16.0f); - s *= 0.75f; - glRotatef2(20.0f, 1.0f, 0.0f, 0.0f); - glRotatef2(45.0f, 0.0f, 1.0f, 0.0f); - glScalef2(s, -s, s); - } else if (item->id == Item::bow->id) { - const float s = 10.0f / 16.0f; - glTranslatef2(0 / 16.0f, 2 / 16.0f, 5 / 16.0f); - glRotatef2(-20, 0, 1, 0); - glScalef2(s, -s, s); - glRotatef2(-100, 1, 0, 0); - glRotatef2(45, 0, 1, 0); - } else if (Item::items[item->id]->isHandEquipped()) { - float s = 10.0f / 16.0f; - glTranslatef2(0.0f, 3.0f / 16.0f, 0.0f); - glScalef2(s, -s, s); - glRotatef2(-100.0f, 1.0f, 0.0f, 0.0f); - glRotatef2(45.0f, 0.0f, 1.0f, 0.0f); - } else { - float s = 6 / 16.0f; - glTranslatef2(+4 / 16.0f, +3 / 16.0f, -3 / 16.0f); - glScalef2(s, s, s); - glRotatef2(60.0f, 0.0f, 0.0f, 1.0f); - glRotatef2(-90.0f, 1.0f, 0.0f, 0.0f); - glRotatef2(20.0f, 0.0f, 0.0f, 1.0f); - } - entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item); - glPopMatrix2(); - } - - // Render player cape if available -{ - Player* player = Player::asPlayer(mob); - if (player) { - const std::string capeTex = player->getCapeTexture(); - if (!capeTex.empty()) { - - bindTexture(capeTex); - - glPushMatrix2(); - - // Attach to player body - humanoidModel->body.translateTo(1 / 16.0f); - - // Convert model units (pixels) to world units - glScalef2(1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f); - - // Position cape slightly down and behind the shoulders - glTranslatef2(0.0f, 1.0f, 2.0f); - - // Java-like cape physics (interpolated inertia + body motion) - float pt = a; - - double capeX = player->getCapePrevX() + (player->getCapeX() - player->getCapePrevX()) * pt; - double capeY = player->getCapePrevY() + (player->getCapeY() - player->getCapePrevY()) * pt; - double capeZ = player->getCapePrevZ() + (player->getCapeZ() - player->getCapePrevZ()) * pt; - - double px = player->xo + (player->x - player->xo) * pt; - double py = player->yo + (player->y - player->yo) * pt; - double pz = player->zo + (player->z - player->zo) * pt; - - double dx = capeX - px; - double dy = capeY - py; - double dz = capeZ - pz; - - float bodyYaw = player->yBodyRotO + (player->yBodyRot - player->yBodyRotO) * pt; - - float rad = bodyYaw * Mth::PI / 180.0f; - double sinYaw = Mth::sin(rad); - double cosYaw = -Mth::cos(rad); - - float forward = (float)(dx * sinYaw + dz * cosYaw) * 100.0f; - float sideways = (float)(dx * cosYaw - dz * sinYaw) * 100.0f; - if (forward < 0.0f) forward = 0.0f; - - float lift = (float)dy * 10.0f; - if (lift < -6.0f) lift = -6.0f; - if (lift > 32.0f) lift = 32.0f; - - float walk = - Mth::sin((player->walkAnimPos + player->walkAnimSpeed) * 6.0f) * - 32.0f * - player->walkAnimSpeed; - - float capeXRot = 6.0f + forward / 2.0f + lift + walk; - float capeZRot = sideways / 2.0f; - - // Smooth out jitter by lerping from the previous frame - const float smooth = 0.3f; - capeXRot = lastCapeXRot + (capeXRot - lastCapeXRot) * smooth; - capeZRot = lastCapeZRot + (capeZRot - lastCapeZRot) * smooth; - - lastCapeXRot = capeXRot; - lastCapeZRot = capeZRot; - - glRotatef2(capeXRot, 1.0f, 0.0f, 0.0f); - glRotatef2(capeZRot, 0.0f, 0.0f, 1.0f); - - Tesselator& t = Tesselator::instance; - t.begin(); - - // UV coordinates (64x32 skin layout) - const float u0 = 1.0f / 64.0f; - const float u1 = 11.0f / 64.0f; - const float u2 = 12.0f / 64.0f; - const float u3 = 22.0f / 64.0f; - - const float uL0 = 0.0f / 64.0f; - const float uL1 = 1.0f / 64.0f; - - const float uR0 = 11.0f / 64.0f; - const float uR1 = 12.0f / 64.0f; - - const float v0 = 0.0f / 32.0f; - const float v1 = 1.0f / 32.0f; - - const float vTop = 1.0f / 32.0f; - const float vBottom = 17.0f / 32.0f; - - // Cape size (10x16x1 pixels) - const float halfW = 5.0f; - const float height = 16.0f; - const float depth = 1.0f; - - // Front - t.tex(u2, vTop); t.vertex(-halfW, 0.0f, 0.0f); - t.tex(u3, vTop); t.vertex(halfW, 0.0f, 0.0f); - t.tex(u3, vBottom); t.vertex(halfW, height, 0.0f); - t.tex(u2, vBottom); t.vertex(-halfW, height, 0.0f); - - // Back - t.tex(u0, vTop); t.vertex(halfW, 0.0f, depth); - t.tex(u1, vTop); t.vertex(-halfW, 0.0f, depth); - t.tex(u1, vBottom); t.vertex(-halfW, height, depth); - t.tex(u0, vBottom); t.vertex(halfW, height, depth); - - // Left - t.tex(uL0, vTop); t.vertex(-halfW, 0.0f, depth); - t.tex(uL1, vTop); t.vertex(-halfW, 0.0f, 0.0f); - t.tex(uL1, vBottom); t.vertex(-halfW, height, 0.0f); - t.tex(uL0, vBottom); t.vertex(-halfW, height, depth); - - // Right - t.tex(uR0, vTop); t.vertex(halfW, 0.0f, 0.0f); - t.tex(uR1, vTop); t.vertex(halfW, 0.0f, depth); - t.tex(uR1, vBottom); t.vertex(halfW, height, depth); - t.tex(uR0, vBottom); t.vertex(halfW, height, 0.0f); - - // Top - t.tex(u0, v0); t.vertex(-halfW, 0.0f, depth); - t.tex(u1, v0); t.vertex(halfW, 0.0f, depth); - t.tex(u1, v1); t.vertex(halfW, 0.0f, 0.0f); - t.tex(u0, v1); t.vertex(-halfW, 0.0f, 0.0f); - - // Bottom - t.tex(u2, v0); t.vertex(halfW, height, 0.0f); - t.tex(u3, v0); t.vertex(-halfW, height, 0.0f); - t.tex(u3, v1); t.vertex(-halfW, height, depth); - t.tex(u2, v1); t.vertex(halfW, height, depth); - - t.draw(); - - glPopMatrix2(); - } - } -} -} - -void HumanoidMobRenderer::render( Entity* mob_, float x, float y, float z, float rot, float a ) { - Mob* mob = (Mob*)mob_; - ItemInstance* carriedItem = mob->getCarriedItem(); - if(carriedItem != NULL) - humanoidModel->holdingRightHand = true; - - humanoidModel->sneaking = mob->isSneaking(); - - super::render(mob_, x, y, z, rot, a); - humanoidModel->holdingRightHand = false; -} +#include "HumanoidMobRenderer.hpp" +#include "EntityRenderDispatcher.hpp" +#include "client/renderer/ItemInHandRenderer.hpp" +#include "client/renderer/TileRenderer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/model/HumanoidModel.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/item/Item.hpp" +#include "world/item/BowItem.hpp" + +HumanoidMobRenderer::HumanoidMobRenderer(HumanoidModel* humanoidModel, float shadow) +: super(humanoidModel, shadow), + humanoidModel(humanoidModel), + lastCapeXRot(0), + lastCapeZRot(0) +{ +} + +void HumanoidMobRenderer::renderHand() { + humanoidModel->attackTime = 0; + humanoidModel->setupAnim(0, 0, 0, 0, 0, 1 / 16.0f); + + //@attn @cuberender @enableClientState @vertexarray + glEnableClientState2(GL_VERTEX_ARRAY); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + //glEnableClientState2(GL_COLOR_ARRAY); + humanoidModel->arm0.render(1 / 16.0f); + glDisableClientState2(GL_VERTEX_ARRAY); + glDisableClientState2(GL_TEXTURE_COORD_ARRAY); + //glDisableClientState2(GL_COLOR_ARRAY); +} + +void HumanoidMobRenderer::additionalRendering(Mob* mob, float a) { + ItemInstance* item = mob->getCarriedItem(); + if (item != NULL && item->count > 0) { + glPushMatrix2(); + humanoidModel->arm0.translateTo(1 / 16.0f); + glTranslatef2(-1.0f / 16.0f, 7.0f / 16.0f, 1.0f / 16.0f); + + if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) { + float s = 8.0f / 16.0f; + glTranslatef2(0.0f, 3.0f / 16.0f, -5 / 16.0f); + s *= 0.75f; + glRotatef2(20.0f, 1.0f, 0.0f, 0.0f); + glRotatef2(45.0f, 0.0f, 1.0f, 0.0f); + glScalef2(s, -s, s); + } else if (item->id == Item::bow->id) { + const float s = 10.0f / 16.0f; + glTranslatef2(0 / 16.0f, 2 / 16.0f, 5 / 16.0f); + glRotatef2(-20, 0, 1, 0); + glScalef2(s, -s, s); + glRotatef2(-100, 1, 0, 0); + glRotatef2(45, 0, 1, 0); + } else if (Item::items[item->id]->isHandEquipped()) { + float s = 10.0f / 16.0f; + glTranslatef2(0.0f, 3.0f / 16.0f, 0.0f); + glScalef2(s, -s, s); + glRotatef2(-100.0f, 1.0f, 0.0f, 0.0f); + glRotatef2(45.0f, 0.0f, 1.0f, 0.0f); + } else { + float s = 6 / 16.0f; + glTranslatef2(+4 / 16.0f, +3 / 16.0f, -3 / 16.0f); + glScalef2(s, s, s); + glRotatef2(60.0f, 0.0f, 0.0f, 1.0f); + glRotatef2(-90.0f, 1.0f, 0.0f, 0.0f); + glRotatef2(20.0f, 0.0f, 0.0f, 1.0f); + } + entityRenderDispatcher->itemInHandRenderer->renderItem(mob, item); + glPopMatrix2(); + } + + // Render player cape if available +{ + Player* player = Player::asPlayer(mob); + if (player) { + const std::string capeTex = player->getCapeTexture(); + if (!capeTex.empty()) { + + bindTexture(capeTex); + + glPushMatrix2(); + + // Attach to player body + humanoidModel->body.translateTo(1 / 16.0f); + + // Convert model units (pixels) to world units + glScalef2(1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f); + + // Position cape slightly down and behind the shoulders + glTranslatef2(0.0f, 1.0f, 2.0f); + + // Java-like cape physics (interpolated inertia + body motion) + float pt = a; + + double capeX = player->getCapePrevX() + (player->getCapeX() - player->getCapePrevX()) * pt; + double capeY = player->getCapePrevY() + (player->getCapeY() - player->getCapePrevY()) * pt; + double capeZ = player->getCapePrevZ() + (player->getCapeZ() - player->getCapePrevZ()) * pt; + + double px = player->xo + (player->x - player->xo) * pt; + double py = player->yo + (player->y - player->yo) * pt; + double pz = player->zo + (player->z - player->zo) * pt; + + double dx = capeX - px; + double dy = capeY - py; + double dz = capeZ - pz; + + float bodyYaw = player->yBodyRotO + (player->yBodyRot - player->yBodyRotO) * pt; + + float rad = bodyYaw * Mth::PI / 180.0f; + double sinYaw = Mth::sin(rad); + double cosYaw = -Mth::cos(rad); + + float forward = (float)(dx * sinYaw + dz * cosYaw) * 100.0f; + float sideways = (float)(dx * cosYaw - dz * sinYaw) * 100.0f; + if (forward < 0.0f) forward = 0.0f; + + float lift = (float)dy * 10.0f; + if (lift < -6.0f) lift = -6.0f; + if (lift > 32.0f) lift = 32.0f; + + float walk = + Mth::sin((player->walkAnimPos + player->walkAnimSpeed) * 6.0f) * + 32.0f * + player->walkAnimSpeed; + + float capeXRot = 6.0f + forward / 2.0f + lift + walk; + float capeZRot = sideways / 2.0f; + + // Smooth out jitter by lerping from the previous frame + const float smooth = 0.3f; + capeXRot = lastCapeXRot + (capeXRot - lastCapeXRot) * smooth; + capeZRot = lastCapeZRot + (capeZRot - lastCapeZRot) * smooth; + + lastCapeXRot = capeXRot; + lastCapeZRot = capeZRot; + + glRotatef2(capeXRot, 1.0f, 0.0f, 0.0f); + glRotatef2(capeZRot, 0.0f, 0.0f, 1.0f); + + Tesselator& t = Tesselator::instance; + t.begin(); + + // UV coordinates (64x32 skin layout) + const float u0 = 1.0f / 64.0f; + const float u1 = 11.0f / 64.0f; + const float u2 = 12.0f / 64.0f; + const float u3 = 22.0f / 64.0f; + + const float uL0 = 0.0f / 64.0f; + const float uL1 = 1.0f / 64.0f; + + const float uR0 = 11.0f / 64.0f; + const float uR1 = 12.0f / 64.0f; + + const float v0 = 0.0f / 32.0f; + const float v1 = 1.0f / 32.0f; + + const float vTop = 1.0f / 32.0f; + const float vBottom = 17.0f / 32.0f; + + // Cape size (10x16x1 pixels) + const float halfW = 5.0f; + const float height = 16.0f; + const float depth = 1.0f; + + // Front + t.tex(u2, vTop); t.vertex(-halfW, 0.0f, 0.0f); + t.tex(u3, vTop); t.vertex(halfW, 0.0f, 0.0f); + t.tex(u3, vBottom); t.vertex(halfW, height, 0.0f); + t.tex(u2, vBottom); t.vertex(-halfW, height, 0.0f); + + // Back + t.tex(u0, vTop); t.vertex(halfW, 0.0f, depth); + t.tex(u1, vTop); t.vertex(-halfW, 0.0f, depth); + t.tex(u1, vBottom); t.vertex(-halfW, height, depth); + t.tex(u0, vBottom); t.vertex(halfW, height, depth); + + // Left + t.tex(uL0, vTop); t.vertex(-halfW, 0.0f, depth); + t.tex(uL1, vTop); t.vertex(-halfW, 0.0f, 0.0f); + t.tex(uL1, vBottom); t.vertex(-halfW, height, 0.0f); + t.tex(uL0, vBottom); t.vertex(-halfW, height, depth); + + // Right + t.tex(uR0, vTop); t.vertex(halfW, 0.0f, 0.0f); + t.tex(uR1, vTop); t.vertex(halfW, 0.0f, depth); + t.tex(uR1, vBottom); t.vertex(halfW, height, depth); + t.tex(uR0, vBottom); t.vertex(halfW, height, 0.0f); + + // Top + t.tex(u0, v0); t.vertex(-halfW, 0.0f, depth); + t.tex(u1, v0); t.vertex(halfW, 0.0f, depth); + t.tex(u1, v1); t.vertex(halfW, 0.0f, 0.0f); + t.tex(u0, v1); t.vertex(-halfW, 0.0f, 0.0f); + + // Bottom + t.tex(u2, v0); t.vertex(halfW, height, 0.0f); + t.tex(u3, v0); t.vertex(-halfW, height, 0.0f); + t.tex(u3, v1); t.vertex(-halfW, height, depth); + t.tex(u2, v1); t.vertex(halfW, height, depth); + + t.draw(); + + glPopMatrix2(); + } + } +} +} + +void HumanoidMobRenderer::render( Entity* mob_, float x, float y, float z, float rot, float a ) { + Mob* mob = (Mob*)mob_; + ItemInstance* carriedItem = mob->getCarriedItem(); + if(carriedItem != NULL) + humanoidModel->holdingRightHand = true; + + humanoidModel->sneaking = mob->isSneaking(); + + super::render(mob_, x, y, z, rot, a); + humanoidModel->holdingRightHand = false; +} diff --git a/src/client/renderer/entity/HumanoidMobRenderer.h b/src/client/renderer/entity/HumanoidMobRenderer.hpp similarity index 95% rename from src/client/renderer/entity/HumanoidMobRenderer.h rename to src/client/renderer/entity/HumanoidMobRenderer.hpp index c02441e..387ef6a 100755 --- a/src/client/renderer/entity/HumanoidMobRenderer.h +++ b/src/client/renderer/entity/HumanoidMobRenderer.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.entity; -#include "MobRenderer.h" +#include "MobRenderer.hpp" class HumanoidModel; class Mob; diff --git a/src/client/renderer/entity/ItemRenderer.cpp b/src/client/renderer/entity/ItemRenderer.cpp index 15e63d1..e74fed5 100755 --- a/src/client/renderer/entity/ItemRenderer.cpp +++ b/src/client/renderer/entity/ItemRenderer.cpp @@ -1,321 +1,321 @@ -#include "ItemRenderer.h" -#include "EntityRenderDispatcher.h" -#include "../Tesselator.h" -#include "../TileRenderer.h" -#include "../Textures.h" -#include "../../gui/Font.h" -#include "../../../world/entity/item/ItemEntity.h" -#include "../../../world/item/ItemInstance.h" -#include "../../../world/level/tile/Tile.h" -#include "../../../util/Mth.h" -#include "../../../util/Random.h" -#include "EntityRenderer.h" -#include "../ItemInHandRenderer.h" -#include "../../gui/Gui.h" -#include "../../../world/item/Item.h" - -/*static*/ -TileRenderer* ItemRenderer::tileRenderer = new TileRenderer(); - -ItemRenderer::ItemRenderer() -{ - shadowRadius = 0.15f; - shadowStrength = 0.75f; -} - -void ItemRenderer::teardown_static() { - if (tileRenderer) { - delete tileRenderer; - tileRenderer = NULL; - } -} - -void ItemRenderer::render(Entity* itemEntity_, float x, float y, float z, float rot, float a) { - ItemEntity* itemEntity = (ItemEntity*) itemEntity_; - random.setSeed(187); - ItemInstance* item = &itemEntity->item; - - glPushMatrix2(); - float bob = Mth::sin((itemEntity->age + a) / 10.0f + itemEntity->bobOffs) * 0.1f + 0.1f; - float spin = ((itemEntity->age + a) / 20.0f + itemEntity->bobOffs) * Mth::RADDEG; - - int count = 1; - if (item->count > 20) count = 4; - else if (item->count > 5) count = 3; - else if (item->count > 1) count = 2; - - glTranslatef2((float) x, (float) y + bob, (float) z); - //glEnable2(GL_RESCALE_NORMAL); - if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) { - glRotatef2(spin, 0, 1, 0); - - float br = itemEntity->getBrightness(a); - if (item->id == Tile::sand->id || item->id == Tile::sandStone->id) br *= 0.8f; - glColor4f2(br, br, br, 1.0f); - - bindTexture("terrain.png"); - float s = 1 / 4.0f; - //if (!Tile::tiles[item->id]->isCubeShaped() && item->id != Tile::stoneSlabHalf->id) { - const int shape = Tile::tiles[item->id]->getRenderShape(); - if (shape == Tile::SHAPE_CROSS_TEXTURE || shape == Tile::SHAPE_TORCH) - s = 0.5f; - - glScalef2(s, s, s); - for (int i = 0; i < count; i++) { - if (i > 0) { - glPushMatrix2(); - float xo = (random.nextFloat() * 2 - 1) * 0.2f / s; - float yo = (random.nextFloat() * 2 - 1) * 0.2f / s; - float zo = (random.nextFloat() * 2 - 1) * 0.2f / s; - glTranslatef2(xo, yo, zo); - } - //static Stopwatch w; - //w.start(); - entityRenderDispatcher->itemInHandRenderer->renderItem(NULL, item); - //tileRenderer->renderTile(Tile::tiles[item->id], item->getAuxValue()); - //w.stop(); - //w.printEvery(100, "render-item"); - if (i > 0) glPopMatrix2(); - } - } else { - glScalef2(1 / 2.0f, 1 / 2.0f, 1 / 2.0f); - int icon = item->getIcon(); - if (item->id < 256) { - bindTexture("terrain.png"); - } else { - bindTexture("gui/items.png"); - } - Tesselator& t = Tesselator::instance; - - float u0 = ((icon % 16) * 16 + 0) / 256.0f; - float u1 = ((icon % 16) * 16 + 16) / 256.0f; - float v0 = ((icon / 16) * 16 + 0) / 256.0f; - float v1 = ((icon / 16) * 16 + 16) / 256.0f; - - float r = 1.0f; - float xo = 0.5f; - float yo = 0.25f; - - // glRotatef2(-playerRotX, 1, 0, 0); - for (int i = 0; i < count; i++) { - glPushMatrix2(); - if (i > 0) { - float _xo = (random.nextFloat() * 2 - 1) * 0.3f; - float _yo = (random.nextFloat() * 2 - 1) * 0.3f; - float _zo = (random.nextFloat() * 2 - 1) * 0.3f; - glTranslatef2(_xo, _yo, _zo); - } - glRotatef2(180 - entityRenderDispatcher->playerRotY, 0, 1, 0); - t.begin(); - //t.normal(0, 1, 0); - t.vertexUV(0 - xo, 0 - yo, 0, u0, v1); - t.vertexUV(r - xo, 0 - yo, 0, u1, v1); - t.vertexUV(r - xo, 1 - yo, 0, u1, v0); - t.vertexUV(0 - xo, 1 - yo, 0, u0, v0); - //t.end(); - t.draw(); - - glPopMatrix2(); - } - } - //glDisable2(GL_RESCALE_NORMAL); - glPopMatrix2(); -} - - -// @note: _18 -> a,b,c,-1, a,b,c-1, ... -static const signed short _6[] = {139, 140, 141, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static const signed short _17[] = {16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static const signed short _18[] = {79, 80, 81, -1, 79, 80, 81, -1, 79, 80, 81, -1, 79, 80, 81, -1}; -static const signed short _24[] = {11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static const signed short _35[] = {52, 59, 58, 57, 56, 55, 54, 53, 67, 66, 65, 64, 63, 62, 61, 60}; -static const signed short _44[] = {28, 32, 30, 29, 31, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static const signed short _98[] = {1, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static const signed short _155[] = {34, 36, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static const signed short _263[] = {230, 151, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -static const signed short _351[] = {-1, 152, 154, -1, 193, 215, 216, -1, -1, 217, 218, 219, 220, 221, 222, 144}; - -static const signed short _mapper[] = {-1, 7, 9, 8, 0, 5, -2, -1, -1, -1, -1, -1, 14, 15, 39, 38, 37, -2, -2, -1, 49, 41, 46, -1, -2, -1, -1, -1, -1, -1, 235, -1, -1, -1, -1, -2, -1, 134, 135, 136, 137, 43, 44, -1, -2, 6, 76, 71, 4, 47, 129, -1, -1, 22, 74, -1, 40, 45, 72, -1, -1, 75, -1, -1, -1, 128, -1, 21, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 48, 77, 10, 236, -1, 69, -1, 20, -1, 50, -1, -1, -1, -1, -1, -1, 68, -1, -2, -1, -1, -1, 130, 78, -1, -1, -1, 70, 23, 25, -1, -1, 19, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, 51, -1, -1, -1, -1, -1, 82, -1, -1, 174, 173, 175, 231, 234, 147, 190, -2, 153, 150, 149, 146, 185, 166, 164, 167, 186, 170, 169, 171, 187, 177, 176, 178, 165, 195, 194, 188, 181, 180, 182, 189, 191, 228, 168, 172, 145, 179, 183, 142, 233, 232, 198, 200, 201, 202, -1, -1, -1, -1, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 192, 156, 157, 133, -1, 148, 131, -1, -1, -1, -1, -1, -1, -1, 226, -1, 199, -1, 159, 158, 138, 224, 225, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -2, 223, 229, -1, 132, -1, -1, -1, 184, 196, -1, 143, 160, 161, 162, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, 197}; - -#define IRMAPCASE(x) case x: return _##x [item->getAuxValue() & 15] - -int ItemRenderer::getAtlasPos(const ItemInstance* item) { - int id = item->id; - if (id < 0 || id >= sizeof(_mapper) / sizeof(const signed short)) - return -1; - - int texId = _mapper[id]; - if (texId != -2) - return texId; - - switch(id) { - IRMAPCASE(6); - IRMAPCASE(17); - IRMAPCASE(18); - IRMAPCASE(24); - IRMAPCASE(35); - IRMAPCASE(44); - IRMAPCASE(98); - IRMAPCASE(155); - IRMAPCASE(263); - IRMAPCASE(351); - default: - break; - } - return -1; -} - -/*static*/ -void ItemRenderer::renderGuiItem(Font* font, Textures* textures, const ItemInstance* item, float x, float y, bool fancy) { - renderGuiItem(font, textures, item, x, y, 16, 16, fancy); -} -void ItemRenderer::renderGuiItem(Font* font, Textures* textures, const ItemInstance* item, float x, float y, float w, float h, bool fancy) { - if (item == NULL) { - //LOGW("item is NULL @ ItemRenderer::renderGuiItem\n"); - return; - } - const int id = item->id; - if (!Item::items[id]) - return; - - int i = getAtlasPos(item); - - if (i < 0) { - Tesselator& t = Tesselator::instance; - if (!t.isOverridden()) - renderGuiItemCorrect(font, textures, item, int(x), int(y)); - else { - // @huge @attn @todo @fix: This is just guess-works.. - // it we're batching for saving the - // buffer, this will fail miserably - t.endOverrideAndDraw(); - glDisable2(GL_TEXTURE_2D); - fillRect(t, x, y, w, h, 0xff0000); - glEnable2(GL_TEXTURE_2D); - renderGuiItemCorrect(font, textures, item, int(x), int(y)); - t.beginOverride(); - } - return; - } - - textures->loadAndBindTexture("gui/gui_blocks.png"); - float u0, u1, v0, v1; - if (i < 128) { - const float P = 48.0f / 512.0f; - u0 = (float)(i%10) * P; - v0 = (float)(i/10) * P; - u1 = u0 + P; - v1 = v0 + P; - } else { - i -= 128; - const float P = 16.0f / 512.0f; - u0 = float(i & 31) * P; - v0 = 27 * P + float(i >> 5) * P; // 27 "icon" rows down - u1 = u0 + P; - v1 = v0 + P; - } - - const float blitOffset = 0; - Tesselator& t = Tesselator::instance; - t.begin(); - t.colorABGR( item->count>0? 0xffffffff : 0x60ffffff); - t.vertexUV(x, y + h, blitOffset, u0, v1); - t.vertexUV(x + w, y + h, blitOffset, u1, v1); - t.vertexUV(x + w, y, blitOffset, u1, v0); - t.vertexUV(x, y, blitOffset, u0, v0); - t.draw(); -} - -void ItemRenderer::renderGuiItemDecorations(const ItemInstance* item, float x, float y) { - if (!item) return; - if (item->count > 0 && item->isDamaged()) { - float p = std::floor(13.5f - (float) item->getDamageValue() * 13.0f / (float) item->getMaxDamage()); - int cc = (int) std::floor(255.5f - (float) item->getDamageValue() * 255.0f / (float) item->getMaxDamage()); - //glDisable(GL_LIGHTING); - //glDisable(GL_DEPTH_TEST); - //glDisable(GL_TEXTURE_2D); - - Tesselator& t = Tesselator::instance; - - int ca = (255 - cc) << 16 | (cc) << 8; - int cb = ((255 - cc) / 4) << 16 | (255 / 4) << 8; - fillRect(t, x + 2, y + 13, 13, 1, 0x000000); - fillRect(t, x + 2, y + 13, 12, 1, cb); - fillRect(t, x + 2, y + 13, p, 1, ca); - - //glEnable(GL_TEXTURE_2D); - //glEnable(GL_LIGHTING); - //glEnable(GL_DEPTH_TEST); - glColor4f2(1, 1, 1, 1); - } -} - -void ItemRenderer::fillRect(Tesselator& t, float x, float y, float w, float h, int c) { - t.begin(); - t.color(c); - t.vertex(x + 0, y + 0, 0); - t.vertex(x + 0, y + h, 0); - t.vertex(x + w, y + h, 0); - t.vertex(x + w, y + 0, 0); - t.draw(); -} - - -void ItemRenderer::renderGuiItemCorrect(Font* font, Textures* textures, const ItemInstance* item, int x, int y) { - if (item == NULL) - return; - - //glDisable(GL_CULL_FACE); - if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) - { - int paint = item->id; - textures->loadAndBindTexture("terrain.png"); - - static float ff = 0;// ff += 0.005f; - static float gg = 0;// gg += 0.01f; - - Tile* tile = Tile::tiles[paint]; - glPushMatrix2(); - glTranslatef2((GLfloat)(x - 2), (GLfloat)(y + 3), -8); - glScalef2(10.0f, 10.0f, 10.0f); - glTranslatef2(1.0f, 0.5f, 0.0f); - glRotatef2(ff + 180.0f + 30.0f, 1, 0, 0); - glRotatef2(gg + 45.0f, 0, 1, 0); - - //glColor4f2(1, 1, 1, 1); - glScalef2(1, 1, 1); - tileRenderer->renderGuiTile(tile, item->getAuxValue()); - glPopMatrix2(); - } - else if (item->getIcon() >= 0) - { - //if (item->id == Item::camera->id) { - // printf("item->id: %d, %d\n", item->id, item->getIcon()); - //} - if (item->id < 256) { - textures->loadAndBindTexture("terrain.png"); - } else { - textures->loadAndBindTexture("gui/items.png"); - } - //Tesselator& t = Tesselator::instance; - //t.scale2d(Gui::InvGuiScale, Gui::InvGuiScale); - blit((float)x, (float)y, (float)(item->getIcon() % 16 * 16), (float)(item->getIcon() / 16 * 16), 16, 16); - //t.resetScale(); - } - //glEnable(GL_CULL_FACE); -} - -/*static*/ -void ItemRenderer::blit(float x, float y, float sx, float sy, float w, float h) { - float blitOffset = 0; - const float us = 1 / 256.0f; - const float vs = 1 / 256.0f; - Tesselator& t = Tesselator::instance; - t.begin(); - t.vertexUV(x, y + h, blitOffset, sx * us, (sy + h) * vs); - t.vertexUV(x + w, y + h, blitOffset, (sx + w) * us, (sy + h) * vs); - t.vertexUV(x + w, y, blitOffset, (sx + w) * us, sy * vs); - t.vertexUV(x, y, blitOffset, sx * us, sy * vs); - //t.end(); - t.draw(); -} +#include "ItemRenderer.hpp" +#include "EntityRenderDispatcher.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/TileRenderer.hpp" +#include "client/renderer/Textures.hpp" +#include "client/gui/Font.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Mth.hpp" +#include "util/Random.hpp" +#include "EntityRenderer.hpp" +#include "client/renderer/ItemInHandRenderer.hpp" +#include "client/gui/Gui.hpp" +#include "world/item/Item.hpp" + +/*static*/ +TileRenderer* ItemRenderer::tileRenderer = new TileRenderer(); + +ItemRenderer::ItemRenderer() +{ + shadowRadius = 0.15f; + shadowStrength = 0.75f; +} + +void ItemRenderer::teardown_static() { + if (tileRenderer) { + delete tileRenderer; + tileRenderer = NULL; + } +} + +void ItemRenderer::render(Entity* itemEntity_, float x, float y, float z, float rot, float a) { + ItemEntity* itemEntity = (ItemEntity*) itemEntity_; + random.setSeed(187); + ItemInstance* item = &itemEntity->item; + + glPushMatrix2(); + float bob = Mth::sin((itemEntity->age + a) / 10.0f + itemEntity->bobOffs) * 0.1f + 0.1f; + float spin = ((itemEntity->age + a) / 20.0f + itemEntity->bobOffs) * Mth::RADDEG; + + int count = 1; + if (item->count > 20) count = 4; + else if (item->count > 5) count = 3; + else if (item->count > 1) count = 2; + + glTranslatef2((float) x, (float) y + bob, (float) z); + //glEnable2(GL_RESCALE_NORMAL); + if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) { + glRotatef2(spin, 0, 1, 0); + + float br = itemEntity->getBrightness(a); + if (item->id == Tile::sand->id || item->id == Tile::sandStone->id) br *= 0.8f; + glColor4f2(br, br, br, 1.0f); + + bindTexture("terrain.png"); + float s = 1 / 4.0f; + //if (!Tile::tiles[item->id]->isCubeShaped() && item->id != Tile::stoneSlabHalf->id) { + const int shape = Tile::tiles[item->id]->getRenderShape(); + if (shape == Tile::SHAPE_CROSS_TEXTURE || shape == Tile::SHAPE_TORCH) + s = 0.5f; + + glScalef2(s, s, s); + for (int i = 0; i < count; i++) { + if (i > 0) { + glPushMatrix2(); + float xo = (random.nextFloat() * 2 - 1) * 0.2f / s; + float yo = (random.nextFloat() * 2 - 1) * 0.2f / s; + float zo = (random.nextFloat() * 2 - 1) * 0.2f / s; + glTranslatef2(xo, yo, zo); + } + //static Stopwatch w; + //w.start(); + entityRenderDispatcher->itemInHandRenderer->renderItem(NULL, item); + //tileRenderer->renderTile(Tile::tiles[item->id], item->getAuxValue()); + //w.stop(); + //w.printEvery(100, "render-item"); + if (i > 0) glPopMatrix2(); + } + } else { + glScalef2(1 / 2.0f, 1 / 2.0f, 1 / 2.0f); + int icon = item->getIcon(); + if (item->id < 256) { + bindTexture("terrain.png"); + } else { + bindTexture("gui/items.png"); + } + Tesselator& t = Tesselator::instance; + + float u0 = ((icon % 16) * 16 + 0) / 256.0f; + float u1 = ((icon % 16) * 16 + 16) / 256.0f; + float v0 = ((icon / 16) * 16 + 0) / 256.0f; + float v1 = ((icon / 16) * 16 + 16) / 256.0f; + + float r = 1.0f; + float xo = 0.5f; + float yo = 0.25f; + + // glRotatef2(-playerRotX, 1, 0, 0); + for (int i = 0; i < count; i++) { + glPushMatrix2(); + if (i > 0) { + float _xo = (random.nextFloat() * 2 - 1) * 0.3f; + float _yo = (random.nextFloat() * 2 - 1) * 0.3f; + float _zo = (random.nextFloat() * 2 - 1) * 0.3f; + glTranslatef2(_xo, _yo, _zo); + } + glRotatef2(180 - entityRenderDispatcher->playerRotY, 0, 1, 0); + t.begin(); + //t.normal(0, 1, 0); + t.vertexUV(0 - xo, 0 - yo, 0, u0, v1); + t.vertexUV(r - xo, 0 - yo, 0, u1, v1); + t.vertexUV(r - xo, 1 - yo, 0, u1, v0); + t.vertexUV(0 - xo, 1 - yo, 0, u0, v0); + //t.end(); + t.draw(); + + glPopMatrix2(); + } + } + //glDisable2(GL_RESCALE_NORMAL); + glPopMatrix2(); +} + + +// @note: _18 -> a,b,c,-1, a,b,c-1, ... +static const signed short _6[] = {139, 140, 141, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _17[] = {16, 17, 18, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _18[] = {79, 80, 81, -1, 79, 80, 81, -1, 79, 80, 81, -1, 79, 80, 81, -1}; +static const signed short _24[] = {11, 12, 13, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _35[] = {52, 59, 58, 57, 56, 55, 54, 53, 67, 66, 65, 64, 63, 62, 61, 60}; +static const signed short _44[] = {28, 32, 30, 29, 31, 33, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _98[] = {1, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _155[] = {34, 36, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _263[] = {230, 151, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static const signed short _351[] = {-1, 152, 154, -1, 193, 215, 216, -1, -1, 217, 218, 219, 220, 221, 222, 144}; + +static const signed short _mapper[] = {-1, 7, 9, 8, 0, 5, -2, -1, -1, -1, -1, -1, 14, 15, 39, 38, 37, -2, -2, -1, 49, 41, 46, -1, -2, -1, -1, -1, -1, -1, 235, -1, -1, -1, -1, -2, -1, 134, 135, 136, 137, 43, 44, -1, -2, 6, 76, 71, 4, 47, 129, -1, -1, 22, 74, -1, 40, 45, 72, -1, -1, 75, -1, -1, -1, 128, -1, 21, -1, -1, -1, -1, -1, 42, -1, -1, -1, -1, -1, -1, 48, 77, 10, 236, -1, 69, -1, 20, -1, 50, -1, -1, -1, -1, -1, -1, 68, -1, -2, -1, -1, -1, 130, 78, -1, -1, -1, 70, 23, 25, -1, -1, 19, -1, 26, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, 27, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 73, -1, 51, -1, -1, -1, -1, -1, 82, -1, -1, 174, 173, 175, 231, 234, 147, 190, -2, 153, 150, 149, 146, 185, 166, 164, 167, 186, 170, 169, 171, 187, 177, 176, 178, 165, 195, 194, 188, 181, 180, 182, 189, 191, 228, 168, 172, 145, 179, 183, 142, 233, 232, 198, 200, 201, 202, -1, -1, -1, -1, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 192, 156, 157, 133, -1, 148, 131, -1, -1, -1, -1, -1, -1, -1, 226, -1, 199, -1, 159, 158, 138, 224, 225, -1, -1, -1, -1, -1, -1, -1, 227, -1, -1, -2, 223, 229, -1, 132, -1, -1, -1, 184, 196, -1, 143, 160, 161, 162, 163, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 155, 197}; + +#define IRMAPCASE(x) case x: return _##x [item->getAuxValue() & 15] + +int ItemRenderer::getAtlasPos(const ItemInstance* item) { + int id = item->id; + if (id < 0 || id >= sizeof(_mapper) / sizeof(const signed short)) + return -1; + + int texId = _mapper[id]; + if (texId != -2) + return texId; + + switch(id) { + IRMAPCASE(6); + IRMAPCASE(17); + IRMAPCASE(18); + IRMAPCASE(24); + IRMAPCASE(35); + IRMAPCASE(44); + IRMAPCASE(98); + IRMAPCASE(155); + IRMAPCASE(263); + IRMAPCASE(351); + default: + break; + } + return -1; +} + +/*static*/ +void ItemRenderer::renderGuiItem(Font* font, Textures* textures, const ItemInstance* item, float x, float y, bool fancy) { + renderGuiItem(font, textures, item, x, y, 16, 16, fancy); +} +void ItemRenderer::renderGuiItem(Font* font, Textures* textures, const ItemInstance* item, float x, float y, float w, float h, bool fancy) { + if (item == NULL) { + //LOGW("item is NULL @ ItemRenderer::renderGuiItem\n"); + return; + } + const int id = item->id; + if (!Item::items[id]) + return; + + int i = getAtlasPos(item); + + if (i < 0) { + Tesselator& t = Tesselator::instance; + if (!t.isOverridden()) + renderGuiItemCorrect(font, textures, item, int(x), int(y)); + else { + // @huge @attn @todo @fix: This is just guess-works.. + // it we're batching for saving the + // buffer, this will fail miserably + t.endOverrideAndDraw(); + glDisable2(GL_TEXTURE_2D); + fillRect(t, x, y, w, h, 0xff0000); + glEnable2(GL_TEXTURE_2D); + renderGuiItemCorrect(font, textures, item, int(x), int(y)); + t.beginOverride(); + } + return; + } + + textures->loadAndBindTexture("gui/gui_blocks.png"); + float u0, u1, v0, v1; + if (i < 128) { + const float P = 48.0f / 512.0f; + u0 = (float)(i%10) * P; + v0 = (float)(i/10) * P; + u1 = u0 + P; + v1 = v0 + P; + } else { + i -= 128; + const float P = 16.0f / 512.0f; + u0 = float(i & 31) * P; + v0 = 27 * P + float(i >> 5) * P; // 27 "icon" rows down + u1 = u0 + P; + v1 = v0 + P; + } + + const float blitOffset = 0; + Tesselator& t = Tesselator::instance; + t.begin(); + t.colorABGR( item->count>0? 0xffffffff : 0x60ffffff); + t.vertexUV(x, y + h, blitOffset, u0, v1); + t.vertexUV(x + w, y + h, blitOffset, u1, v1); + t.vertexUV(x + w, y, blitOffset, u1, v0); + t.vertexUV(x, y, blitOffset, u0, v0); + t.draw(); +} + +void ItemRenderer::renderGuiItemDecorations(const ItemInstance* item, float x, float y) { + if (!item) return; + if (item->count > 0 && item->isDamaged()) { + float p = std::floor(13.5f - (float) item->getDamageValue() * 13.0f / (float) item->getMaxDamage()); + int cc = (int) std::floor(255.5f - (float) item->getDamageValue() * 255.0f / (float) item->getMaxDamage()); + //glDisable(GL_LIGHTING); + //glDisable(GL_DEPTH_TEST); + //glDisable(GL_TEXTURE_2D); + + Tesselator& t = Tesselator::instance; + + int ca = (255 - cc) << 16 | (cc) << 8; + int cb = ((255 - cc) / 4) << 16 | (255 / 4) << 8; + fillRect(t, x + 2, y + 13, 13, 1, 0x000000); + fillRect(t, x + 2, y + 13, 12, 1, cb); + fillRect(t, x + 2, y + 13, p, 1, ca); + + //glEnable(GL_TEXTURE_2D); + //glEnable(GL_LIGHTING); + //glEnable(GL_DEPTH_TEST); + glColor4f2(1, 1, 1, 1); + } +} + +void ItemRenderer::fillRect(Tesselator& t, float x, float y, float w, float h, int c) { + t.begin(); + t.color(c); + t.vertex(x + 0, y + 0, 0); + t.vertex(x + 0, y + h, 0); + t.vertex(x + w, y + h, 0); + t.vertex(x + w, y + 0, 0); + t.draw(); +} + + +void ItemRenderer::renderGuiItemCorrect(Font* font, Textures* textures, const ItemInstance* item, int x, int y) { + if (item == NULL) + return; + + //glDisable(GL_CULL_FACE); + if (item->id < 256 && TileRenderer::canRender(Tile::tiles[item->id]->getRenderShape())) + { + int paint = item->id; + textures->loadAndBindTexture("terrain.png"); + + static float ff = 0;// ff += 0.005f; + static float gg = 0;// gg += 0.01f; + + Tile* tile = Tile::tiles[paint]; + glPushMatrix2(); + glTranslatef2((GLfloat)(x - 2), (GLfloat)(y + 3), -8); + glScalef2(10.0f, 10.0f, 10.0f); + glTranslatef2(1.0f, 0.5f, 0.0f); + glRotatef2(ff + 180.0f + 30.0f, 1, 0, 0); + glRotatef2(gg + 45.0f, 0, 1, 0); + + //glColor4f2(1, 1, 1, 1); + glScalef2(1, 1, 1); + tileRenderer->renderGuiTile(tile, item->getAuxValue()); + glPopMatrix2(); + } + else if (item->getIcon() >= 0) + { + //if (item->id == Item::camera->id) { + // printf("item->id: %d, %d\n", item->id, item->getIcon()); + //} + if (item->id < 256) { + textures->loadAndBindTexture("terrain.png"); + } else { + textures->loadAndBindTexture("gui/items.png"); + } + //Tesselator& t = Tesselator::instance; + //t.scale2d(Gui::InvGuiScale, Gui::InvGuiScale); + blit((float)x, (float)y, (float)(item->getIcon() % 16 * 16), (float)(item->getIcon() / 16 * 16), 16, 16); + //t.resetScale(); + } + //glEnable(GL_CULL_FACE); +} + +/*static*/ +void ItemRenderer::blit(float x, float y, float sx, float sy, float w, float h) { + float blitOffset = 0; + const float us = 1 / 256.0f; + const float vs = 1 / 256.0f; + Tesselator& t = Tesselator::instance; + t.begin(); + t.vertexUV(x, y + h, blitOffset, sx * us, (sy + h) * vs); + t.vertexUV(x + w, y + h, blitOffset, (sx + w) * us, (sy + h) * vs); + t.vertexUV(x + w, y, blitOffset, (sx + w) * us, sy * vs); + t.vertexUV(x, y, blitOffset, sx * us, sy * vs); + //t.end(); + t.draw(); +} diff --git a/src/client/renderer/entity/ItemRenderer.h b/src/client/renderer/entity/ItemRenderer.hpp similarity index 94% rename from src/client/renderer/entity/ItemRenderer.h rename to src/client/renderer/entity/ItemRenderer.hpp index 9931e7d..c5c03f5 100755 --- a/src/client/renderer/entity/ItemRenderer.h +++ b/src/client/renderer/entity/ItemRenderer.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer.entity; -#include "EntityRenderer.h" -#include "../../../util/Random.h" +#include "EntityRenderer.hpp" +#include "util/Random.hpp" class Font; class Entity; diff --git a/src/client/renderer/entity/ItemSpriteRenderer.cpp b/src/client/renderer/entity/ItemSpriteRenderer.cpp index 7557c4d..f0eaaf6 100755 --- a/src/client/renderer/entity/ItemSpriteRenderer.cpp +++ b/src/client/renderer/entity/ItemSpriteRenderer.cpp @@ -1,41 +1,41 @@ -#include "ItemSpriteRenderer.h" -#include "EntityRenderDispatcher.h" -#include "../Tesselator.h" -#include "../../../world/entity/Entity.h" - - -ItemSpriteRenderer::ItemSpriteRenderer( int icon ) -: icon(icon) -{ -} - -void ItemSpriteRenderer::render( Entity* e, float x, float y, float z, float rot, float a ) -{ - glPushMatrix2(); - - glTranslatef2((float) x, (float) y, (float) z); - glScalef2(1 / 2.0f, 1 / 2.0f, 1 / 2.0f); - bindTexture("gui/items.png"); - Tesselator& t = Tesselator::instance; - - float u0 = ((icon % 16) * 16 + 0) / 256.0f; - float u1 = ((icon % 16) * 16 + 16) / 256.0f; - float v0 = ((icon / 16) * 16 + 0) / 256.0f; - float v1 = ((icon / 16) * 16 + 16) / 256.0f; - - - float r = 1.0f; - float xo = 0.5f; - float yo = 0.25f; - - glRotatef2(180 - entityRenderDispatcher->playerRotY, 0, 1, 0); - glRotatef2(-entityRenderDispatcher->playerRotX, 1, 0, 0); - t.begin(); - t.vertexUV(0 - xo, 0 - yo, 0, u0, v1); - t.vertexUV(r - xo, 0 - yo, 0, u1, v1); - t.vertexUV(r - xo, 1 - yo, 0, u1, v0); - t.vertexUV(0 - xo, 1 - yo, 0, u0, v0); - t.draw(); - - glPopMatrix2(); -} +#include "ItemSpriteRenderer.hpp" +#include "EntityRenderDispatcher.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/entity/Entity.hpp" + + +ItemSpriteRenderer::ItemSpriteRenderer( int icon ) +: icon(icon) +{ +} + +void ItemSpriteRenderer::render( Entity* e, float x, float y, float z, float rot, float a ) +{ + glPushMatrix2(); + + glTranslatef2((float) x, (float) y, (float) z); + glScalef2(1 / 2.0f, 1 / 2.0f, 1 / 2.0f); + bindTexture("gui/items.png"); + Tesselator& t = Tesselator::instance; + + float u0 = ((icon % 16) * 16 + 0) / 256.0f; + float u1 = ((icon % 16) * 16 + 16) / 256.0f; + float v0 = ((icon / 16) * 16 + 0) / 256.0f; + float v1 = ((icon / 16) * 16 + 16) / 256.0f; + + + float r = 1.0f; + float xo = 0.5f; + float yo = 0.25f; + + glRotatef2(180 - entityRenderDispatcher->playerRotY, 0, 1, 0); + glRotatef2(-entityRenderDispatcher->playerRotX, 1, 0, 0); + t.begin(); + t.vertexUV(0 - xo, 0 - yo, 0, u0, v1); + t.vertexUV(r - xo, 0 - yo, 0, u1, v1); + t.vertexUV(r - xo, 1 - yo, 0, u1, v0); + t.vertexUV(0 - xo, 1 - yo, 0, u0, v0); + t.draw(); + + glPopMatrix2(); +} diff --git a/src/client/renderer/entity/ItemSpriteRenderer.h b/src/client/renderer/entity/ItemSpriteRenderer.hpp similarity index 89% rename from src/client/renderer/entity/ItemSpriteRenderer.h rename to src/client/renderer/entity/ItemSpriteRenderer.hpp index d62c105..db039b0 100755 --- a/src/client/renderer/entity/ItemSpriteRenderer.h +++ b/src/client/renderer/entity/ItemSpriteRenderer.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.entity; -#include "EntityRenderer.h" +#include "EntityRenderer.hpp" class ItemSpriteRenderer: public EntityRenderer { diff --git a/src/client/renderer/entity/MobRenderer.cpp b/src/client/renderer/entity/MobRenderer.cpp index 51ccee9..010c4c7 100755 --- a/src/client/renderer/entity/MobRenderer.cpp +++ b/src/client/renderer/entity/MobRenderer.cpp @@ -1,241 +1,241 @@ -#include "MobRenderer.h" -#include "EntityRenderDispatcher.h" -#include "../../gui/Font.h" -#include "../Tesselator.h" -#include "../../Minecraft.h" -#include "../../model/Model.h" -#include "../../../world/entity/Mob.h" -#include "../../../util/Mth.h" - -MobRenderer::MobRenderer(Model* model, float shadow) -: model(model), - armor(NULL) -{ - shadowRadius = shadow; -} - -MobRenderer::~MobRenderer() { - delete model; -} - -void MobRenderer::setArmor(Model* armor) { - this->armor = armor; -} - -Model* MobRenderer::getArmor() { - return armor; -} - -void MobRenderer::render(Entity* e, float x, float y, float z, float rot, float a) -{ - Mob* mob = (Mob*) e; - - glPushMatrix2(); - glDisable2(GL_CULL_FACE); - - model->attackTime = getAttackAnim(mob, a); - model->riding = false;//mob.isRiding(); - model->young = mob->isBaby(); - - if (armor) { - armor->riding = model->riding; - armor->young = model->young; - armor->attackTime = model->attackTime; - } - - float bodyRot = (mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * a); - float headRot = (mob->yRotO + (mob->yRot - mob->yRotO) * a); - float headRotx = (mob->xRotO + (mob->xRot - mob->xRotO) * a); - - float yoffset = mob->heightOffset; - setupPosition(mob, x, y - yoffset, z); - - float bob = getBob(mob, a); - setupRotations(mob, bob, bodyRot, a); - - float ascale = 1 / 16.0f; - glScalef2(-1, -1, 1); - - scale(mob, a); - glTranslatef2(0, -24 * ascale - 0.125f / 16.0f, 0); - - float ws = mob->walkAnimSpeedO + (mob->walkAnimSpeed - mob->walkAnimSpeedO) * a; - float wp = mob->walkAnimPos - mob->walkAnimSpeed * (1 - a); - if (mob->isBaby()) { - wp *= 3.0f; - } - - if (ws > 1) ws = 1; - - bindTexture(mob->getTexture()); - //glEnable2(GL_ALPHA_TEST); - - model->prepareMobModel(mob, wp, ws, a); - model->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); - - for (int i = 0; i < MAX_ARMOR_LAYERS; i++) { - if (prepareArmor(mob, i, a) < 0) continue; - - armor->prepareMobModel(mob, wp, ws, a); - armor->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); - glDisable2(GL_BLEND); - glEnable2(GL_ALPHA_TEST); - } - - additionalRendering(mob, a); - float br = mob->getBrightness(a); - int overlayColor = getOverlayColor(mob, br, a); - - bool renderOverlay = ((overlayColor >> 24) & 0xff) > 0; - bool renderHurt = (mob->hurtTime > 0) || (mob->deathTime > 0); - - if (renderOverlay || renderHurt) { - glDisable2(GL_TEXTURE_2D); - glDisable2(GL_ALPHA_TEST); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthFunc(GL_EQUAL); - - if (renderHurt) { - glEnable(GL_COLOR_MATERIAL); - glColor4f2(br, 0, 0, 0.4f); - model->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); - for (int i = 0; i < MAX_ARMOR_LAYERS; i++) { - if (prepareArmor(mob, i, a) < 0) continue; - - glColor4f2(br, 0, 0, 0.4f); - armor->prepareMobModel(mob, wp, ws, a); - armor->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); - } - } - - if (renderOverlay) { - float r = ((overlayColor >> 16) & 0xff) / 255.0f; - float g = ((overlayColor >> 8) & 0xff) / 255.0f; - float b = ((overlayColor) & 0xff) / 255.0f; - float aa = ((overlayColor >> 24) & 0xff) / 255.0f; - glColor4f2(r, g, b, aa); - model->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); - for (int i = 0; i < MAX_ARMOR_LAYERS; i++) { - if (prepareArmor(mob, i, a) < 0) continue; - - glColor4f2(r, g, b, aa); - armor->prepareMobModel(mob, wp, ws, a); - armor->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); - } - } - - glDepthFunc(GL_LEQUAL); - glDisable2(GL_BLEND); - glEnable2(GL_ALPHA_TEST); - glEnable2(GL_TEXTURE_2D); - } - - glEnable2(GL_CULL_FACE); - //glEnable2(GL_DEPTH_TEST); - - glPopMatrix2(); - - renderName(mob, x, y, z); -} - -void MobRenderer::setupPosition(Entity* mob, float x, float y, float z) { - glTranslatef2((float) x, (float) y, (float) z); -} - -void MobRenderer::setupRotations(Entity* mob_, float bob, float bodyRot, float a) { - glRotatef2(180 - bodyRot, 0, 1, 0); - - Mob* mob = (Mob*)mob_; - if (mob->deathTime > 0) { - float fall = (mob->deathTime + a - 1) / 20.0f * 1.6f; - fall = Mth::sqrt(fall); - if (fall > 1) fall = 1; - glRotatef2(fall * getFlipDegrees(mob), 0, 0, 1); - } -} - -float MobRenderer::getAttackAnim(Mob* mob, float a) { - return mob->getAttackAnim(a); -} - -float MobRenderer::getBob(Mob* mob, float a) { - return (mob->tickCount + a); -} - -void MobRenderer::additionalRendering(Mob* mob, float a) { -} - -void MobRenderer::onGraphicsReset() { - if (model) model->onGraphicsReset(); - if (armor) armor->onGraphicsReset(); -} - -int MobRenderer::prepareArmor(Mob* mob, int layer, float a) { - return -1; -} - -float MobRenderer::getFlipDegrees(Mob* mob) { - return 90; -} - -int MobRenderer::getOverlayColor(Mob* mob, float br, float a) { - return 0; -} - -void MobRenderer::scale(Mob* mob, float a) { -} - -void MobRenderer::renderName(Mob* mob, float x, float y, float z) { - /* - std::stringstream ss; ss << mob->entityId; - renderNameTag(mob, ss.str(), x, y, z, 64); - */ -} - -void MobRenderer::renderNameTag(Mob* mob, const std::string& name, float x, float y, float z, int maxDist) { - float dist = mob->distanceToSqr(entityRenderDispatcher->cameraEntity); - - if (dist > maxDist*maxDist) - return; - - Font* font = getFont(); - - float size = 1.60f; - float s = 1 / 60.0f * size; - - glPushMatrix2(); - glTranslatef2((float) x + 0, (float) y + 1.0f /*2.3f*/, (float) z); - - glRotatef2(-entityRenderDispatcher->playerRotY, 0, 1, 0); - glRotatef2(entityRenderDispatcher->playerRotX, 1, 0, 0); - - glScalef2(-s, -s, s); - - glDepthMask(false); - glDisable2(GL_DEPTH_TEST); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - Tesselator& t = Tesselator::instance; - - glDisable2(GL_TEXTURE_2D); - t.begin(); - int w = font->width(name) / 2; - t.color(0.0f, 0.0f, 0.0f, 0.25f); - t.vertex(-(float)w - 1, -1, 0); - t.vertex(-(float)w - 1, +8, 0); - t.vertex(+(float)w + 1, +8, 0); - t.vertex(+(float)w + 1, -1, 0); - //t.end(); - t.draw(); - glEnable2(GL_TEXTURE_2D); - const float fnameWidth = (float)font->width(name) / -2; - font->draw(name, fnameWidth, 0, 0x20ffffff); - glEnable2(GL_DEPTH_TEST); - - glDepthMask(true); - font->draw(name, (float) fnameWidth, 0, 0xffffffff); - glDisable2(GL_BLEND); - glColor4f2(1, 1, 1, 1); - glPopMatrix2(); -} +#include "MobRenderer.hpp" +#include "EntityRenderDispatcher.hpp" +#include "client/gui/Font.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/Minecraft.hpp" +#include "client/model/Model.hpp" +#include "world/entity/Mob.hpp" +#include "util/Mth.hpp" + +MobRenderer::MobRenderer(Model* model, float shadow) +: model(model), + armor(NULL) +{ + shadowRadius = shadow; +} + +MobRenderer::~MobRenderer() { + delete model; +} + +void MobRenderer::setArmor(Model* armor) { + this->armor = armor; +} + +Model* MobRenderer::getArmor() { + return armor; +} + +void MobRenderer::render(Entity* e, float x, float y, float z, float rot, float a) +{ + Mob* mob = (Mob*) e; + + glPushMatrix2(); + glDisable2(GL_CULL_FACE); + + model->attackTime = getAttackAnim(mob, a); + model->riding = false;//mob.isRiding(); + model->young = mob->isBaby(); + + if (armor) { + armor->riding = model->riding; + armor->young = model->young; + armor->attackTime = model->attackTime; + } + + float bodyRot = (mob->yBodyRotO + (mob->yBodyRot - mob->yBodyRotO) * a); + float headRot = (mob->yRotO + (mob->yRot - mob->yRotO) * a); + float headRotx = (mob->xRotO + (mob->xRot - mob->xRotO) * a); + + float yoffset = mob->heightOffset; + setupPosition(mob, x, y - yoffset, z); + + float bob = getBob(mob, a); + setupRotations(mob, bob, bodyRot, a); + + float ascale = 1 / 16.0f; + glScalef2(-1, -1, 1); + + scale(mob, a); + glTranslatef2(0, -24 * ascale - 0.125f / 16.0f, 0); + + float ws = mob->walkAnimSpeedO + (mob->walkAnimSpeed - mob->walkAnimSpeedO) * a; + float wp = mob->walkAnimPos - mob->walkAnimSpeed * (1 - a); + if (mob->isBaby()) { + wp *= 3.0f; + } + + if (ws > 1) ws = 1; + + bindTexture(mob->getTexture()); + //glEnable2(GL_ALPHA_TEST); + + model->prepareMobModel(mob, wp, ws, a); + model->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); + + for (int i = 0; i < MAX_ARMOR_LAYERS; i++) { + if (prepareArmor(mob, i, a) < 0) continue; + + armor->prepareMobModel(mob, wp, ws, a); + armor->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); + glDisable2(GL_BLEND); + glEnable2(GL_ALPHA_TEST); + } + + additionalRendering(mob, a); + float br = mob->getBrightness(a); + int overlayColor = getOverlayColor(mob, br, a); + + bool renderOverlay = ((overlayColor >> 24) & 0xff) > 0; + bool renderHurt = (mob->hurtTime > 0) || (mob->deathTime > 0); + + if (renderOverlay || renderHurt) { + glDisable2(GL_TEXTURE_2D); + glDisable2(GL_ALPHA_TEST); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthFunc(GL_EQUAL); + + if (renderHurt) { + glEnable(GL_COLOR_MATERIAL); + glColor4f2(br, 0, 0, 0.4f); + model->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); + for (int i = 0; i < MAX_ARMOR_LAYERS; i++) { + if (prepareArmor(mob, i, a) < 0) continue; + + glColor4f2(br, 0, 0, 0.4f); + armor->prepareMobModel(mob, wp, ws, a); + armor->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); + } + } + + if (renderOverlay) { + float r = ((overlayColor >> 16) & 0xff) / 255.0f; + float g = ((overlayColor >> 8) & 0xff) / 255.0f; + float b = ((overlayColor) & 0xff) / 255.0f; + float aa = ((overlayColor >> 24) & 0xff) / 255.0f; + glColor4f2(r, g, b, aa); + model->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); + for (int i = 0; i < MAX_ARMOR_LAYERS; i++) { + if (prepareArmor(mob, i, a) < 0) continue; + + glColor4f2(r, g, b, aa); + armor->prepareMobModel(mob, wp, ws, a); + armor->render(e, wp, ws, bob, headRot - bodyRot, headRotx, ascale); + } + } + + glDepthFunc(GL_LEQUAL); + glDisable2(GL_BLEND); + glEnable2(GL_ALPHA_TEST); + glEnable2(GL_TEXTURE_2D); + } + + glEnable2(GL_CULL_FACE); + //glEnable2(GL_DEPTH_TEST); + + glPopMatrix2(); + + renderName(mob, x, y, z); +} + +void MobRenderer::setupPosition(Entity* mob, float x, float y, float z) { + glTranslatef2((float) x, (float) y, (float) z); +} + +void MobRenderer::setupRotations(Entity* mob_, float bob, float bodyRot, float a) { + glRotatef2(180 - bodyRot, 0, 1, 0); + + Mob* mob = (Mob*)mob_; + if (mob->deathTime > 0) { + float fall = (mob->deathTime + a - 1) / 20.0f * 1.6f; + fall = Mth::sqrt(fall); + if (fall > 1) fall = 1; + glRotatef2(fall * getFlipDegrees(mob), 0, 0, 1); + } +} + +float MobRenderer::getAttackAnim(Mob* mob, float a) { + return mob->getAttackAnim(a); +} + +float MobRenderer::getBob(Mob* mob, float a) { + return (mob->tickCount + a); +} + +void MobRenderer::additionalRendering(Mob* mob, float a) { +} + +void MobRenderer::onGraphicsReset() { + if (model) model->onGraphicsReset(); + if (armor) armor->onGraphicsReset(); +} + +int MobRenderer::prepareArmor(Mob* mob, int layer, float a) { + return -1; +} + +float MobRenderer::getFlipDegrees(Mob* mob) { + return 90; +} + +int MobRenderer::getOverlayColor(Mob* mob, float br, float a) { + return 0; +} + +void MobRenderer::scale(Mob* mob, float a) { +} + +void MobRenderer::renderName(Mob* mob, float x, float y, float z) { + /* + std::stringstream ss; ss << mob->entityId; + renderNameTag(mob, ss.str(), x, y, z, 64); + */ +} + +void MobRenderer::renderNameTag(Mob* mob, const std::string& name, float x, float y, float z, int maxDist) { + float dist = mob->distanceToSqr(entityRenderDispatcher->cameraEntity); + + if (dist > maxDist*maxDist) + return; + + Font* font = getFont(); + + float size = 1.60f; + float s = 1 / 60.0f * size; + + glPushMatrix2(); + glTranslatef2((float) x + 0, (float) y + 1.0f /*2.3f*/, (float) z); + + glRotatef2(-entityRenderDispatcher->playerRotY, 0, 1, 0); + glRotatef2(entityRenderDispatcher->playerRotX, 1, 0, 0); + + glScalef2(-s, -s, s); + + glDepthMask(false); + glDisable2(GL_DEPTH_TEST); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Tesselator& t = Tesselator::instance; + + glDisable2(GL_TEXTURE_2D); + t.begin(); + int w = font->width(name) / 2; + t.color(0.0f, 0.0f, 0.0f, 0.25f); + t.vertex(-(float)w - 1, -1, 0); + t.vertex(-(float)w - 1, +8, 0); + t.vertex(+(float)w + 1, +8, 0); + t.vertex(+(float)w + 1, -1, 0); + //t.end(); + t.draw(); + glEnable2(GL_TEXTURE_2D); + const float fnameWidth = (float)font->width(name) / -2; + font->draw(name, fnameWidth, 0, 0x20ffffff); + glEnable2(GL_DEPTH_TEST); + + glDepthMask(true); + font->draw(name, (float) fnameWidth, 0, 0xffffffff); + glDisable2(GL_BLEND); + glColor4f2(1, 1, 1, 1); + glPopMatrix2(); +} diff --git a/src/client/renderer/entity/MobRenderer.h b/src/client/renderer/entity/MobRenderer.hpp similarity index 97% rename from src/client/renderer/entity/MobRenderer.h rename to src/client/renderer/entity/MobRenderer.hpp index 5f53638..1fd96f4 100755 --- a/src/client/renderer/entity/MobRenderer.h +++ b/src/client/renderer/entity/MobRenderer.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.entity; -#include "EntityRenderer.h" +#include "EntityRenderer.hpp" #include diff --git a/src/client/renderer/entity/PaintingRenderer.cpp b/src/client/renderer/entity/PaintingRenderer.cpp index 1513e95..8ffd98a 100755 --- a/src/client/renderer/entity/PaintingRenderer.cpp +++ b/src/client/renderer/entity/PaintingRenderer.cpp @@ -1,99 +1,99 @@ -#include "PaintingRenderer.h" -#include "../../../world/entity/Painting.h" -#include "../../../world/Direction.h" -#include "../Tesselator.h" -#include "../Textures.h" -#include "../gles.h" - -void PaintingRenderer::render( Entity* entity, float x, float y, float z, float rot, float a ) { - glPushMatrix(); - glTranslatef(float(x), float(y), float(z)); - glRotatef(rot, 0, 1.0f, 0); - //glEnable(GL_RESCALE_NORMAL); - bindTexture("art/kz.png"); - Painting* painting = (Painting*)entity; - const Motive* motive = painting->motive; - - float s = 1.0f / 16.0f; - glScalef(s, s, s); - renderPainting(painting, motive->w, motive->h, motive->uo, motive->vo, a); - //glDisable(GL_RESCALE_NORMAL); - glPopMatrix(); -} - -void PaintingRenderer::renderPainting( Painting* painting, int w, int h, int uo, int vo, float a) { - float xx0 = -w / 2.0f; - float yy0 = -h / 2.0f; - - float edgeWidth = 0.5f; - - // Back - float bu0 = (12 * 16) / 256.0f; - float bu1 = (12 * 16 + 16) / 256.0f; - float bv0 = (0) / 256.0f; - float bv1 = (0 + 16) / 256.0f; - - // Border - float uu0 = (12 * 16) / 256.0f; - float uu1 = (12 * 16 + 16) / 256.0f; - float uv0 = (0.5f) / 256.0f; - float uv1 = (0.5f) / 256.0f; - - // Border - float su0 = (12 * 16 + 0.5f) / 256.0f; - float su1 = (12 * 16 + 0.5f) / 256.0f; - float sv0 = (0) / 256.0f; - float sv1 = (0 + 16) / 256.0f; - - for (int xs = 0; xs < w / 16; xs++) { - for (int ys = 0; ys < h / 16; ys++) { - float x0 = xx0 + (xs + 1) * 16; - float x1 = xx0 + (xs) * 16; - float y0 = yy0 + (ys + 1) * 16; - float y1 = yy0 + (ys) * 16; - //setBrightness(painting, (x0 + x1) / 2, (y0 + y1) / 2); - - // Painting - float fu0 = (uo + w - (xs) * 16) / 256.0f; - float fu1 = (uo + w - (xs + 1) * 16) / 256.0f; - float fv0 = (vo + h - (ys) * 16) / 256.0f; - float fv1 = (vo + h - (ys + 1) * 16) / 256.0f; - - Tesselator& t = Tesselator::instance; - float br = painting->getBrightness(a); - t.color(br, br, br); - - t.begin(); - t.vertexUV(x0, y1, -edgeWidth, fu1, fv0); - t.vertexUV(x1, y1, -edgeWidth, fu0, fv0); - t.vertexUV(x1, y0, -edgeWidth, fu0, fv1); - t.vertexUV(x0, y0, -edgeWidth, fu1, fv1); - - t.vertexUV(x0, y0, edgeWidth, bu0, bv0); - t.vertexUV(x1, y0, edgeWidth, bu1, bv0); - t.vertexUV(x1, y1, edgeWidth, bu1, bv1); - t.vertexUV(x0, y1, edgeWidth, bu0, bv1); - - t.vertexUV(x0, y0, -edgeWidth, uu0, uv0); - t.vertexUV(x1, y0, -edgeWidth, uu1, uv0); - t.vertexUV(x1, y0, edgeWidth, uu1, uv1); - t.vertexUV(x0, y0, edgeWidth, uu0, uv1); - - t.vertexUV(x0, y1, edgeWidth, uu0, uv0); - t.vertexUV(x1, y1, edgeWidth, uu1, uv0); - t.vertexUV(x1, y1, -edgeWidth, uu1, uv1); - t.vertexUV(x0, y1, -edgeWidth, uu0, uv1); - - t.vertexUV(x0, y0, edgeWidth, su1, sv0); - t.vertexUV(x0, y1, edgeWidth, su1, sv1); - t.vertexUV(x0, y1, -edgeWidth, su0, sv1); - t.vertexUV(x0, y0, -edgeWidth, su0, sv0); - - t.vertexUV(x1, y0, -edgeWidth, su1, sv0); - t.vertexUV(x1, y1, -edgeWidth, su1, sv1); - t.vertexUV(x1, y1, edgeWidth, su0, sv1); - t.vertexUV(x1, y0, edgeWidth, su0, sv0); - t.draw(); - } - } +#include "PaintingRenderer.hpp" +#include "world/entity/Painting.hpp" +#include "world/Direction.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/renderer/Textures.hpp" +#include "client/renderer/gles.hpp" + +void PaintingRenderer::render( Entity* entity, float x, float y, float z, float rot, float a ) { + glPushMatrix(); + glTranslatef(float(x), float(y), float(z)); + glRotatef(rot, 0, 1.0f, 0); + //glEnable(GL_RESCALE_NORMAL); + bindTexture("art/kz.png"); + Painting* painting = (Painting*)entity; + const Motive* motive = painting->motive; + + float s = 1.0f / 16.0f; + glScalef(s, s, s); + renderPainting(painting, motive->w, motive->h, motive->uo, motive->vo, a); + //glDisable(GL_RESCALE_NORMAL); + glPopMatrix(); +} + +void PaintingRenderer::renderPainting( Painting* painting, int w, int h, int uo, int vo, float a) { + float xx0 = -w / 2.0f; + float yy0 = -h / 2.0f; + + float edgeWidth = 0.5f; + + // Back + float bu0 = (12 * 16) / 256.0f; + float bu1 = (12 * 16 + 16) / 256.0f; + float bv0 = (0) / 256.0f; + float bv1 = (0 + 16) / 256.0f; + + // Border + float uu0 = (12 * 16) / 256.0f; + float uu1 = (12 * 16 + 16) / 256.0f; + float uv0 = (0.5f) / 256.0f; + float uv1 = (0.5f) / 256.0f; + + // Border + float su0 = (12 * 16 + 0.5f) / 256.0f; + float su1 = (12 * 16 + 0.5f) / 256.0f; + float sv0 = (0) / 256.0f; + float sv1 = (0 + 16) / 256.0f; + + for (int xs = 0; xs < w / 16; xs++) { + for (int ys = 0; ys < h / 16; ys++) { + float x0 = xx0 + (xs + 1) * 16; + float x1 = xx0 + (xs) * 16; + float y0 = yy0 + (ys + 1) * 16; + float y1 = yy0 + (ys) * 16; + //setBrightness(painting, (x0 + x1) / 2, (y0 + y1) / 2); + + // Painting + float fu0 = (uo + w - (xs) * 16) / 256.0f; + float fu1 = (uo + w - (xs + 1) * 16) / 256.0f; + float fv0 = (vo + h - (ys) * 16) / 256.0f; + float fv1 = (vo + h - (ys + 1) * 16) / 256.0f; + + Tesselator& t = Tesselator::instance; + float br = painting->getBrightness(a); + t.color(br, br, br); + + t.begin(); + t.vertexUV(x0, y1, -edgeWidth, fu1, fv0); + t.vertexUV(x1, y1, -edgeWidth, fu0, fv0); + t.vertexUV(x1, y0, -edgeWidth, fu0, fv1); + t.vertexUV(x0, y0, -edgeWidth, fu1, fv1); + + t.vertexUV(x0, y0, edgeWidth, bu0, bv0); + t.vertexUV(x1, y0, edgeWidth, bu1, bv0); + t.vertexUV(x1, y1, edgeWidth, bu1, bv1); + t.vertexUV(x0, y1, edgeWidth, bu0, bv1); + + t.vertexUV(x0, y0, -edgeWidth, uu0, uv0); + t.vertexUV(x1, y0, -edgeWidth, uu1, uv0); + t.vertexUV(x1, y0, edgeWidth, uu1, uv1); + t.vertexUV(x0, y0, edgeWidth, uu0, uv1); + + t.vertexUV(x0, y1, edgeWidth, uu0, uv0); + t.vertexUV(x1, y1, edgeWidth, uu1, uv0); + t.vertexUV(x1, y1, -edgeWidth, uu1, uv1); + t.vertexUV(x0, y1, -edgeWidth, uu0, uv1); + + t.vertexUV(x0, y0, edgeWidth, su1, sv0); + t.vertexUV(x0, y1, edgeWidth, su1, sv1); + t.vertexUV(x0, y1, -edgeWidth, su0, sv1); + t.vertexUV(x0, y0, -edgeWidth, su0, sv0); + + t.vertexUV(x1, y0, -edgeWidth, su1, sv0); + t.vertexUV(x1, y1, -edgeWidth, su1, sv1); + t.vertexUV(x1, y1, edgeWidth, su0, sv1); + t.vertexUV(x1, y0, edgeWidth, su0, sv0); + t.draw(); + } + } } \ No newline at end of file diff --git a/src/client/renderer/entity/PaintingRenderer.h b/src/client/renderer/entity/PaintingRenderer.hpp similarity index 89% rename from src/client/renderer/entity/PaintingRenderer.h rename to src/client/renderer/entity/PaintingRenderer.hpp index 58b3333..c44967f 100755 --- a/src/client/renderer/entity/PaintingRenderer.h +++ b/src/client/renderer/entity/PaintingRenderer.hpp @@ -1,5 +1,5 @@ #pragma once -#include "EntityRenderer.h" +#include "EntityRenderer.hpp" class Painting; class PaintingRenderer : public EntityRenderer { public: diff --git a/src/client/renderer/entity/PigRenderer.h b/src/client/renderer/entity/PigRenderer.hpp similarity index 87% rename from src/client/renderer/entity/PigRenderer.h rename to src/client/renderer/entity/PigRenderer.hpp index 261456a..284b959 100755 --- a/src/client/renderer/entity/PigRenderer.h +++ b/src/client/renderer/entity/PigRenderer.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer.entity; -#include "../../model/Model.h" -#include "../../../world/entity/animal/Pig.h" +#include "client/model/Model.hpp" +#include "world/entity/animal/Pig.hpp" class PigRenderer: public MobRenderer { diff --git a/src/client/renderer/entity/PlayerRenderer.cpp b/src/client/renderer/entity/PlayerRenderer.cpp index 96ee2eb..8461498 100755 --- a/src/client/renderer/entity/PlayerRenderer.cpp +++ b/src/client/renderer/entity/PlayerRenderer.cpp @@ -1,124 +1,124 @@ -#include "PlayerRenderer.h" -#include "EntityRenderDispatcher.h" -#include "../Textures.h" -#include "../../../world/entity/player/Player.h" -#include "../../../world/level/Level.h" -#include "../../../world/item/ArmorItem.h" - -static const std::string armorFilenames[10] = { - "armor/cloth_1.png", "armor/cloth_2.png", - "armor/chain_1.png", "armor/chain_2.png", - "armor/iron_1.png", "armor/iron_2.png", - "armor/diamond_1.png", "armor/diamond_2.png", - "armor/gold_1.png", "armor/gold_2.png", -}; - -PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow ) -: super(humanoidModel, shadow), - playerModel64(humanoidModel), - playerModel32(new HumanoidModel(0, 0, 64, 32)), - armorParts1(new HumanoidModel(1.0f, 0, 64, 32)), - armorParts2(new HumanoidModel(0.5f, 0, 64, 32)) -{ - // default to legacy skin path until we know the exact texture size - model = playerModel32; - humanoidModel = playerModel32; -} - -PlayerRenderer::~PlayerRenderer() { - // prevent MobRenderer destructor from deleting model pointers we manage manually - model = nullptr; - - delete playerModel32; - delete playerModel64; - delete armorParts1; - delete armorParts2; -} - -void PlayerRenderer::setupPosition( Entity* mob, float x, float y, float z ) { - Player* player = (Player*) mob; - if(player->isAlive() && player->isSleeping()) { - return super::setupPosition(mob, x + player->bedOffsetX, y + player->bedOffsetY, z + player->bedOffsetZ); - } - return super::setupPosition(mob, x, y, z); -} - -void PlayerRenderer::setupRotations( Entity* mob, float bob, float bodyRot, float a ) { - Player* player = (Player*) mob; - if(player->isAlive() && player->isSleeping()) { - glRotatef(player->getSleepRotation(), 0, 1, 0); - glRotatef(getFlipDegrees(player), 0, 0, 1); - glRotatef(270, 0, 1, 0); - return; - } - super::setupRotations(mob, bob, bodyRot, a); -} - -bool PlayerRenderer::isModernPlayerSkin(Mob* mob) { - const std::string texName = mob->getTexture(); - TextureId texId = entityRenderDispatcher->textures->loadTexture(texName); - if (!Textures::isTextureIdValid(texId)) - return false; - const TextureData* texData = entityRenderDispatcher->textures->getTemporaryTextureData(texId); - return texData && texData->w == 64 && texData->h == 64; -} - -void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){ - //@todo: figure out how to handle HideGUI - if (mob != entityRenderDispatcher->cameraEntity && mob->level->adventureSettings.showNameTags) { - renderNameTag(mob, ((Player*)mob)->name, x, y, z, 32); - } -} - -void PlayerRenderer::render(Entity* mob_, float x, float y, float z, float rot, float a) { - Mob* mob = (Mob*) mob_; - HumanoidModel* desired = isModernPlayerSkin(mob) ? playerModel64 : playerModel32; - if (model != desired || humanoidModel != desired) { - model = desired; - humanoidModel = desired; - } - LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n", - ((Player*)mob)->name.c_str(), mob->getTexture().c_str(), - humanoidModel->texWidth, humanoidModel->texHeight, - (desired == playerModel64 ? "64" : "32")); - HumanoidMobRenderer::render(mob_, x, y, z, rot, a); -} - -int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) { - Player* player = (Player*) mob; - - ItemInstance* itemInstance = player->getArmor(layer); - if (!ItemInstance::isArmorItem(itemInstance)) - return -1; - - ArmorItem* armorItem = (ArmorItem*) itemInstance->getItem(); - int fnIndex = (armorItem->modelIndex + armorItem->modelIndex) + (layer == 2 ? 1 : 0); - bindTexture(armorFilenames[fnIndex]); - - HumanoidModel* armor = layer == 2 ? armorParts2 : armorParts1; - - armor->head.visible = layer == 0; - //armor.hair.visible = layer == 0; - armor->body.visible = layer == 1 || layer == 2; - armor->arm0.visible = layer == 1; - armor->arm1.visible = layer == 1; - armor->leg0.visible = layer == 2 || layer == 3; - armor->leg1.visible = layer == 2 || layer == 3; - - setArmor(armor); - - /*if (itemInstance.isEnchanted()) - return 15; */ - - return 1; -} - -void PlayerRenderer::onGraphicsReset() { - if (playerModel32) playerModel32->onGraphicsReset(); - if (playerModel64) playerModel64->onGraphicsReset(); - - if (armorParts1) armorParts1->onGraphicsReset(); - if (armorParts2) armorParts2->onGraphicsReset(); - - super::onGraphicsReset(); -} +#include "PlayerRenderer.hpp" +#include "EntityRenderDispatcher.hpp" +#include "client/renderer/Textures.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/item/ArmorItem.hpp" + +static const std::string armorFilenames[10] = { + "armor/cloth_1.png", "armor/cloth_2.png", + "armor/chain_1.png", "armor/chain_2.png", + "armor/iron_1.png", "armor/iron_2.png", + "armor/diamond_1.png", "armor/diamond_2.png", + "armor/gold_1.png", "armor/gold_2.png", +}; + +PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow ) +: super(humanoidModel, shadow), + playerModel64(humanoidModel), + playerModel32(new HumanoidModel(0, 0, 64, 32)), + armorParts1(new HumanoidModel(1.0f, 0, 64, 32)), + armorParts2(new HumanoidModel(0.5f, 0, 64, 32)) +{ + // default to legacy skin path until we know the exact texture size + model = playerModel32; + humanoidModel = playerModel32; +} + +PlayerRenderer::~PlayerRenderer() { + // prevent MobRenderer destructor from deleting model pointers we manage manually + model = nullptr; + + delete playerModel32; + delete playerModel64; + delete armorParts1; + delete armorParts2; +} + +void PlayerRenderer::setupPosition( Entity* mob, float x, float y, float z ) { + Player* player = (Player*) mob; + if(player->isAlive() && player->isSleeping()) { + return super::setupPosition(mob, x + player->bedOffsetX, y + player->bedOffsetY, z + player->bedOffsetZ); + } + return super::setupPosition(mob, x, y, z); +} + +void PlayerRenderer::setupRotations( Entity* mob, float bob, float bodyRot, float a ) { + Player* player = (Player*) mob; + if(player->isAlive() && player->isSleeping()) { + glRotatef(player->getSleepRotation(), 0, 1, 0); + glRotatef(getFlipDegrees(player), 0, 0, 1); + glRotatef(270, 0, 1, 0); + return; + } + super::setupRotations(mob, bob, bodyRot, a); +} + +bool PlayerRenderer::isModernPlayerSkin(Mob* mob) { + const std::string texName = mob->getTexture(); + TextureId texId = entityRenderDispatcher->textures->loadTexture(texName); + if (!Textures::isTextureIdValid(texId)) + return false; + const TextureData* texData = entityRenderDispatcher->textures->getTemporaryTextureData(texId); + return texData && texData->w == 64 && texData->h == 64; +} + +void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){ + //@todo: figure out how to handle HideGUI + if (mob != entityRenderDispatcher->cameraEntity && mob->level->adventureSettings.showNameTags) { + renderNameTag(mob, ((Player*)mob)->name, x, y, z, 32); + } +} + +void PlayerRenderer::render(Entity* mob_, float x, float y, float z, float rot, float a) { + Mob* mob = (Mob*) mob_; + HumanoidModel* desired = isModernPlayerSkin(mob) ? playerModel64 : playerModel32; + if (model != desired || humanoidModel != desired) { + model = desired; + humanoidModel = desired; + } + LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n", + ((Player*)mob)->name.c_str(), mob->getTexture().c_str(), + humanoidModel->texWidth, humanoidModel->texHeight, + (desired == playerModel64 ? "64" : "32")); + HumanoidMobRenderer::render(mob_, x, y, z, rot, a); +} + +int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) { + Player* player = (Player*) mob; + + ItemInstance* itemInstance = player->getArmor(layer); + if (!ItemInstance::isArmorItem(itemInstance)) + return -1; + + ArmorItem* armorItem = (ArmorItem*) itemInstance->getItem(); + int fnIndex = (armorItem->modelIndex + armorItem->modelIndex) + (layer == 2 ? 1 : 0); + bindTexture(armorFilenames[fnIndex]); + + HumanoidModel* armor = layer == 2 ? armorParts2 : armorParts1; + + armor->head.visible = layer == 0; + //armor.hair.visible = layer == 0; + armor->body.visible = layer == 1 || layer == 2; + armor->arm0.visible = layer == 1; + armor->arm1.visible = layer == 1; + armor->leg0.visible = layer == 2 || layer == 3; + armor->leg1.visible = layer == 2 || layer == 3; + + setArmor(armor); + + /*if (itemInstance.isEnchanted()) + return 15; */ + + return 1; +} + +void PlayerRenderer::onGraphicsReset() { + if (playerModel32) playerModel32->onGraphicsReset(); + if (playerModel64) playerModel64->onGraphicsReset(); + + if (armorParts1) armorParts1->onGraphicsReset(); + if (armorParts2) armorParts2->onGraphicsReset(); + + super::onGraphicsReset(); +} diff --git a/src/client/renderer/entity/PlayerRenderer.h b/src/client/renderer/entity/PlayerRenderer.hpp similarity index 95% rename from src/client/renderer/entity/PlayerRenderer.h rename to src/client/renderer/entity/PlayerRenderer.hpp index 1552277..c109ecb 100755 --- a/src/client/renderer/entity/PlayerRenderer.h +++ b/src/client/renderer/entity/PlayerRenderer.hpp @@ -1,6 +1,6 @@ #pragma once -#include "HumanoidMobRenderer.h" +#include "HumanoidMobRenderer.hpp" class PlayerRenderer : public HumanoidMobRenderer { diff --git a/src/client/renderer/entity/SheepRenderer.cpp b/src/client/renderer/entity/SheepRenderer.cpp index e8f6650..6a1a713 100755 --- a/src/client/renderer/entity/SheepRenderer.cpp +++ b/src/client/renderer/entity/SheepRenderer.cpp @@ -1,29 +1,29 @@ -#include "SheepRenderer.h" -#include "../../../world/entity/animal/Sheep.h" -#include "../gles.h" - -SheepRenderer::SheepRenderer( Model* model, Model* armor, float shadow ) -: super(model, shadow) -{ - setArmor(armor); -} - -SheepRenderer::~SheepRenderer() { - delete getArmor(); -} - -int SheepRenderer::prepareArmor(Mob* mob, int layer, float a) { - Sheep* sheep = (Sheep*) mob; - - if (layer == 0 && !sheep->isSheared()) { - bindTexture("mob/sheep_fur.png"); - - float brightness = sheep->getBrightness(a); - int color = sheep->getColor(); - glColor4f2( brightness * Sheep::COLOR[color][0], - brightness * Sheep::COLOR[color][1], - brightness * Sheep::COLOR[color][2], 1); - return 1; - } - return -1; -} +#include "SheepRenderer.hpp" +#include "world/entity/animal/Sheep.hpp" +#include "client/renderer/gles.hpp" + +SheepRenderer::SheepRenderer( Model* model, Model* armor, float shadow ) +: super(model, shadow) +{ + setArmor(armor); +} + +SheepRenderer::~SheepRenderer() { + delete getArmor(); +} + +int SheepRenderer::prepareArmor(Mob* mob, int layer, float a) { + Sheep* sheep = (Sheep*) mob; + + if (layer == 0 && !sheep->isSheared()) { + bindTexture("mob/sheep_fur.png"); + + float brightness = sheep->getBrightness(a); + int color = sheep->getColor(); + glColor4f2( brightness * Sheep::COLOR[color][0], + brightness * Sheep::COLOR[color][1], + brightness * Sheep::COLOR[color][2], 1); + return 1; + } + return -1; +} diff --git a/src/client/renderer/entity/SheepRenderer.h b/src/client/renderer/entity/SheepRenderer.hpp similarity index 91% rename from src/client/renderer/entity/SheepRenderer.h rename to src/client/renderer/entity/SheepRenderer.hpp index c074d45..5e628ac 100755 --- a/src/client/renderer/entity/SheepRenderer.h +++ b/src/client/renderer/entity/SheepRenderer.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.renderer.entity; -#include "MobRenderer.h" +#include "MobRenderer.hpp" class Mob; class SheepRenderer: public MobRenderer diff --git a/src/client/renderer/entity/SpiderRenderer.h b/src/client/renderer/entity/SpiderRenderer.hpp similarity index 86% rename from src/client/renderer/entity/SpiderRenderer.h rename to src/client/renderer/entity/SpiderRenderer.hpp index ef41f95..2075d32 100755 --- a/src/client/renderer/entity/SpiderRenderer.h +++ b/src/client/renderer/entity/SpiderRenderer.hpp @@ -2,11 +2,11 @@ //package net.minecraft.client.renderer.entity; -#include "MobRenderer.h" +#include "MobRenderer.hpp" -#include "../gles.h" -#include "../../model/SpiderModel.h" -#include "../../../world/entity/monster/Spider.h" +#include "client/renderer/gles.hpp" +#include "client/model/SpiderModel.hpp" +#include "world/entity/monster/Spider.hpp" class SpiderRenderer: public MobRenderer { diff --git a/src/client/renderer/entity/TntRenderer.cpp b/src/client/renderer/entity/TntRenderer.cpp index 6371656..5ff9479 100755 --- a/src/client/renderer/entity/TntRenderer.cpp +++ b/src/client/renderer/entity/TntRenderer.cpp @@ -1,47 +1,47 @@ -#include "TntRenderer.h" -#include "../Tesselator.h" -#include "../../../world/level/tile/Tile.h" -#include "../../../world/entity/item/PrimedTnt.h" - - -TntRenderer::TntRenderer() -{ - this->shadowRadius = 0.5f; -} - -void TntRenderer::render( Entity* tnt_, float x, float y, float z, float rot, float a ) -{ - PrimedTnt* tnt = (PrimedTnt*)tnt_; - glPushMatrix2(); - glTranslatef2((float) x, (float) y, (float) z); - if (tnt->life - a + 1 < 10) { - float g = 1 - ((tnt->life - a + 1) / 10.0f); - if (g < 0) g = 0; - if (g > 1) g = 1; - g = g * g; - g = g * g; - float s = 1.0f + g * 0.3f; - glScalef2(s, s, s); - } - - float br = (1 - ((tnt->life - a + 1) / 100.0f)) * 0.8f; - bindTexture("terrain.png"); - - Tesselator& t = Tesselator::instance; - t.color(1.0f, 1.0f, 1.0f); - tileRenderer.renderTile(Tile::tnt, 0); - - if (((tnt->life / 5) & 1) == 0) { - glDisable2(GL_TEXTURE_2D); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_DST_ALPHA); - glColor4f2(1, 1, 1, br); - //t.color(1.0f, 1.0f, 1.0f, br); - tileRenderer.renderTile(Tile::tnt, 0); - glColor4f2(1, 1, 1, 1); - glDisable2(GL_BLEND); - //glEnable2(GL_LIGHTING); - glEnable2(GL_TEXTURE_2D); - } - glPopMatrix2(); -} +#include "TntRenderer.hpp" +#include "client/renderer/Tesselator.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/entity/item/PrimedTnt.hpp" + + +TntRenderer::TntRenderer() +{ + this->shadowRadius = 0.5f; +} + +void TntRenderer::render( Entity* tnt_, float x, float y, float z, float rot, float a ) +{ + PrimedTnt* tnt = (PrimedTnt*)tnt_; + glPushMatrix2(); + glTranslatef2((float) x, (float) y, (float) z); + if (tnt->life - a + 1 < 10) { + float g = 1 - ((tnt->life - a + 1) / 10.0f); + if (g < 0) g = 0; + if (g > 1) g = 1; + g = g * g; + g = g * g; + float s = 1.0f + g * 0.3f; + glScalef2(s, s, s); + } + + float br = (1 - ((tnt->life - a + 1) / 100.0f)) * 0.8f; + bindTexture("terrain.png"); + + Tesselator& t = Tesselator::instance; + t.color(1.0f, 1.0f, 1.0f); + tileRenderer.renderTile(Tile::tnt, 0); + + if (((tnt->life / 5) & 1) == 0) { + glDisable2(GL_TEXTURE_2D); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_DST_ALPHA); + glColor4f2(1, 1, 1, br); + //t.color(1.0f, 1.0f, 1.0f, br); + tileRenderer.renderTile(Tile::tnt, 0); + glColor4f2(1, 1, 1, 1); + glDisable2(GL_BLEND); + //glEnable2(GL_LIGHTING); + glEnable2(GL_TEXTURE_2D); + } + glPopMatrix2(); +} diff --git a/src/client/renderer/entity/TntRenderer.h b/src/client/renderer/entity/TntRenderer.hpp similarity index 76% rename from src/client/renderer/entity/TntRenderer.h rename to src/client/renderer/entity/TntRenderer.hpp index c5fdd37..a9fc4e6 100755 --- a/src/client/renderer/entity/TntRenderer.h +++ b/src/client/renderer/entity/TntRenderer.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer.entity; -#include "EntityRenderer.h" -#include "../TileRenderer.h" +#include "EntityRenderer.hpp" +#include "client/renderer/TileRenderer.hpp" class TntRenderer: public EntityRenderer { diff --git a/src/client/renderer/entity/TripodCameraRenderer.cpp b/src/client/renderer/entity/TripodCameraRenderer.cpp index 97838d5..b9db99c 100755 --- a/src/client/renderer/entity/TripodCameraRenderer.cpp +++ b/src/client/renderer/entity/TripodCameraRenderer.cpp @@ -1,75 +1,75 @@ -#include "TripodCameraRenderer.h" -#include "EntityRenderDispatcher.h" -#include "../Tesselator.h" -#include "../../Minecraft.h" -#include "../../../world/entity/item/TripodCamera.h" -#include "../../../world/level/material/Material.h" - -TripodCameraRenderer::TripodCameraRenderer() -: tripod(0, 15 * 16 + 3, Material::plant), - cameraCube(0, 0) -{ - cameraCube.addBox(-4, -4, -6, 8, 8, 10); - cameraCube.y = 11; - this->shadowRadius = 0.5f; -} - -float TripodCameraRenderer::getFlashTime(const TripodCamera* c, float a) { - if (c->life >= 8) return -1; - if (c->life < 0) return -1; - return (c->life - a) * 0.125f; -} - -void TripodCameraRenderer::render(Entity* cam_, float x, float y, float z, float rot, float a) { - TripodCamera* cam = (TripodCamera*)cam_; - - glPushMatrix2(); - glTranslatef2((float) x, (float) y, (float) z); - - cameraCube.xRot = Mth::DEGRAD * (180.0f + cam->xRot * 0.5f); - cameraCube.yRot = -Mth::DEGRAD * cam->yRot; - - //float br = (1 - ((cam->life - a + 1) / 100.0f)) * 0.8f; - - Tesselator& t = Tesselator::instance; - t.color(1.0f, 1.0f, 1.0f); - - //printf("xyz: %f, %f, %f\n", x, y, z); - - // Render tripod legs - bindTexture("gui/items.png"); - t.begin(); - tileRenderer.tesselateCrossTexture(&tripod, 0, -0.5f, -0.5f, -0.5f);//, y, z); - t.draw(); - - // Render tripod - bindTexture("item/camera.png"); - cameraCube.render(1.0f / 16.0f); - - bool isCurrentlyPicked = entityRenderDispatcher->minecraft->hitResult.entity == cam; - - const float flashLife = getFlashTime(cam, a); - - if (flashLife >= 0) { - const float flashStrength = ::sin(flashLife * 6.2830f); - - // Flash - glColor4f2(1, 1, 1, flashStrength); - glColor4f2(1, 1, 1, 1); - } - - // "red light" flashing when photo is about to go off - if (isCurrentlyPicked) { - glDisable2(GL_TEXTURE_2D); - glEnable2(GL_BLEND); - glBlendFunc2(GL_SRC_ALPHA, GL_DST_ALPHA); - glColor4f2(0.5f,0.5f,0.5f,0.5f); - - cameraCube.renderHorrible(1.0f / 16.0f); - - glColor4f2(1,1,1,1); - glDisable2(GL_BLEND); - glEnable2(GL_TEXTURE_2D); - } - glPopMatrix2(); -} +#include "TripodCameraRenderer.hpp" +#include "EntityRenderDispatcher.hpp" +#include "client/renderer/Tesselator.hpp" +#include "client/Minecraft.hpp" +#include "world/entity/item/TripodCamera.hpp" +#include "world/level/material/Material.hpp" + +TripodCameraRenderer::TripodCameraRenderer() +: tripod(0, 15 * 16 + 3, Material::plant), + cameraCube(0, 0) +{ + cameraCube.addBox(-4, -4, -6, 8, 8, 10); + cameraCube.y = 11; + this->shadowRadius = 0.5f; +} + +float TripodCameraRenderer::getFlashTime(const TripodCamera* c, float a) { + if (c->life >= 8) return -1; + if (c->life < 0) return -1; + return (c->life - a) * 0.125f; +} + +void TripodCameraRenderer::render(Entity* cam_, float x, float y, float z, float rot, float a) { + TripodCamera* cam = (TripodCamera*)cam_; + + glPushMatrix2(); + glTranslatef2((float) x, (float) y, (float) z); + + cameraCube.xRot = Mth::DEGRAD * (180.0f + cam->xRot * 0.5f); + cameraCube.yRot = -Mth::DEGRAD * cam->yRot; + + //float br = (1 - ((cam->life - a + 1) / 100.0f)) * 0.8f; + + Tesselator& t = Tesselator::instance; + t.color(1.0f, 1.0f, 1.0f); + + //printf("xyz: %f, %f, %f\n", x, y, z); + + // Render tripod legs + bindTexture("gui/items.png"); + t.begin(); + tileRenderer.tesselateCrossTexture(&tripod, 0, -0.5f, -0.5f, -0.5f);//, y, z); + t.draw(); + + // Render tripod + bindTexture("item/camera.png"); + cameraCube.render(1.0f / 16.0f); + + bool isCurrentlyPicked = entityRenderDispatcher->minecraft->hitResult.entity == cam; + + const float flashLife = getFlashTime(cam, a); + + if (flashLife >= 0) { + const float flashStrength = ::sin(flashLife * 6.2830f); + + // Flash + glColor4f2(1, 1, 1, flashStrength); + glColor4f2(1, 1, 1, 1); + } + + // "red light" flashing when photo is about to go off + if (isCurrentlyPicked) { + glDisable2(GL_TEXTURE_2D); + glEnable2(GL_BLEND); + glBlendFunc2(GL_SRC_ALPHA, GL_DST_ALPHA); + glColor4f2(0.5f,0.5f,0.5f,0.5f); + + cameraCube.renderHorrible(1.0f / 16.0f); + + glColor4f2(1,1,1,1); + glDisable2(GL_BLEND); + glEnable2(GL_TEXTURE_2D); + } + glPopMatrix2(); +} diff --git a/src/client/renderer/entity/TripodCameraRenderer.h b/src/client/renderer/entity/TripodCameraRenderer.hpp similarity index 71% rename from src/client/renderer/entity/TripodCameraRenderer.h rename to src/client/renderer/entity/TripodCameraRenderer.hpp index 16d5d34..8c6320e 100755 --- a/src/client/renderer/entity/TripodCameraRenderer.h +++ b/src/client/renderer/entity/TripodCameraRenderer.hpp @@ -1,9 +1,9 @@ #pragma once -#include "EntityRenderer.h" -#include "../TileRenderer.h" -#include "../../model/geom/ModelPart.h" -#include "../../../world/level/tile/Tile.h" +#include "EntityRenderer.hpp" +#include "client/renderer/TileRenderer.hpp" +#include "client/model/geom/ModelPart.hpp" +#include "world/level/tile/Tile.hpp" class TripodCamera; diff --git a/src/client/renderer/gles.cpp b/src/client/renderer/gles.cpp index 04ae3d3..2fad6ab 100755 --- a/src/client/renderer/gles.cpp +++ b/src/client/renderer/gles.cpp @@ -1,386 +1,386 @@ -#include "gles.h" -#include -#include - -static const float __glPi = 3.14159265358979323846f; - -static void __gluMakeIdentityf(GLfloat m[16]); - - -void gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) { - GLfloat m[4][4]; - GLfloat sine, cotangent, deltaZ; - GLfloat radians=(GLfloat)(fovy/2.0f*__glPi/180.0f); - - deltaZ=zFar-zNear; - sine=(GLfloat)sin(radians); - if ((deltaZ==0.0f) || (sine==0.0f) || (aspect==0.0f)) - { - return; - } - cotangent=(GLfloat)(cos(radians)/sine); - - __gluMakeIdentityf(&m[0][0]); - m[0][0] = cotangent / aspect; - m[1][1] = cotangent; - m[2][2] = -(zFar + zNear) / deltaZ; - m[2][3] = -1.0f; - m[3][2] = -2.0f * zNear * zFar / deltaZ; - m[3][3] = 0; - glMultMatrixf(&m[0][0]); -} - -void __gluMakeIdentityf(GLfloat m[16]) { - m[0] = 1; m[4] = 0; m[8] = 0; m[12] = 0; - m[1] = 0; m[5] = 1; m[9] = 0; m[13] = 0; - m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; - m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; -} - -void glInit() -{ -#ifndef OPENGL_ES - - GLenum err = glewInit(); - printf("Err: %d\n", err); -#endif -} - -void anGenBuffers(GLsizei n, GLuint* buffers) { -#ifdef __EMSCRIPTEN__ - glGenBuffers(n, buffers); -#else - static GLuint k = 1; - for (int i = 0; i < n; ++i) - buffers[i] = ++k; -#endif -} - -#ifdef USE_VBO -void drawArrayVT(int bufferId, int vertices, int vertexSize /* = 24 */, unsigned int mode /* = GL_TRIANGLES */) { - //if (Options::debugGl) LOGI("drawArray\n"); - glBindBuffer2(GL_ARRAY_BUFFER, bufferId); - glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - glVertexPointer2(3, GL_FLOAT, vertexSize, 0); - glEnableClientState2(GL_VERTEX_ARRAY); - glDrawArrays2(mode, 0, vertices); - glDisableClientState2(GL_VERTEX_ARRAY); - glDisableClientState2(GL_TEXTURE_COORD_ARRAY); -} - -#ifndef drawArrayVT_NoState -void drawArrayVT_NoState(int bufferId, int vertices, int vertexSize /* = 24 */) { - //if (Options::debugGl) LOGI("drawArray\n"); - glBindBuffer2(GL_ARRAY_BUFFER, bufferId); - glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); - //glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - glVertexPointer2(3, GL_FLOAT, vertexSize, 0); - //glEnableClientState2(GL_VERTEX_ARRAY); - glDrawArrays2(GL_TRIANGLES, 0, vertices); - //glDisableClientState2(GL_VERTEX_ARRAY); - //glDisableClientState2(GL_TEXTURE_COORD_ARRAY); -} -#endif - -void drawArrayVTC(int bufferId, int vertices, int vertexSize /* = 24 */) { - //if (Options::debugGl) LOGI("drawArray\n"); - //LOGI("draw-vtc: %d, %d, %d\n", bufferId, vertices, vertexSize); - glEnableClientState2(GL_VERTEX_ARRAY); - glEnableClientState2(GL_TEXTURE_COORD_ARRAY); - glEnableClientState2(GL_COLOR_ARRAY); - - glBindBuffer2(GL_ARRAY_BUFFER, bufferId); - - glVertexPointer2( 3, GL_FLOAT, vertexSize, 0); - glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); - glColorPointer2(4, GL_UNSIGNED_BYTE, vertexSize, (GLvoid*) (5*4)); - - glDrawArrays2(GL_TRIANGLES, 0, vertices); - - glDisableClientState2(GL_VERTEX_ARRAY); - glDisableClientState2(GL_TEXTURE_COORD_ARRAY); - glDisableClientState2(GL_COLOR_ARRAY); -} - -#ifndef drawArrayVTC_NoState -void drawArrayVTC_NoState(int bufferId, int vertices, int vertexSize /* = 24 */) { - glBindBuffer2(GL_ARRAY_BUFFER, bufferId); - - glVertexPointer2( 3, GL_FLOAT, vertexSize, 0); - glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); - glColorPointer2(4, GL_UNSIGNED_BYTE, vertexSize, (GLvoid*) (5*4)); - - glDrawArrays2(GL_TRIANGLES, 0, vertices); -} -#endif - -#endif - - -// -// Code borrowed from OpenGL.org -// http://www.opengl.org/wiki/GluProject_and_gluUnProject_code -// The gluUnProject code in Android seems to be broken -// - -void MultiplyMatrices4by4OpenGL_FLOAT(float *result, float *matrix1, float *matrix2) -{ - result[0]=matrix1[0]*matrix2[0]+ - matrix1[4]*matrix2[1]+ - matrix1[8]*matrix2[2]+ - matrix1[12]*matrix2[3]; - result[4]=matrix1[0]*matrix2[4]+ - matrix1[4]*matrix2[5]+ - matrix1[8]*matrix2[6]+ - matrix1[12]*matrix2[7]; - result[8]=matrix1[0]*matrix2[8]+ - matrix1[4]*matrix2[9]+ - matrix1[8]*matrix2[10]+ - matrix1[12]*matrix2[11]; - result[12]=matrix1[0]*matrix2[12]+ - matrix1[4]*matrix2[13]+ - matrix1[8]*matrix2[14]+ - matrix1[12]*matrix2[15]; - result[1]=matrix1[1]*matrix2[0]+ - matrix1[5]*matrix2[1]+ - matrix1[9]*matrix2[2]+ - matrix1[13]*matrix2[3]; - result[5]=matrix1[1]*matrix2[4]+ - matrix1[5]*matrix2[5]+ - matrix1[9]*matrix2[6]+ - matrix1[13]*matrix2[7]; - result[9]=matrix1[1]*matrix2[8]+ - matrix1[5]*matrix2[9]+ - matrix1[9]*matrix2[10]+ - matrix1[13]*matrix2[11]; - result[13]=matrix1[1]*matrix2[12]+ - matrix1[5]*matrix2[13]+ - matrix1[9]*matrix2[14]+ - matrix1[13]*matrix2[15]; - result[2]=matrix1[2]*matrix2[0]+ - matrix1[6]*matrix2[1]+ - matrix1[10]*matrix2[2]+ - matrix1[14]*matrix2[3]; - result[6]=matrix1[2]*matrix2[4]+ - matrix1[6]*matrix2[5]+ - matrix1[10]*matrix2[6]+ - matrix1[14]*matrix2[7]; - result[10]=matrix1[2]*matrix2[8]+ - matrix1[6]*matrix2[9]+ - matrix1[10]*matrix2[10]+ - matrix1[14]*matrix2[11]; - result[14]=matrix1[2]*matrix2[12]+ - matrix1[6]*matrix2[13]+ - matrix1[10]*matrix2[14]+ - matrix1[14]*matrix2[15]; - result[3]=matrix1[3]*matrix2[0]+ - matrix1[7]*matrix2[1]+ - matrix1[11]*matrix2[2]+ - matrix1[15]*matrix2[3]; - result[7]=matrix1[3]*matrix2[4]+ - matrix1[7]*matrix2[5]+ - matrix1[11]*matrix2[6]+ - matrix1[15]*matrix2[7]; - result[11]=matrix1[3]*matrix2[8]+ - matrix1[7]*matrix2[9]+ - matrix1[11]*matrix2[10]+ - matrix1[15]*matrix2[11]; - result[15]=matrix1[3]*matrix2[12]+ - matrix1[7]*matrix2[13]+ - matrix1[11]*matrix2[14]+ - matrix1[15]*matrix2[15]; -} - -void MultiplyMatrixByVector4by4OpenGL_FLOAT(float *resultvector, const float *matrix, const float *pvector) -{ - resultvector[0]=matrix[0]*pvector[0]+matrix[4]*pvector[1]+matrix[8]*pvector[2]+matrix[12]*pvector[3]; - resultvector[1]=matrix[1]*pvector[0]+matrix[5]*pvector[1]+matrix[9]*pvector[2]+matrix[13]*pvector[3]; - resultvector[2]=matrix[2]*pvector[0]+matrix[6]*pvector[1]+matrix[10]*pvector[2]+matrix[14]*pvector[3]; - resultvector[3]=matrix[3]*pvector[0]+matrix[7]*pvector[1]+matrix[11]*pvector[2]+matrix[15]*pvector[3]; -} - -#define SWAP_ROWS_DOUBLE(a, b) { double *_tmp = a; (a)=(b); (b)=_tmp; } -#define SWAP_ROWS_FLOAT(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; } -#define MAT(m,r,c) (m)[(c)*4+(r)] - -//This code comes directly from GLU except that it is for float -int glhInvertMatrixf2(float *m, float *out) -{ - float wtmp[4][8]; - float m0, m1, m2, m3, s; - float *r0, *r1, *r2, *r3; - r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; - r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1), - r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3), - r0[4] = 1.0f, r0[5] = r0[6] = r0[7] = 0.0f, - r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1), - r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3), - r1[5] = 1.0f, r1[4] = r1[6] = r1[7] = 0.0f, - r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1), - r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3), - r2[6] = 1.0f, r2[4] = r2[5] = r2[7] = 0.0f, - r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1), - r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3), - r3[7] = 1.0f, r3[4] = r3[5] = r3[6] = 0.0f; - /* choose pivot - or die */ - if (fabsf(r3[0]) > fabsf(r2[0])) - SWAP_ROWS_FLOAT(r3, r2); - if (fabsf(r2[0]) > fabsf(r1[0])) - SWAP_ROWS_FLOAT(r2, r1); - if (fabsf(r1[0]) > fabsf(r0[0])) - SWAP_ROWS_FLOAT(r1, r0); - if (0.0f == r0[0]) - return 0; - /* eliminate first variable */ - m1 = r1[0] / r0[0]; - m2 = r2[0] / r0[0]; - m3 = r3[0] / r0[0]; - s = r0[1]; - r1[1] -= m1 * s; - r2[1] -= m2 * s; - r3[1] -= m3 * s; - s = r0[2]; - r1[2] -= m1 * s; - r2[2] -= m2 * s; - r3[2] -= m3 * s; - s = r0[3]; - r1[3] -= m1 * s; - r2[3] -= m2 * s; - r3[3] -= m3 * s; - s = r0[4]; - if (s != 0.0f) { - r1[4] -= m1 * s; - r2[4] -= m2 * s; - r3[4] -= m3 * s; - } - s = r0[5]; - if (s != 0.0f) { - r1[5] -= m1 * s; - r2[5] -= m2 * s; - r3[5] -= m3 * s; - } - s = r0[6]; - if (s != 0.0f) { - r1[6] -= m1 * s; - r2[6] -= m2 * s; - r3[6] -= m3 * s; - } - s = r0[7]; - if (s != 0.0f) { - r1[7] -= m1 * s; - r2[7] -= m2 * s; - r3[7] -= m3 * s; - } - /* choose pivot - or die */ - if (fabsf(r3[1]) > fabsf(r2[1])) - SWAP_ROWS_FLOAT(r3, r2); - if (fabsf(r2[1]) > fabsf(r1[1])) - SWAP_ROWS_FLOAT(r2, r1); - if (0.0f == r1[1]) - return 0; - /* eliminate second variable */ - m2 = r2[1] / r1[1]; - m3 = r3[1] / r1[1]; - r2[2] -= m2 * r1[2]; - r3[2] -= m3 * r1[2]; - r2[3] -= m2 * r1[3]; - r3[3] -= m3 * r1[3]; - s = r1[4]; - if (0.0f != s) { - r2[4] -= m2 * s; - r3[4] -= m3 * s; - } - s = r1[5]; - if (0.0f != s) { - r2[5] -= m2 * s; - r3[5] -= m3 * s; - } - s = r1[6]; - if (0.0f != s) { - r2[6] -= m2 * s; - r3[6] -= m3 * s; - } - s = r1[7]; - if (0.0f != s) { - r2[7] -= m2 * s; - r3[7] -= m3 * s; - } - /* choose pivot - or die */ - if (fabsf(r3[2]) > fabsf(r2[2])) - SWAP_ROWS_FLOAT(r3, r2); - if (0.0f == r2[2]) - return 0; - /* eliminate third variable */ - m3 = r3[2] / r2[2]; - r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], - r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7]; - /* last check */ - if (0.0f == r3[3]) - return 0; - s = 1.0f / r3[3]; /* now back substitute row 3 */ - r3[4] *= s; - r3[5] *= s; - r3[6] *= s; - r3[7] *= s; - m2 = r2[3]; /* now back substitute row 2 */ - s = 1.0f / r2[2]; - r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), - r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); - m1 = r1[3]; - r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, - r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; - m0 = r0[3]; - r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, - r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; - m1 = r1[2]; /* now back substitute row 1 */ - s = 1.0f / r1[1]; - r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), - r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); - m0 = r0[2]; - r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, - r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; - m0 = r0[1]; /* now back substitute row 0 */ - s = 1.0f / r0[0]; - r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), - r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); - MAT(out, 0, 0) = r0[4]; - MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6]; - MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4]; - MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6]; - MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4]; - MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6]; - MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4]; - MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6]; - MAT(out, 3, 3) = r3[7]; - return 1; -} - -int glhUnProjectf( float winx, float winy, float winz, - float *modelview, float *projection, - int *viewport, float *objectCoordinate) -{ - //Transformation matrices - float m[16], A[16]; - float in[4], out[4]; - //Calculation for inverting a matrix, compute projection x modelview - //and store in A[16] - MultiplyMatrices4by4OpenGL_FLOAT(A, projection, modelview); - //Now compute the inverse of matrix A - if(glhInvertMatrixf2(A, m)==0) - return 0; - //Transformation of normalized coordinates between -1 and 1 - in[0]=(winx-(float)viewport[0])/(float)viewport[2]*2.0f-1.0f; - in[1]=(winy-(float)viewport[1])/(float)viewport[3]*2.0f-1.0f; - in[2]=2.0f*winz-1.0f; - in[3]=1.0f; - //Objects coordinates - MultiplyMatrixByVector4by4OpenGL_FLOAT(out, m, in); - if(out[3]==0.0f) - return 0; - out[3]=1.0f/out[3]; - objectCoordinate[0]=out[0]*out[3]; - objectCoordinate[1]=out[1]*out[3]; - objectCoordinate[2]=out[2]*out[3]; - return 1; -} +#include "gles.hpp" +#include +#include + +static const float __glPi = 3.14159265358979323846f; + +static void __gluMakeIdentityf(GLfloat m[16]); + + +void gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) { + GLfloat m[4][4]; + GLfloat sine, cotangent, deltaZ; + GLfloat radians=(GLfloat)(fovy/2.0f*__glPi/180.0f); + + deltaZ=zFar-zNear; + sine=(GLfloat)sin(radians); + if ((deltaZ==0.0f) || (sine==0.0f) || (aspect==0.0f)) + { + return; + } + cotangent=(GLfloat)(cos(radians)/sine); + + __gluMakeIdentityf(&m[0][0]); + m[0][0] = cotangent / aspect; + m[1][1] = cotangent; + m[2][2] = -(zFar + zNear) / deltaZ; + m[2][3] = -1.0f; + m[3][2] = -2.0f * zNear * zFar / deltaZ; + m[3][3] = 0; + glMultMatrixf(&m[0][0]); +} + +void __gluMakeIdentityf(GLfloat m[16]) { + m[0] = 1; m[4] = 0; m[8] = 0; m[12] = 0; + m[1] = 0; m[5] = 1; m[9] = 0; m[13] = 0; + m[2] = 0; m[6] = 0; m[10] = 1; m[14] = 0; + m[3] = 0; m[7] = 0; m[11] = 0; m[15] = 1; +} + +void glInit() +{ +#ifndef OPENGL_ES + + GLenum err = glewInit(); + printf("Err: %d\n", err); +#endif +} + +void anGenBuffers(GLsizei n, GLuint* buffers) { +#ifdef __EMSCRIPTEN__ + glGenBuffers(n, buffers); +#else + static GLuint k = 1; + for (int i = 0; i < n; ++i) + buffers[i] = ++k; +#endif +} + +#ifdef USE_VBO +void drawArrayVT(int bufferId, int vertices, int vertexSize /* = 24 */, unsigned int mode /* = GL_TRIANGLES */) { + //if (Options::debugGl) LOGI("drawArray\n"); + glBindBuffer2(GL_ARRAY_BUFFER, bufferId); + glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + glVertexPointer2(3, GL_FLOAT, vertexSize, 0); + glEnableClientState2(GL_VERTEX_ARRAY); + glDrawArrays2(mode, 0, vertices); + glDisableClientState2(GL_VERTEX_ARRAY); + glDisableClientState2(GL_TEXTURE_COORD_ARRAY); +} + +#ifndef drawArrayVT_NoState +void drawArrayVT_NoState(int bufferId, int vertices, int vertexSize /* = 24 */) { + //if (Options::debugGl) LOGI("drawArray\n"); + glBindBuffer2(GL_ARRAY_BUFFER, bufferId); + glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); + //glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + glVertexPointer2(3, GL_FLOAT, vertexSize, 0); + //glEnableClientState2(GL_VERTEX_ARRAY); + glDrawArrays2(GL_TRIANGLES, 0, vertices); + //glDisableClientState2(GL_VERTEX_ARRAY); + //glDisableClientState2(GL_TEXTURE_COORD_ARRAY); +} +#endif + +void drawArrayVTC(int bufferId, int vertices, int vertexSize /* = 24 */) { + //if (Options::debugGl) LOGI("drawArray\n"); + //LOGI("draw-vtc: %d, %d, %d\n", bufferId, vertices, vertexSize); + glEnableClientState2(GL_VERTEX_ARRAY); + glEnableClientState2(GL_TEXTURE_COORD_ARRAY); + glEnableClientState2(GL_COLOR_ARRAY); + + glBindBuffer2(GL_ARRAY_BUFFER, bufferId); + + glVertexPointer2( 3, GL_FLOAT, vertexSize, 0); + glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); + glColorPointer2(4, GL_UNSIGNED_BYTE, vertexSize, (GLvoid*) (5*4)); + + glDrawArrays2(GL_TRIANGLES, 0, vertices); + + glDisableClientState2(GL_VERTEX_ARRAY); + glDisableClientState2(GL_TEXTURE_COORD_ARRAY); + glDisableClientState2(GL_COLOR_ARRAY); +} + +#ifndef drawArrayVTC_NoState +void drawArrayVTC_NoState(int bufferId, int vertices, int vertexSize /* = 24 */) { + glBindBuffer2(GL_ARRAY_BUFFER, bufferId); + + glVertexPointer2( 3, GL_FLOAT, vertexSize, 0); + glTexCoordPointer2(2, GL_FLOAT, vertexSize, (GLvoid*) (3 * 4)); + glColorPointer2(4, GL_UNSIGNED_BYTE, vertexSize, (GLvoid*) (5*4)); + + glDrawArrays2(GL_TRIANGLES, 0, vertices); +} +#endif + +#endif + + +// +// Code borrowed from OpenGL.org +// http://www.opengl.org/wiki/GluProject_and_gluUnProject_code +// The gluUnProject code in Android seems to be broken +// + +void MultiplyMatrices4by4OpenGL_FLOAT(float *result, float *matrix1, float *matrix2) +{ + result[0]=matrix1[0]*matrix2[0]+ + matrix1[4]*matrix2[1]+ + matrix1[8]*matrix2[2]+ + matrix1[12]*matrix2[3]; + result[4]=matrix1[0]*matrix2[4]+ + matrix1[4]*matrix2[5]+ + matrix1[8]*matrix2[6]+ + matrix1[12]*matrix2[7]; + result[8]=matrix1[0]*matrix2[8]+ + matrix1[4]*matrix2[9]+ + matrix1[8]*matrix2[10]+ + matrix1[12]*matrix2[11]; + result[12]=matrix1[0]*matrix2[12]+ + matrix1[4]*matrix2[13]+ + matrix1[8]*matrix2[14]+ + matrix1[12]*matrix2[15]; + result[1]=matrix1[1]*matrix2[0]+ + matrix1[5]*matrix2[1]+ + matrix1[9]*matrix2[2]+ + matrix1[13]*matrix2[3]; + result[5]=matrix1[1]*matrix2[4]+ + matrix1[5]*matrix2[5]+ + matrix1[9]*matrix2[6]+ + matrix1[13]*matrix2[7]; + result[9]=matrix1[1]*matrix2[8]+ + matrix1[5]*matrix2[9]+ + matrix1[9]*matrix2[10]+ + matrix1[13]*matrix2[11]; + result[13]=matrix1[1]*matrix2[12]+ + matrix1[5]*matrix2[13]+ + matrix1[9]*matrix2[14]+ + matrix1[13]*matrix2[15]; + result[2]=matrix1[2]*matrix2[0]+ + matrix1[6]*matrix2[1]+ + matrix1[10]*matrix2[2]+ + matrix1[14]*matrix2[3]; + result[6]=matrix1[2]*matrix2[4]+ + matrix1[6]*matrix2[5]+ + matrix1[10]*matrix2[6]+ + matrix1[14]*matrix2[7]; + result[10]=matrix1[2]*matrix2[8]+ + matrix1[6]*matrix2[9]+ + matrix1[10]*matrix2[10]+ + matrix1[14]*matrix2[11]; + result[14]=matrix1[2]*matrix2[12]+ + matrix1[6]*matrix2[13]+ + matrix1[10]*matrix2[14]+ + matrix1[14]*matrix2[15]; + result[3]=matrix1[3]*matrix2[0]+ + matrix1[7]*matrix2[1]+ + matrix1[11]*matrix2[2]+ + matrix1[15]*matrix2[3]; + result[7]=matrix1[3]*matrix2[4]+ + matrix1[7]*matrix2[5]+ + matrix1[11]*matrix2[6]+ + matrix1[15]*matrix2[7]; + result[11]=matrix1[3]*matrix2[8]+ + matrix1[7]*matrix2[9]+ + matrix1[11]*matrix2[10]+ + matrix1[15]*matrix2[11]; + result[15]=matrix1[3]*matrix2[12]+ + matrix1[7]*matrix2[13]+ + matrix1[11]*matrix2[14]+ + matrix1[15]*matrix2[15]; +} + +void MultiplyMatrixByVector4by4OpenGL_FLOAT(float *resultvector, const float *matrix, const float *pvector) +{ + resultvector[0]=matrix[0]*pvector[0]+matrix[4]*pvector[1]+matrix[8]*pvector[2]+matrix[12]*pvector[3]; + resultvector[1]=matrix[1]*pvector[0]+matrix[5]*pvector[1]+matrix[9]*pvector[2]+matrix[13]*pvector[3]; + resultvector[2]=matrix[2]*pvector[0]+matrix[6]*pvector[1]+matrix[10]*pvector[2]+matrix[14]*pvector[3]; + resultvector[3]=matrix[3]*pvector[0]+matrix[7]*pvector[1]+matrix[11]*pvector[2]+matrix[15]*pvector[3]; +} + +#define SWAP_ROWS_DOUBLE(a, b) { double *_tmp = a; (a)=(b); (b)=_tmp; } +#define SWAP_ROWS_FLOAT(a, b) { float *_tmp = a; (a)=(b); (b)=_tmp; } +#define MAT(m,r,c) (m)[(c)*4+(r)] + +//This code comes directly from GLU except that it is for float +int glhInvertMatrixf2(float *m, float *out) +{ + float wtmp[4][8]; + float m0, m1, m2, m3, s; + float *r0, *r1, *r2, *r3; + r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; + r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1), + r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3), + r0[4] = 1.0f, r0[5] = r0[6] = r0[7] = 0.0f, + r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1), + r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3), + r1[5] = 1.0f, r1[4] = r1[6] = r1[7] = 0.0f, + r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1), + r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3), + r2[6] = 1.0f, r2[4] = r2[5] = r2[7] = 0.0f, + r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1), + r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3), + r3[7] = 1.0f, r3[4] = r3[5] = r3[6] = 0.0f; + /* choose pivot - or die */ + if (fabsf(r3[0]) > fabsf(r2[0])) + SWAP_ROWS_FLOAT(r3, r2); + if (fabsf(r2[0]) > fabsf(r1[0])) + SWAP_ROWS_FLOAT(r2, r1); + if (fabsf(r1[0]) > fabsf(r0[0])) + SWAP_ROWS_FLOAT(r1, r0); + if (0.0f == r0[0]) + return 0; + /* eliminate first variable */ + m1 = r1[0] / r0[0]; + m2 = r2[0] / r0[0]; + m3 = r3[0] / r0[0]; + s = r0[1]; + r1[1] -= m1 * s; + r2[1] -= m2 * s; + r3[1] -= m3 * s; + s = r0[2]; + r1[2] -= m1 * s; + r2[2] -= m2 * s; + r3[2] -= m3 * s; + s = r0[3]; + r1[3] -= m1 * s; + r2[3] -= m2 * s; + r3[3] -= m3 * s; + s = r0[4]; + if (s != 0.0f) { + r1[4] -= m1 * s; + r2[4] -= m2 * s; + r3[4] -= m3 * s; + } + s = r0[5]; + if (s != 0.0f) { + r1[5] -= m1 * s; + r2[5] -= m2 * s; + r3[5] -= m3 * s; + } + s = r0[6]; + if (s != 0.0f) { + r1[6] -= m1 * s; + r2[6] -= m2 * s; + r3[6] -= m3 * s; + } + s = r0[7]; + if (s != 0.0f) { + r1[7] -= m1 * s; + r2[7] -= m2 * s; + r3[7] -= m3 * s; + } + /* choose pivot - or die */ + if (fabsf(r3[1]) > fabsf(r2[1])) + SWAP_ROWS_FLOAT(r3, r2); + if (fabsf(r2[1]) > fabsf(r1[1])) + SWAP_ROWS_FLOAT(r2, r1); + if (0.0f == r1[1]) + return 0; + /* eliminate second variable */ + m2 = r2[1] / r1[1]; + m3 = r3[1] / r1[1]; + r2[2] -= m2 * r1[2]; + r3[2] -= m3 * r1[2]; + r2[3] -= m2 * r1[3]; + r3[3] -= m3 * r1[3]; + s = r1[4]; + if (0.0f != s) { + r2[4] -= m2 * s; + r3[4] -= m3 * s; + } + s = r1[5]; + if (0.0f != s) { + r2[5] -= m2 * s; + r3[5] -= m3 * s; + } + s = r1[6]; + if (0.0f != s) { + r2[6] -= m2 * s; + r3[6] -= m3 * s; + } + s = r1[7]; + if (0.0f != s) { + r2[7] -= m2 * s; + r3[7] -= m3 * s; + } + /* choose pivot - or die */ + if (fabsf(r3[2]) > fabsf(r2[2])) + SWAP_ROWS_FLOAT(r3, r2); + if (0.0f == r2[2]) + return 0; + /* eliminate third variable */ + m3 = r3[2] / r2[2]; + r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], + r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7]; + /* last check */ + if (0.0f == r3[3]) + return 0; + s = 1.0f / r3[3]; /* now back substitute row 3 */ + r3[4] *= s; + r3[5] *= s; + r3[6] *= s; + r3[7] *= s; + m2 = r2[3]; /* now back substitute row 2 */ + s = 1.0f / r2[2]; + r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), + r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); + m1 = r1[3]; + r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, + r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; + m0 = r0[3]; + r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, + r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; + m1 = r1[2]; /* now back substitute row 1 */ + s = 1.0f / r1[1]; + r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), + r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); + m0 = r0[2]; + r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, + r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; + m0 = r0[1]; /* now back substitute row 0 */ + s = 1.0f / r0[0]; + r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), + r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); + MAT(out, 0, 0) = r0[4]; + MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6]; + MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4]; + MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6]; + MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4]; + MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6]; + MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4]; + MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6]; + MAT(out, 3, 3) = r3[7]; + return 1; +} + +int glhUnProjectf( float winx, float winy, float winz, + float *modelview, float *projection, + int *viewport, float *objectCoordinate) +{ + //Transformation matrices + float m[16], A[16]; + float in[4], out[4]; + //Calculation for inverting a matrix, compute projection x modelview + //and store in A[16] + MultiplyMatrices4by4OpenGL_FLOAT(A, projection, modelview); + //Now compute the inverse of matrix A + if(glhInvertMatrixf2(A, m)==0) + return 0; + //Transformation of normalized coordinates between -1 and 1 + in[0]=(winx-(float)viewport[0])/(float)viewport[2]*2.0f-1.0f; + in[1]=(winy-(float)viewport[1])/(float)viewport[3]*2.0f-1.0f; + in[2]=2.0f*winz-1.0f; + in[3]=1.0f; + //Objects coordinates + MultiplyMatrixByVector4by4OpenGL_FLOAT(out, m, in); + if(out[3]==0.0f) + return 0; + out[3]=1.0f/out[3]; + objectCoordinate[0]=out[0]*out[3]; + objectCoordinate[1]=out[1]*out[3]; + objectCoordinate[2]=out[2]*out[3]; + return 1; +} diff --git a/src/client/renderer/gles.h b/src/client/renderer/gles.hpp similarity index 99% rename from src/client/renderer/gles.h rename to src/client/renderer/gles.hpp index 569da1b..8210401 100755 --- a/src/client/renderer/gles.h +++ b/src/client/renderer/gles.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../../platform/log.h" -#include "../Options.h" +#include "platform/log.hpp" +#include "client/Options.hpp" // Android should always run OPENGL_ES #if defined(ANDROID) || defined(__APPLE__) || defined(RPI) diff --git a/src/client/renderer/ptexture/DynamicTexture.cpp b/src/client/renderer/ptexture/DynamicTexture.cpp index e3b7b47..5cce363 100755 --- a/src/client/renderer/ptexture/DynamicTexture.cpp +++ b/src/client/renderer/ptexture/DynamicTexture.cpp @@ -1,208 +1,208 @@ -#include "DynamicTexture.h" - -#include -#include "../Textures.h" -#include "../../../world/level/tile/Tile.h" -#include "../../../util/Mth.h" - -// -// DynamicTexture -// -DynamicTexture::DynamicTexture(int tex_) -: tex(tex_), - replicate(1) -{ - memset(pixels, 0, 16*16*4); -} - -void DynamicTexture::bindTexture(Textures* tex) { - tex->loadAndBindTexture("terrain.png"); -} - -// -// WaterTexture -// I was thinking of adding something simple (a simple frame copy from a -// "still water image sequence") every n:th tick for calm water, and shifting -// the rows of a texture for the running water. I might do that, but I got -// impressed over the java code, so I will try that first.. and I suspect they -// wont mix very good. -/* -WaterTexture::WaterTexture() -: super(Tile::water->tex), - _tick(0), - _frame(0) -{ -} - -void WaterTexture::tick() { -} -*/ - -WaterTexture::WaterTexture() -: super(Tile::water->tex), - _tick(0), - _frame(0) -{ - current = new float[16*16]; - next = new float[16*16]; - heat = new float[16*16]; - heata = new float[16*16]; - - for (int i = 0; i < 256; ++i) { - current[i] = 0; - next[i] = 0; - heat[i] = 0; - heata[i] = 0; - } -} - -WaterTexture::~WaterTexture() { - delete[] current; - delete[] next; - delete[] heat; - delete[] heata; -} - -void WaterTexture::tick() -{ - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) { - float pow = 0; - for (int xx = x - 1; xx <= x + 1; xx++) { - int xi = (xx) & 15; - int yi = (y) & 15; - pow += current[xi + yi * 16]; - } - next[x + y * 16] = pow / 3.3f + heat[x + y * 16] * 0.8f; - } - - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) { - heat[x + y * 16] += heata[x + y * 16] * 0.05f; - - if (heat[x + y * 16] < 0) heat[x + y * 16] = 0; - heata[x + y * 16] -= 0.1f; - if (Mth::random() < 0.05f) { - heata[x + y * 16] = 0.5f; - } - } - - float* tmp = next; - next = current; - current = tmp; - - for (int i = 0; i < 256; i++) { - float pow = current[i]; - if (pow > 1) pow = 1; - if (pow < 0) pow = 0; - - float pp = pow * pow; - - int r = (int) (32 + pp * 32); - int g = (int) (50 + pp * 64); - int b = (int) (255); - int a = (int) (146 + pp * 50); - - //if (anaglyph3d) { - // int rr = (r * 30 + g * 59 + b * 11) / 100; - // int gg = (r * 30 + g * 70) / (100); - // int bb = (r * 30 + b * 70) / (100); - - // r = rr; - // g = gg; - // b = bb; - //} - - pixels[i * 4 + 0] = r; - pixels[i * 4 + 1] = g; - pixels[i * 4 + 2] = b; - pixels[i * 4 + 3] = a; - } -} - -// -// WaterSideTexture -// -WaterSideTexture::WaterSideTexture() -: super(Tile::water->tex + 1), - _tick(0), - _frame(0), - _tickCount(0) -{ - replicate = 2; - - current = new float[16*16]; - next = new float[16*16]; - heat = new float[16*16]; - heata = new float[16*16]; - - for (int i = 0; i < 256; ++i) { - current[i] = 0; - next[i] = 0; - heat[i] = 0; - heata[i] = 0; - } -} - -WaterSideTexture::~WaterSideTexture() { - delete[] current; - delete[] next; - delete[] heat; - delete[] heata; -} - -void WaterSideTexture::tick() { - ++_tickCount; - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) { - float pow = 0; - for (int xx = y - 2; xx <= y; xx++) { - int xi = (x) & 15; - int yi = (xx) & 15; - pow += current[xi + yi * 16]; - } - next[x + y * 16] = pow / 3.2f + heat[x + y * 16] * 0.8f; - } - - for (int x = 0; x < 16; x++) - for (int y = 0; y < 16; y++) { - heat[x + y * 16] += heata[x + y * 16] * 0.05f; - - if (heat[x + y * 16] < 0) heat[x + y * 16] = 0; - heata[x + y * 16] -= 0.3f; - if (Mth::random() < 0.2) { - heata[x + y * 16] = 0.5f; - } - } - float* tmp = next; - next = current; - current = tmp; - - for (int i = 0; i < 256; i++) { - float pow = current[(i - _tickCount * 16) & 255]; - if (pow > 1) pow = 1; - if (pow < 0) pow = 0; - - float pp = pow * pow; - - int r = (int) (32 + pp * 32); - int g = (int) (50 + pp * 64); - int b = (int) (255); - int a = (int) (146 + pp * 50); - - //if (anaglyph3d) { - // int rr = (r * 30 + g * 59 + b * 11) / 100; - // int gg = (r * 30 + g * 70) / (100); - // int bb = (r * 30 + b * 70) / (100); - - // r = rr; - // g = gg; - // b = bb; - //} - - pixels[i * 4 + 0] = r; - pixels[i * 4 + 1] = g; - pixels[i * 4 + 2] = b; - pixels[i * 4 + 3] = a; - } -} +#include "DynamicTexture.hpp" + +#include +#include "client/renderer/Textures.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Mth.hpp" + +// +// DynamicTexture +// +DynamicTexture::DynamicTexture(int tex_) +: tex(tex_), + replicate(1) +{ + memset(pixels, 0, 16*16*4); +} + +void DynamicTexture::bindTexture(Textures* tex) { + tex->loadAndBindTexture("terrain.png"); +} + +// +// WaterTexture +// I was thinking of adding something simple (a simple frame copy from a +// "still water image sequence") every n:th tick for calm water, and shifting +// the rows of a texture for the running water. I might do that, but I got +// impressed over the java code, so I will try that first.. and I suspect they +// wont mix very good. +/* +WaterTexture::WaterTexture() +: super(Tile::water->tex), + _tick(0), + _frame(0) +{ +} + +void WaterTexture::tick() { +} +*/ + +WaterTexture::WaterTexture() +: super(Tile::water->tex), + _tick(0), + _frame(0) +{ + current = new float[16*16]; + next = new float[16*16]; + heat = new float[16*16]; + heata = new float[16*16]; + + for (int i = 0; i < 256; ++i) { + current[i] = 0; + next[i] = 0; + heat[i] = 0; + heata[i] = 0; + } +} + +WaterTexture::~WaterTexture() { + delete[] current; + delete[] next; + delete[] heat; + delete[] heata; +} + +void WaterTexture::tick() +{ + for (int x = 0; x < 16; x++) + for (int y = 0; y < 16; y++) { + float pow = 0; + for (int xx = x - 1; xx <= x + 1; xx++) { + int xi = (xx) & 15; + int yi = (y) & 15; + pow += current[xi + yi * 16]; + } + next[x + y * 16] = pow / 3.3f + heat[x + y * 16] * 0.8f; + } + + for (int x = 0; x < 16; x++) + for (int y = 0; y < 16; y++) { + heat[x + y * 16] += heata[x + y * 16] * 0.05f; + + if (heat[x + y * 16] < 0) heat[x + y * 16] = 0; + heata[x + y * 16] -= 0.1f; + if (Mth::random() < 0.05f) { + heata[x + y * 16] = 0.5f; + } + } + + float* tmp = next; + next = current; + current = tmp; + + for (int i = 0; i < 256; i++) { + float pow = current[i]; + if (pow > 1) pow = 1; + if (pow < 0) pow = 0; + + float pp = pow * pow; + + int r = (int) (32 + pp * 32); + int g = (int) (50 + pp * 64); + int b = (int) (255); + int a = (int) (146 + pp * 50); + + //if (anaglyph3d) { + // int rr = (r * 30 + g * 59 + b * 11) / 100; + // int gg = (r * 30 + g * 70) / (100); + // int bb = (r * 30 + b * 70) / (100); + + // r = rr; + // g = gg; + // b = bb; + //} + + pixels[i * 4 + 0] = r; + pixels[i * 4 + 1] = g; + pixels[i * 4 + 2] = b; + pixels[i * 4 + 3] = a; + } +} + +// +// WaterSideTexture +// +WaterSideTexture::WaterSideTexture() +: super(Tile::water->tex + 1), + _tick(0), + _frame(0), + _tickCount(0) +{ + replicate = 2; + + current = new float[16*16]; + next = new float[16*16]; + heat = new float[16*16]; + heata = new float[16*16]; + + for (int i = 0; i < 256; ++i) { + current[i] = 0; + next[i] = 0; + heat[i] = 0; + heata[i] = 0; + } +} + +WaterSideTexture::~WaterSideTexture() { + delete[] current; + delete[] next; + delete[] heat; + delete[] heata; +} + +void WaterSideTexture::tick() { + ++_tickCount; + for (int x = 0; x < 16; x++) + for (int y = 0; y < 16; y++) { + float pow = 0; + for (int xx = y - 2; xx <= y; xx++) { + int xi = (x) & 15; + int yi = (xx) & 15; + pow += current[xi + yi * 16]; + } + next[x + y * 16] = pow / 3.2f + heat[x + y * 16] * 0.8f; + } + + for (int x = 0; x < 16; x++) + for (int y = 0; y < 16; y++) { + heat[x + y * 16] += heata[x + y * 16] * 0.05f; + + if (heat[x + y * 16] < 0) heat[x + y * 16] = 0; + heata[x + y * 16] -= 0.3f; + if (Mth::random() < 0.2) { + heata[x + y * 16] = 0.5f; + } + } + float* tmp = next; + next = current; + current = tmp; + + for (int i = 0; i < 256; i++) { + float pow = current[(i - _tickCount * 16) & 255]; + if (pow > 1) pow = 1; + if (pow < 0) pow = 0; + + float pp = pow * pow; + + int r = (int) (32 + pp * 32); + int g = (int) (50 + pp * 64); + int b = (int) (255); + int a = (int) (146 + pp * 50); + + //if (anaglyph3d) { + // int rr = (r * 30 + g * 59 + b * 11) / 100; + // int gg = (r * 30 + g * 70) / (100); + // int bb = (r * 30 + b * 70) / (100); + + // r = rr; + // g = gg; + // b = bb; + //} + + pixels[i * 4 + 0] = r; + pixels[i * 4 + 1] = g; + pixels[i * 4 + 2] = b; + pixels[i * 4 + 3] = a; + } +} diff --git a/src/client/renderer/ptexture/DynamicTexture.h b/src/client/renderer/ptexture/DynamicTexture.hpp similarity index 100% rename from src/client/renderer/ptexture/DynamicTexture.h rename to src/client/renderer/ptexture/DynamicTexture.hpp diff --git a/src/client/renderer/tileentity/ChestRenderer.cpp b/src/client/renderer/tileentity/ChestRenderer.cpp index 5a5a58f..ef393e9 100755 --- a/src/client/renderer/tileentity/ChestRenderer.cpp +++ b/src/client/renderer/tileentity/ChestRenderer.cpp @@ -1,76 +1,76 @@ -#include "ChestRenderer.h" -#include "TileEntityRenderer.h" -#include "../gles.h" -#include "../../model/ChestModel.h" -#include "../../../world/level/tile/entity/ChestTileEntity.h" -#include "../../../world/level/tile/ChestTile.h" -#include "../../../util/Mth.h" - - -void ChestRenderer::render( TileEntity* entity, float x, float y, float z, float a ) -{ - ChestTileEntity* chest = (ChestTileEntity*) entity; - int data = 0; - - if (chest->level) { - Tile* tile = chest->getTile(); - data = chest->getData(); - - if (tile != NULL && data == 0) { - ((ChestTile*)tile)->recalcLockDir(chest->level, chest->x, chest->y, chest->z); - data = chest->getData(); - } - - chest->checkNeighbors(); - } - if (chest->n != NULL || chest->w != NULL) return; - - ChestModel* model; - //if (chest->e != NULL || chest->s != NULL) { - // //model = &largeChestModel; - // bindTexture("item/largechest.png"); - //} else - { - model = &chestModel; - bindTexture("item/chest.png"); - } - - glPushMatrix2(); - glColor4f2(1, 1, 1, 1); - glTranslatef2(x, y + 1, z + 1); - glScalef2(1, -1, -1); - - glTranslatef2(0.5f, 0.5f, 0.5f); - GLfloat rot = 0; - if (data == 2) rot = 180; - if (data == 3) rot = 0; - if (data == 4) rot = 90; - if (data == 5) rot = -90; - - if (data == 2 && chest->e != NULL) { - glTranslatef2(1, 0, 0); - } - if (data == 5 && chest->s != NULL) { - glTranslatef2(0, 0, -1); - } - glRotatef2(rot, 0, 1, 0); - glTranslatef2(-0.5f, -0.5f, -0.5f); - - float open = chest->oOpenness + (chest->openness - chest->oOpenness) * a; - if (chest->n != NULL) { - float open2 = chest->n->oOpenness + (chest->n->openness - chest->n->oOpenness) * a; - if (open2 > open) open = open2; - } - if (chest->w != NULL) { - float open2 = chest->w->oOpenness + (chest->w->openness - chest->w->oOpenness) * a; - if (open2 > open) open = open2; - } - - open = 1 - open; - open = 1 - open * open * open; - - model->lid.xRot = -(open * Mth::PI / 2); - model->render(); - glPopMatrix2(); - glColor4f2(1, 1, 1, 1); -} +#include "ChestRenderer.hpp" +#include "TileEntityRenderer.hpp" +#include "client/renderer/gles.hpp" +#include "client/model/ChestModel.hpp" +#include "world/level/tile/entity/ChestTileEntity.hpp" +#include "world/level/tile/ChestTile.hpp" +#include "util/Mth.hpp" + + +void ChestRenderer::render( TileEntity* entity, float x, float y, float z, float a ) +{ + ChestTileEntity* chest = (ChestTileEntity*) entity; + int data = 0; + + if (chest->level) { + Tile* tile = chest->getTile(); + data = chest->getData(); + + if (tile != NULL && data == 0) { + ((ChestTile*)tile)->recalcLockDir(chest->level, chest->x, chest->y, chest->z); + data = chest->getData(); + } + + chest->checkNeighbors(); + } + if (chest->n != NULL || chest->w != NULL) return; + + ChestModel* model; + //if (chest->e != NULL || chest->s != NULL) { + // //model = &largeChestModel; + // bindTexture("item/largechest.png"); + //} else + { + model = &chestModel; + bindTexture("item/chest.png"); + } + + glPushMatrix2(); + glColor4f2(1, 1, 1, 1); + glTranslatef2(x, y + 1, z + 1); + glScalef2(1, -1, -1); + + glTranslatef2(0.5f, 0.5f, 0.5f); + GLfloat rot = 0; + if (data == 2) rot = 180; + if (data == 3) rot = 0; + if (data == 4) rot = 90; + if (data == 5) rot = -90; + + if (data == 2 && chest->e != NULL) { + glTranslatef2(1, 0, 0); + } + if (data == 5 && chest->s != NULL) { + glTranslatef2(0, 0, -1); + } + glRotatef2(rot, 0, 1, 0); + glTranslatef2(-0.5f, -0.5f, -0.5f); + + float open = chest->oOpenness + (chest->openness - chest->oOpenness) * a; + if (chest->n != NULL) { + float open2 = chest->n->oOpenness + (chest->n->openness - chest->n->oOpenness) * a; + if (open2 > open) open = open2; + } + if (chest->w != NULL) { + float open2 = chest->w->oOpenness + (chest->w->openness - chest->w->oOpenness) * a; + if (open2 > open) open = open2; + } + + open = 1 - open; + open = 1 - open * open * open; + + model->lid.xRot = -(open * Mth::PI / 2); + model->render(); + glPopMatrix2(); + glColor4f2(1, 1, 1, 1); +} diff --git a/src/client/renderer/tileentity/ChestRenderer.h b/src/client/renderer/tileentity/ChestRenderer.hpp similarity index 81% rename from src/client/renderer/tileentity/ChestRenderer.h rename to src/client/renderer/tileentity/ChestRenderer.hpp index f133ef0..25bbc23 100755 --- a/src/client/renderer/tileentity/ChestRenderer.h +++ b/src/client/renderer/tileentity/ChestRenderer.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.renderer.tileentity; -#include "TileEntityRenderer.h" -#include "../../model/ChestModel.h" +#include "TileEntityRenderer.hpp" +#include "client/model/ChestModel.hpp" class ChestTileEntity; diff --git a/src/client/renderer/tileentity/SignRenderer.cpp b/src/client/renderer/tileentity/SignRenderer.cpp index 0bd5d4c..9194448 100755 --- a/src/client/renderer/tileentity/SignRenderer.cpp +++ b/src/client/renderer/tileentity/SignRenderer.cpp @@ -1,65 +1,65 @@ -#include "SignRenderer.h" -#include "../../../world/level/tile/Tile.h" -#include "../../../world/level/tile/entity/SignTileEntity.h" - -void SignRenderer::render( TileEntity* te, float x, float y, float z, float a ) -{ - SignTileEntity* sign = (SignTileEntity*) te; - Tile* tile = sign->getTile(); - - glPushMatrix(); - float size = 16 / 24.0f; - if (tile == Tile::sign) { - glTranslatef(x + 0.5f, y + 0.75f * size, z + 0.5f); - float rot = sign->getData() * 360 / 16.0f; - glRotatef(-rot, 0, 1, 0); - signModel.cube2.visible = true; - } else { - int face = sign->getData(); - float rot = 0; - - if (face == 2) rot = 180; - if (face == 4) rot = 90; - if (face == 5) rot = -90; - - glTranslatef(x + 0.5f, y + 0.75f * size, z + 0.5f); - glRotatef(-rot, 0, 1, 0); - glTranslatef(0, -5 / 16.0f, -7 / 16.0f); - - signModel.cube2.visible = false; - } - - bindTexture("item/sign.png"); - - glPushMatrix(); - glScalef(size, -size, -size); - signModel.render(); - glPopMatrix(); - Font* font = getFont(); - - float s = 1 / 60.0f * size; - glTranslatef(0, 0.5f * size, 0.07f * size); - glScalef(s, -s, s); - glNormal3f(0, 0, -1 * s); - glDepthMask(false); - - int col = 0; - float yy = (float)(SignTileEntity::NUM_LINES * -5); - for (int i = 0; i < SignTileEntity::NUM_LINES; i++) { - std::string& msg = sign->messages[i]; - if (i == sign->selectedLine) { - std::string s = "> " + msg + " <"; - font->draw(s, (float)-font->width(s) / 2, yy, col); - } else { - font->draw(msg, (float)-font->width(msg) / 2, yy, col); - } - yy += 10; - } - glDepthMask(true); - glColor4f(1, 1, 1, 1); - glPopMatrix(); -} - -void SignRenderer::onGraphicsReset() { - signModel.onGraphicsReset(); -} +#include "SignRenderer.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/entity/SignTileEntity.hpp" + +void SignRenderer::render( TileEntity* te, float x, float y, float z, float a ) +{ + SignTileEntity* sign = (SignTileEntity*) te; + Tile* tile = sign->getTile(); + + glPushMatrix(); + float size = 16 / 24.0f; + if (tile == Tile::sign) { + glTranslatef(x + 0.5f, y + 0.75f * size, z + 0.5f); + float rot = sign->getData() * 360 / 16.0f; + glRotatef(-rot, 0, 1, 0); + signModel.cube2.visible = true; + } else { + int face = sign->getData(); + float rot = 0; + + if (face == 2) rot = 180; + if (face == 4) rot = 90; + if (face == 5) rot = -90; + + glTranslatef(x + 0.5f, y + 0.75f * size, z + 0.5f); + glRotatef(-rot, 0, 1, 0); + glTranslatef(0, -5 / 16.0f, -7 / 16.0f); + + signModel.cube2.visible = false; + } + + bindTexture("item/sign.png"); + + glPushMatrix(); + glScalef(size, -size, -size); + signModel.render(); + glPopMatrix(); + Font* font = getFont(); + + float s = 1 / 60.0f * size; + glTranslatef(0, 0.5f * size, 0.07f * size); + glScalef(s, -s, s); + glNormal3f(0, 0, -1 * s); + glDepthMask(false); + + int col = 0; + float yy = (float)(SignTileEntity::NUM_LINES * -5); + for (int i = 0; i < SignTileEntity::NUM_LINES; i++) { + std::string& msg = sign->messages[i]; + if (i == sign->selectedLine) { + std::string s = "> " + msg + " <"; + font->draw(s, (float)-font->width(s) / 2, yy, col); + } else { + font->draw(msg, (float)-font->width(msg) / 2, yy, col); + } + yy += 10; + } + glDepthMask(true); + glColor4f(1, 1, 1, 1); + glPopMatrix(); +} + +void SignRenderer::onGraphicsReset() { + signModel.onGraphicsReset(); +} diff --git a/src/client/renderer/tileentity/SignRenderer.h b/src/client/renderer/tileentity/SignRenderer.hpp similarity index 72% rename from src/client/renderer/tileentity/SignRenderer.h rename to src/client/renderer/tileentity/SignRenderer.hpp index ba9b136..25cccac 100755 --- a/src/client/renderer/tileentity/SignRenderer.h +++ b/src/client/renderer/tileentity/SignRenderer.hpp @@ -2,10 +2,10 @@ //package net.minecraft.client.renderer.tileentity; -#include "TileEntityRenderer.h" +#include "TileEntityRenderer.hpp" -#include "../../gui/Font.h" -#include "../../model/SignModel.h" +#include "client/gui/Font.hpp" +#include "client/model/SignModel.hpp" class SignRenderer: public TileEntityRenderer { diff --git a/src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp b/src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp index 9b1f82d..3d07794 100755 --- a/src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp +++ b/src/client/renderer/tileentity/TileEntityRenderDispatcher.cpp @@ -1,136 +1,136 @@ -#include "TileEntityRenderDispatcher.h" -#include "ChestRenderer.h" -#include "../Textures.h" -#include "../../gui/Font.h" -#include "../../../SharedConstants.h" -#include "../../../world/entity/Mob.h" -#include "../../../world/level/Level.h" -#include "../../../world/level/tile/entity/TileEntity.h" -#include "SignRenderer.h" - -/*static*/ -TileEntityRenderDispatcher* TileEntityRenderDispatcher::instance = 0; -/*static*/ -float TileEntityRenderDispatcher::xOff = 0, - TileEntityRenderDispatcher::yOff = 0, - TileEntityRenderDispatcher::zOff = 0; - -TileEntityRenderDispatcher* TileEntityRenderDispatcher::getInstance() -{ - if (!instance) instance = new TileEntityRenderDispatcher(); - return instance; -} - -TileEntityRenderDispatcher::~TileEntityRenderDispatcher() -{ - std::set destroyed; - for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) { - if (destroyed.find(cit->second) == destroyed.end()) { - destroyed.insert(cit->second); - delete cit->second; - } - } -} - -void TileEntityRenderDispatcher::destroy() -{ - if (instance) { - delete instance; - instance = NULL; - } -} - -void TileEntityRenderDispatcher::prepare( Level* level, Textures* textures, Font* font, Mob* player, float a ) -{ - if (this->level != level) - setLevel(level); - - this->textures = textures; - this->cameraEntity = player; - this->_font = font; - - playerRotY = player->yRotO + (player->yRot - player->yRotO) * a; - playerRotX = player->xRotO + (player->xRot - player->xRotO) * a; - - xPlayer = player->xOld + (player->x - player->xOld) * a; - yPlayer = player->yOld + (player->y - player->yOld) * a; - zPlayer = player->zOld + (player->z - player->zOld) * a; - - // xPlayer -= xPlayerOffs; - // yPlayer -= yPlayerOffs; - // zPlayer -= zPlayerOffs; -} - -void TileEntityRenderDispatcher::render( TileEntity* e, float a ) -{ - if (e->distanceToSqr(xPlayer, yPlayer, zPlayer) < 64 * 64) { - float br = level->getBrightness(e->x, e->y, e->z); - glColor4f(br, br, br, 1); - render(e, e->x - xOff, e->y - yOff, e->z - zOff, a); - } -} - -void TileEntityRenderDispatcher::render( TileEntity* entity, float x, float y, float z, float a ) -{ - TileEntityRenderer* renderer = getRenderer(entity); - if (renderer != NULL) { - renderer->render(entity, x, y, z, a); - } -} - -void TileEntityRenderDispatcher::setLevel( Level* level ) -{ - this->level = level; - - for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) - if (cit->second != NULL) - cit->second->onNewLevel(level); -} - -float TileEntityRenderDispatcher::distanceToSqr( float x, float y, float z ) -{ - float xd = x - xPlayer; - float yd = y - yPlayer; - float zd = z - zPlayer; - return xd * xd + yd * yd + zd * zd; -} - -Font* TileEntityRenderDispatcher::getFont() -{ - return _font; -} - -TileEntityRenderer* TileEntityRenderDispatcher::getRenderer( TileEntity* entity ) -{ - TileEntityRendererId rendererId = entity->rendererId; - - //if (rendererId == TR_QUERY_RENDERER) - // rendererId = entity->queryEntityRenderer(); - - return getRenderer(rendererId); -} - -TileEntityRenderer* TileEntityRenderDispatcher::getRenderer( TileEntityRendererId rendererId ) -{ - TileEntityRenderer* renderer = NULL; - RendererCIterator cit = _renderers.find(rendererId); - if (cit != _renderers.end()) { - renderer = cit->second; - } - return renderer; -} - -TileEntityRenderDispatcher::TileEntityRenderDispatcher() -{ - _renderers.insert(std::make_pair(TR_CHEST_RENDERER, new ChestRenderer())); - _renderers.insert(std::make_pair(TR_SIGN_RENDERER, new SignRenderer())); - - for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) - cit->second->init(this); -} - -void TileEntityRenderDispatcher::onGraphicsReset() { - for (RendererIterator it = _renderers.begin(); it != _renderers.end(); ++it) { - it->second->onGraphicsReset(); - } -} +#include "TileEntityRenderDispatcher.hpp" +#include "ChestRenderer.hpp" +#include "client/renderer/Textures.hpp" +#include "client/gui/Font.hpp" +#include "SharedConstants.hpp" +#include "world/entity/Mob.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/entity/TileEntity.hpp" +#include "SignRenderer.hpp" + +/*static*/ +TileEntityRenderDispatcher* TileEntityRenderDispatcher::instance = 0; +/*static*/ +float TileEntityRenderDispatcher::xOff = 0, + TileEntityRenderDispatcher::yOff = 0, + TileEntityRenderDispatcher::zOff = 0; + +TileEntityRenderDispatcher* TileEntityRenderDispatcher::getInstance() +{ + if (!instance) instance = new TileEntityRenderDispatcher(); + return instance; +} + +TileEntityRenderDispatcher::~TileEntityRenderDispatcher() +{ + std::set destroyed; + for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) { + if (destroyed.find(cit->second) == destroyed.end()) { + destroyed.insert(cit->second); + delete cit->second; + } + } +} + +void TileEntityRenderDispatcher::destroy() +{ + if (instance) { + delete instance; + instance = NULL; + } +} + +void TileEntityRenderDispatcher::prepare( Level* level, Textures* textures, Font* font, Mob* player, float a ) +{ + if (this->level != level) + setLevel(level); + + this->textures = textures; + this->cameraEntity = player; + this->_font = font; + + playerRotY = player->yRotO + (player->yRot - player->yRotO) * a; + playerRotX = player->xRotO + (player->xRot - player->xRotO) * a; + + xPlayer = player->xOld + (player->x - player->xOld) * a; + yPlayer = player->yOld + (player->y - player->yOld) * a; + zPlayer = player->zOld + (player->z - player->zOld) * a; + + // xPlayer -= xPlayerOffs; + // yPlayer -= yPlayerOffs; + // zPlayer -= zPlayerOffs; +} + +void TileEntityRenderDispatcher::render( TileEntity* e, float a ) +{ + if (e->distanceToSqr(xPlayer, yPlayer, zPlayer) < 64 * 64) { + float br = level->getBrightness(e->x, e->y, e->z); + glColor4f(br, br, br, 1); + render(e, e->x - xOff, e->y - yOff, e->z - zOff, a); + } +} + +void TileEntityRenderDispatcher::render( TileEntity* entity, float x, float y, float z, float a ) +{ + TileEntityRenderer* renderer = getRenderer(entity); + if (renderer != NULL) { + renderer->render(entity, x, y, z, a); + } +} + +void TileEntityRenderDispatcher::setLevel( Level* level ) +{ + this->level = level; + + for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) + if (cit->second != NULL) + cit->second->onNewLevel(level); +} + +float TileEntityRenderDispatcher::distanceToSqr( float x, float y, float z ) +{ + float xd = x - xPlayer; + float yd = y - yPlayer; + float zd = z - zPlayer; + return xd * xd + yd * yd + zd * zd; +} + +Font* TileEntityRenderDispatcher::getFont() +{ + return _font; +} + +TileEntityRenderer* TileEntityRenderDispatcher::getRenderer( TileEntity* entity ) +{ + TileEntityRendererId rendererId = entity->rendererId; + + //if (rendererId == TR_QUERY_RENDERER) + // rendererId = entity->queryEntityRenderer(); + + return getRenderer(rendererId); +} + +TileEntityRenderer* TileEntityRenderDispatcher::getRenderer( TileEntityRendererId rendererId ) +{ + TileEntityRenderer* renderer = NULL; + RendererCIterator cit = _renderers.find(rendererId); + if (cit != _renderers.end()) { + renderer = cit->second; + } + return renderer; +} + +TileEntityRenderDispatcher::TileEntityRenderDispatcher() +{ + _renderers.insert(std::make_pair(TR_CHEST_RENDERER, new ChestRenderer())); + _renderers.insert(std::make_pair(TR_SIGN_RENDERER, new SignRenderer())); + + for (RendererCIterator cit = _renderers.begin(); cit != _renderers.end(); ++cit) + cit->second->init(this); +} + +void TileEntityRenderDispatcher::onGraphicsReset() { + for (RendererIterator it = _renderers.begin(); it != _renderers.end(); ++it) { + it->second->onGraphicsReset(); + } +} diff --git a/src/client/renderer/tileentity/TileEntityRenderDispatcher.h b/src/client/renderer/tileentity/TileEntityRenderDispatcher.hpp similarity index 95% rename from src/client/renderer/tileentity/TileEntityRenderDispatcher.h rename to src/client/renderer/tileentity/TileEntityRenderDispatcher.hpp index b040731..a10b2ee 100755 --- a/src/client/renderer/tileentity/TileEntityRenderDispatcher.h +++ b/src/client/renderer/tileentity/TileEntityRenderDispatcher.hpp @@ -3,7 +3,7 @@ //package net.minecraft.client.renderer.tileentity; #include -#include "../../../world/level/tile/entity/TileEntityRendererId.h" +#include "world/level/tile/entity/TileEntityRendererId.hpp" class TileEntityRenderer; class Level; diff --git a/src/client/renderer/tileentity/TileEntityRenderer.cpp b/src/client/renderer/tileentity/TileEntityRenderer.cpp index 042a3e3..0553ff9 100755 --- a/src/client/renderer/tileentity/TileEntityRenderer.cpp +++ b/src/client/renderer/tileentity/TileEntityRenderer.cpp @@ -1,32 +1,32 @@ -#include "TileEntityRenderer.h" -#include "TileEntityRenderDispatcher.h" -#include "../Textures.h" -#include "../../gui/Font.h" -#include "../../../world/level/Level.h" -#include "../../../world/level/tile/entity/TileEntity.h" - -TileEntityRenderer::TileEntityRenderer() -: tileEntityRenderDispatcher(NULL) -{ -} - -void TileEntityRenderer::bindTexture( const std::string& resourceName ) -{ - Textures* t = tileEntityRenderDispatcher->textures; - if (t != NULL) t->loadAndBindTexture(resourceName); -} - -Level* TileEntityRenderer::getLevel() -{ - return tileEntityRenderDispatcher->level; -} - -void TileEntityRenderer::init( TileEntityRenderDispatcher* tileEntityRenderDispatcher ) -{ - this->tileEntityRenderDispatcher = tileEntityRenderDispatcher; -} - -Font* TileEntityRenderer::getFont() -{ - return tileEntityRenderDispatcher->getFont(); -} +#include "TileEntityRenderer.hpp" +#include "TileEntityRenderDispatcher.hpp" +#include "client/renderer/Textures.hpp" +#include "client/gui/Font.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/entity/TileEntity.hpp" + +TileEntityRenderer::TileEntityRenderer() +: tileEntityRenderDispatcher(NULL) +{ +} + +void TileEntityRenderer::bindTexture( const std::string& resourceName ) +{ + Textures* t = tileEntityRenderDispatcher->textures; + if (t != NULL) t->loadAndBindTexture(resourceName); +} + +Level* TileEntityRenderer::getLevel() +{ + return tileEntityRenderDispatcher->level; +} + +void TileEntityRenderer::init( TileEntityRenderDispatcher* tileEntityRenderDispatcher ) +{ + this->tileEntityRenderDispatcher = tileEntityRenderDispatcher; +} + +Font* TileEntityRenderer::getFont() +{ + return tileEntityRenderDispatcher->getFont(); +} diff --git a/src/client/renderer/tileentity/TileEntityRenderer.h b/src/client/renderer/tileentity/TileEntityRenderer.hpp similarity index 100% rename from src/client/renderer/tileentity/TileEntityRenderer.h rename to src/client/renderer/tileentity/TileEntityRenderer.hpp diff --git a/src/client/sound/Sound.cpp b/src/client/sound/Sound.cpp index ff5442a..d60479a 100755 --- a/src/client/sound/Sound.cpp +++ b/src/client/sound/Sound.cpp @@ -1,226 +1,226 @@ -#include "Sound.h" - -#if !defined(PRE_ANDROID23) && !defined(__APPLE__) && !defined(RPI) - -#include "data/cloth1.pcm" -#include "data/cloth2.pcm" -#include "data/cloth3.pcm" -#include "data/cloth4.pcm" -#include "data/grass1.pcm" -#include "data/grass2.pcm" -#include "data/grass3.pcm" -#include "data/grass4.pcm" -#include "data/gravel1.pcm" -#include "data/gravel2.pcm" -#include "data/gravel3.pcm" -#include "data/gravel4.pcm" -#include "data/sand1.pcm" -#include "data/sand2.pcm" -#include "data/sand3.pcm" -#include "data/sand4.pcm" -#include "data/stone1.pcm" -#include "data/stone2.pcm" -#include "data/stone3.pcm" -#include "data/stone4.pcm" -#include "data/wood1.pcm" -#include "data/wood2.pcm" -#include "data/wood3.pcm" -#include "data/wood4.pcm" - -#include "data/click.pcm" -#include "data/explode.pcm" -#include "data/splash.pcm" -#include "data/pop.pcm" -#include "data/pop2.pcm" -#include "data/hurt.pcm" -#include "data/door_open.pcm" -#include "data/door_close.pcm" -#include "data/glass1.pcm" -#include "data/glass2.pcm" -#include "data/glass3.pcm" - -#include "data/sheep1.pcm" -#include "data/sheep2.pcm" -#include "data/sheep3.pcm" - -#include "data/pig1.pcm" -#include "data/pig2.pcm" -#include "data/pig3.pcm" -#include "data/pigdeath.pcm" - -//#include "data/chicken1.pcm" -#include "data/chicken2.pcm" -#include "data/chicken3.pcm" -#include "data/chickenhurt1.pcm" -#include "data/chickenhurt2.pcm" - -#include "data/cow1.pcm" -#include "data/cow2.pcm" -#include "data/cow3.pcm" -#include "data/cow4.pcm" -#include "data/cowhurt1.pcm" -#include "data/cowhurt2.pcm" -#include "data/cowhurt3.pcm" - -#include "data/zombie1.pcm" -#include "data/zombie2.pcm" -#include "data/zombie3.pcm" -#include "data/zombiedeath.pcm" -#include "data/zombiehurt1.pcm" -#include "data/zombiehurt2.pcm" - -#include "data/zpig1.pcm" -#include "data/zpig2.pcm" -#include "data/zpig3.pcm" -#include "data/zpig4.pcm" -#include "data/zpigangry1.pcm" -#include "data/zpigangry2.pcm" -#include "data/zpigangry3.pcm" -#include "data/zpigangry4.pcm" -#include "data/zpigdeath.pcm" -#include "data/zpighurt1.pcm" -#include "data/zpighurt2.pcm" - -#include "data/bow.pcm" -#include "data/bowhit1.pcm" -#include "data/bowhit2.pcm" -#include "data/bowhit3.pcm" -#include "data/bowhit4.pcm" -#include "data/fallbig1.pcm" -#include "data/fallbig2.pcm" -#include "data/fallsmall.pcm" -#include "data/skeleton1.pcm" -#include "data/skeleton2.pcm" -#include "data/skeleton3.pcm" -#include "data/skeletondeath.pcm" -#include "data/skeletonhurt1.pcm" -#include "data/skeletonhurt2.pcm" -#include "data/skeletonhurt3.pcm" -#include "data/skeletonhurt4.pcm" -#include "data/spider1.pcm" -#include "data/spider2.pcm" -#include "data/spider3.pcm" -#include "data/spider4.pcm" -#include "data/spiderdeath.pcm" - -#include "data/creeper1.pcm" -#include "data/creeper2.pcm" -#include "data/creeper3.pcm" -#include "data/creeper4.pcm" -#include "data/creeperdeath.pcm" -#include "data/eat1.pcm" -#include "data/eat2.pcm" -#include "data/eat3.pcm" -#include "data/fuse.pcm" - -SoundDesc SA_cloth1((char*)PCM_cloth1); -SoundDesc SA_cloth2((char*)PCM_cloth2); -SoundDesc SA_cloth3((char*)PCM_cloth3); -SoundDesc SA_cloth4((char*)PCM_cloth4); -SoundDesc SA_grass1((char*)PCM_grass1); -SoundDesc SA_grass2((char*)PCM_grass2); -SoundDesc SA_grass3((char*)PCM_grass3); -SoundDesc SA_grass4((char*)PCM_grass4); -SoundDesc SA_gravel1((char*)PCM_gravel1); -SoundDesc SA_gravel2((char*)PCM_gravel2); -SoundDesc SA_gravel3((char*)PCM_gravel3); -SoundDesc SA_gravel4((char*)PCM_gravel4); -SoundDesc SA_sand1((char*)PCM_sand1); -SoundDesc SA_sand2((char*)PCM_sand2); -SoundDesc SA_sand3((char*)PCM_sand3); -SoundDesc SA_sand4((char*)PCM_sand4); -SoundDesc SA_stone1((char*)PCM_stone1); -SoundDesc SA_stone2((char*)PCM_stone2); -SoundDesc SA_stone3((char*)PCM_stone3); -SoundDesc SA_stone4((char*)PCM_stone4); -SoundDesc SA_wood1((char*)PCM_wood1); -SoundDesc SA_wood2((char*)PCM_wood2); -SoundDesc SA_wood3((char*)PCM_wood3); -SoundDesc SA_wood4((char*)PCM_wood4); - -SoundDesc SA_click((char*)PCM_click); -SoundDesc SA_explode((char*)PCM_explode); -SoundDesc SA_splash((char*)PCM_splash); - -SoundDesc SA_door_open((char*)PCM_door_open); -SoundDesc SA_door_close((char*)PCM_door_close); -SoundDesc SA_pop((char*)PCM_pop); -SoundDesc SA_hurt((char*)PCM_hurt); -SoundDesc SA_glass1((char*)PCM_glass1); -SoundDesc SA_glass2((char*)PCM_glass2); -SoundDesc SA_glass3((char*)PCM_glass3); - -SoundDesc SA_sheep1((char*)PCM_sheep1); -SoundDesc SA_sheep2((char*)PCM_sheep2); -SoundDesc SA_sheep3((char*)PCM_sheep3); -SoundDesc SA_pig1((char*)PCM_pig1); -SoundDesc SA_pig2((char*)PCM_pig2); -SoundDesc SA_pig3((char*)PCM_pig3); -SoundDesc SA_pigdeath((char*)PCM_pigdeath); - -//SoundDesc SA_chicken1((char*)PCM_chicken1); -SoundDesc SA_chicken2((char*)PCM_chicken2); -SoundDesc SA_chicken3((char*)PCM_chicken3); -SoundDesc SA_chickenhurt1((char*)PCM_chickenhurt1); -SoundDesc SA_chickenhurt2((char*)PCM_chickenhurt2); -SoundDesc SA_cow1((char*)PCM_cow1); -SoundDesc SA_cow2((char*)PCM_cow2); -SoundDesc SA_cow3((char*)PCM_cow3); -SoundDesc SA_cow4((char*)PCM_cow4); -SoundDesc SA_cowhurt1((char*)PCM_cowhurt1); -SoundDesc SA_cowhurt2((char*)PCM_cowhurt2); -SoundDesc SA_cowhurt3((char*)PCM_cowhurt3); - -SoundDesc SA_zombie1((char*)PCM_zombie1); -SoundDesc SA_zombie2((char*)PCM_zombie2); -SoundDesc SA_zombie3((char*)PCM_zombie3); - -SoundDesc SA_zpig1((char*)PCM_zpig1); -SoundDesc SA_zpig2((char*)PCM_zpig2); -SoundDesc SA_zpig3((char*)PCM_zpig3); -SoundDesc SA_zpig4((char*)PCM_zpig4); -SoundDesc SA_zpigangry1((char*)PCM_zpigangry1); -SoundDesc SA_zpigangry2((char*)PCM_zpigangry2); -SoundDesc SA_zpigangry3((char*)PCM_zpigangry3); -SoundDesc SA_zpigangry4((char*)PCM_zpigangry4); -SoundDesc SA_zpigdeath((char*)PCM_zpigdeath); -SoundDesc SA_zpighurt1((char*)PCM_zpighurt1); -SoundDesc SA_zpighurt2((char*)PCM_zpighurt2); - -SoundDesc SA_zombiedeath((char*)PCM_zombiedeath); -SoundDesc SA_zombiehurt1((char*)PCM_zombiehurt1); -SoundDesc SA_zombiehurt2((char*)PCM_zombiehurt2); - -SoundDesc SA_bow((char*)PCM_bow); -SoundDesc SA_bowhit1((char*)PCM_bowhit1); -SoundDesc SA_bowhit2((char*)PCM_bowhit2); -SoundDesc SA_bowhit3((char*)PCM_bowhit3); -SoundDesc SA_bowhit4((char*)PCM_bowhit4); -SoundDesc SA_fallbig1((char*)PCM_fallbig1); -SoundDesc SA_fallbig2((char*)PCM_fallbig2); -SoundDesc SA_fallsmall((char*)PCM_fallsmall); -SoundDesc SA_skeleton1((char*)PCM_skeleton1); -SoundDesc SA_skeleton2((char*)PCM_skeleton2); -SoundDesc SA_skeleton3((char*)PCM_skeleton3); -SoundDesc SA_skeletondeath((char*)PCM_skeletondeath); -SoundDesc SA_skeletonhurt1((char*)PCM_skeletonhurt1); -SoundDesc SA_skeletonhurt2((char*)PCM_skeletonhurt2); -SoundDesc SA_skeletonhurt3((char*)PCM_skeletonhurt3); -SoundDesc SA_skeletonhurt4((char*)PCM_skeletonhurt4); -SoundDesc SA_spider1((char*)PCM_spider1); -SoundDesc SA_spider2((char*)PCM_spider2); -SoundDesc SA_spider3((char*)PCM_spider3); -SoundDesc SA_spider4((char*)PCM_spider4); -SoundDesc SA_spiderdeath((char*)PCM_spiderdeath); - -SoundDesc SA_creeper1((char*)PCM_creeper1); -SoundDesc SA_creeper2((char*)PCM_creeper2); -SoundDesc SA_creeper3((char*)PCM_creeper3); -SoundDesc SA_creeper4((char*)PCM_creeper4); -SoundDesc SA_creeperdeath((char*)PCM_creeperdeath); -SoundDesc SA_eat1((char*)PCM_eat1); -SoundDesc SA_eat2((char*)PCM_eat2); -SoundDesc SA_eat3((char*)PCM_eat3); -SoundDesc SA_fuse((char*)PCM_fuse); - -#endif /*!PRE_ANDROID23 && !__APPLE__*/ +#include "Sound.hpp" + +#if !defined(PRE_ANDROID23) && !defined(__APPLE__) && !defined(RPI) + +#include "data/cloth1.pcm" +#include "data/cloth2.pcm" +#include "data/cloth3.pcm" +#include "data/cloth4.pcm" +#include "data/grass1.pcm" +#include "data/grass2.pcm" +#include "data/grass3.pcm" +#include "data/grass4.pcm" +#include "data/gravel1.pcm" +#include "data/gravel2.pcm" +#include "data/gravel3.pcm" +#include "data/gravel4.pcm" +#include "data/sand1.pcm" +#include "data/sand2.pcm" +#include "data/sand3.pcm" +#include "data/sand4.pcm" +#include "data/stone1.pcm" +#include "data/stone2.pcm" +#include "data/stone3.pcm" +#include "data/stone4.pcm" +#include "data/wood1.pcm" +#include "data/wood2.pcm" +#include "data/wood3.pcm" +#include "data/wood4.pcm" + +#include "data/click.pcm" +#include "data/explode.pcm" +#include "data/splash.pcm" +#include "data/pop.pcm" +#include "data/pop2.pcm" +#include "data/hurt.pcm" +#include "data/door_open.pcm" +#include "data/door_close.pcm" +#include "data/glass1.pcm" +#include "data/glass2.pcm" +#include "data/glass3.pcm" + +#include "data/sheep1.pcm" +#include "data/sheep2.pcm" +#include "data/sheep3.pcm" + +#include "data/pig1.pcm" +#include "data/pig2.pcm" +#include "data/pig3.pcm" +#include "data/pigdeath.pcm" + +//#include "data/chicken1.pcm" +#include "data/chicken2.pcm" +#include "data/chicken3.pcm" +#include "data/chickenhurt1.pcm" +#include "data/chickenhurt2.pcm" + +#include "data/cow1.pcm" +#include "data/cow2.pcm" +#include "data/cow3.pcm" +#include "data/cow4.pcm" +#include "data/cowhurt1.pcm" +#include "data/cowhurt2.pcm" +#include "data/cowhurt3.pcm" + +#include "data/zombie1.pcm" +#include "data/zombie2.pcm" +#include "data/zombie3.pcm" +#include "data/zombiedeath.pcm" +#include "data/zombiehurt1.pcm" +#include "data/zombiehurt2.pcm" + +#include "data/zpig1.pcm" +#include "data/zpig2.pcm" +#include "data/zpig3.pcm" +#include "data/zpig4.pcm" +#include "data/zpigangry1.pcm" +#include "data/zpigangry2.pcm" +#include "data/zpigangry3.pcm" +#include "data/zpigangry4.pcm" +#include "data/zpigdeath.pcm" +#include "data/zpighurt1.pcm" +#include "data/zpighurt2.pcm" + +#include "data/bow.pcm" +#include "data/bowhit1.pcm" +#include "data/bowhit2.pcm" +#include "data/bowhit3.pcm" +#include "data/bowhit4.pcm" +#include "data/fallbig1.pcm" +#include "data/fallbig2.pcm" +#include "data/fallsmall.pcm" +#include "data/skeleton1.pcm" +#include "data/skeleton2.pcm" +#include "data/skeleton3.pcm" +#include "data/skeletondeath.pcm" +#include "data/skeletonhurt1.pcm" +#include "data/skeletonhurt2.pcm" +#include "data/skeletonhurt3.pcm" +#include "data/skeletonhurt4.pcm" +#include "data/spider1.pcm" +#include "data/spider2.pcm" +#include "data/spider3.pcm" +#include "data/spider4.pcm" +#include "data/spiderdeath.pcm" + +#include "data/creeper1.pcm" +#include "data/creeper2.pcm" +#include "data/creeper3.pcm" +#include "data/creeper4.pcm" +#include "data/creeperdeath.pcm" +#include "data/eat1.pcm" +#include "data/eat2.pcm" +#include "data/eat3.pcm" +#include "data/fuse.pcm" + +SoundDesc SA_cloth1((char*)PCM_cloth1); +SoundDesc SA_cloth2((char*)PCM_cloth2); +SoundDesc SA_cloth3((char*)PCM_cloth3); +SoundDesc SA_cloth4((char*)PCM_cloth4); +SoundDesc SA_grass1((char*)PCM_grass1); +SoundDesc SA_grass2((char*)PCM_grass2); +SoundDesc SA_grass3((char*)PCM_grass3); +SoundDesc SA_grass4((char*)PCM_grass4); +SoundDesc SA_gravel1((char*)PCM_gravel1); +SoundDesc SA_gravel2((char*)PCM_gravel2); +SoundDesc SA_gravel3((char*)PCM_gravel3); +SoundDesc SA_gravel4((char*)PCM_gravel4); +SoundDesc SA_sand1((char*)PCM_sand1); +SoundDesc SA_sand2((char*)PCM_sand2); +SoundDesc SA_sand3((char*)PCM_sand3); +SoundDesc SA_sand4((char*)PCM_sand4); +SoundDesc SA_stone1((char*)PCM_stone1); +SoundDesc SA_stone2((char*)PCM_stone2); +SoundDesc SA_stone3((char*)PCM_stone3); +SoundDesc SA_stone4((char*)PCM_stone4); +SoundDesc SA_wood1((char*)PCM_wood1); +SoundDesc SA_wood2((char*)PCM_wood2); +SoundDesc SA_wood3((char*)PCM_wood3); +SoundDesc SA_wood4((char*)PCM_wood4); + +SoundDesc SA_click((char*)PCM_click); +SoundDesc SA_explode((char*)PCM_explode); +SoundDesc SA_splash((char*)PCM_splash); + +SoundDesc SA_door_open((char*)PCM_door_open); +SoundDesc SA_door_close((char*)PCM_door_close); +SoundDesc SA_pop((char*)PCM_pop); +SoundDesc SA_hurt((char*)PCM_hurt); +SoundDesc SA_glass1((char*)PCM_glass1); +SoundDesc SA_glass2((char*)PCM_glass2); +SoundDesc SA_glass3((char*)PCM_glass3); + +SoundDesc SA_sheep1((char*)PCM_sheep1); +SoundDesc SA_sheep2((char*)PCM_sheep2); +SoundDesc SA_sheep3((char*)PCM_sheep3); +SoundDesc SA_pig1((char*)PCM_pig1); +SoundDesc SA_pig2((char*)PCM_pig2); +SoundDesc SA_pig3((char*)PCM_pig3); +SoundDesc SA_pigdeath((char*)PCM_pigdeath); + +//SoundDesc SA_chicken1((char*)PCM_chicken1); +SoundDesc SA_chicken2((char*)PCM_chicken2); +SoundDesc SA_chicken3((char*)PCM_chicken3); +SoundDesc SA_chickenhurt1((char*)PCM_chickenhurt1); +SoundDesc SA_chickenhurt2((char*)PCM_chickenhurt2); +SoundDesc SA_cow1((char*)PCM_cow1); +SoundDesc SA_cow2((char*)PCM_cow2); +SoundDesc SA_cow3((char*)PCM_cow3); +SoundDesc SA_cow4((char*)PCM_cow4); +SoundDesc SA_cowhurt1((char*)PCM_cowhurt1); +SoundDesc SA_cowhurt2((char*)PCM_cowhurt2); +SoundDesc SA_cowhurt3((char*)PCM_cowhurt3); + +SoundDesc SA_zombie1((char*)PCM_zombie1); +SoundDesc SA_zombie2((char*)PCM_zombie2); +SoundDesc SA_zombie3((char*)PCM_zombie3); + +SoundDesc SA_zpig1((char*)PCM_zpig1); +SoundDesc SA_zpig2((char*)PCM_zpig2); +SoundDesc SA_zpig3((char*)PCM_zpig3); +SoundDesc SA_zpig4((char*)PCM_zpig4); +SoundDesc SA_zpigangry1((char*)PCM_zpigangry1); +SoundDesc SA_zpigangry2((char*)PCM_zpigangry2); +SoundDesc SA_zpigangry3((char*)PCM_zpigangry3); +SoundDesc SA_zpigangry4((char*)PCM_zpigangry4); +SoundDesc SA_zpigdeath((char*)PCM_zpigdeath); +SoundDesc SA_zpighurt1((char*)PCM_zpighurt1); +SoundDesc SA_zpighurt2((char*)PCM_zpighurt2); + +SoundDesc SA_zombiedeath((char*)PCM_zombiedeath); +SoundDesc SA_zombiehurt1((char*)PCM_zombiehurt1); +SoundDesc SA_zombiehurt2((char*)PCM_zombiehurt2); + +SoundDesc SA_bow((char*)PCM_bow); +SoundDesc SA_bowhit1((char*)PCM_bowhit1); +SoundDesc SA_bowhit2((char*)PCM_bowhit2); +SoundDesc SA_bowhit3((char*)PCM_bowhit3); +SoundDesc SA_bowhit4((char*)PCM_bowhit4); +SoundDesc SA_fallbig1((char*)PCM_fallbig1); +SoundDesc SA_fallbig2((char*)PCM_fallbig2); +SoundDesc SA_fallsmall((char*)PCM_fallsmall); +SoundDesc SA_skeleton1((char*)PCM_skeleton1); +SoundDesc SA_skeleton2((char*)PCM_skeleton2); +SoundDesc SA_skeleton3((char*)PCM_skeleton3); +SoundDesc SA_skeletondeath((char*)PCM_skeletondeath); +SoundDesc SA_skeletonhurt1((char*)PCM_skeletonhurt1); +SoundDesc SA_skeletonhurt2((char*)PCM_skeletonhurt2); +SoundDesc SA_skeletonhurt3((char*)PCM_skeletonhurt3); +SoundDesc SA_skeletonhurt4((char*)PCM_skeletonhurt4); +SoundDesc SA_spider1((char*)PCM_spider1); +SoundDesc SA_spider2((char*)PCM_spider2); +SoundDesc SA_spider3((char*)PCM_spider3); +SoundDesc SA_spider4((char*)PCM_spider4); +SoundDesc SA_spiderdeath((char*)PCM_spiderdeath); + +SoundDesc SA_creeper1((char*)PCM_creeper1); +SoundDesc SA_creeper2((char*)PCM_creeper2); +SoundDesc SA_creeper3((char*)PCM_creeper3); +SoundDesc SA_creeper4((char*)PCM_creeper4); +SoundDesc SA_creeperdeath((char*)PCM_creeperdeath); +SoundDesc SA_eat1((char*)PCM_eat1); +SoundDesc SA_eat2((char*)PCM_eat2); +SoundDesc SA_eat3((char*)PCM_eat3); +SoundDesc SA_fuse((char*)PCM_fuse); + +#endif /*!PRE_ANDROID23 && !__APPLE__*/ diff --git a/src/client/sound/Sound.h b/src/client/sound/Sound.hpp similarity index 100% rename from src/client/sound/Sound.h rename to src/client/sound/Sound.hpp diff --git a/src/client/sound/SoundEngine.cpp b/src/client/sound/SoundEngine.cpp index 5582069..327012e 100755 --- a/src/client/sound/SoundEngine.cpp +++ b/src/client/sound/SoundEngine.cpp @@ -1,257 +1,257 @@ -#include "SoundEngine.h" -#include "../Options.h" -#include -#include "../../world/entity/Mob.h" - - -SoundEngine::SoundEngine( float maxDistance ) -: idCounter(0), - mc(0), - _x(0), - _y(0), - _z(0), - _yRot(0), - _invMaxDistance(1.0f / maxDistance) -{ - -} - -SoundEngine::~SoundEngine() -{ - -} - -void SoundEngine::init( Minecraft* mc, Options* options ) -{ - this->mc = mc; - this->options = options; - - if (/*!loaded && */(options == NULL || - (options->getProgressValue(OPTIONS_SOUND_VOLUME) != 0.f || - options->getProgressValue(OPTIONS_MUSIC_VOLUME) != 0.f))) - { - loadLibrary(); - } - -#if !defined(PRE_ANDROID23) && !defined(__APPLE__) && !defined(RPI) - sounds.add("step.cloth", SA_cloth1); - sounds.add("step.cloth", SA_cloth2); - sounds.add("step.cloth", SA_cloth3); - sounds.add("step.cloth", SA_cloth4); - sounds.add("step.grass", SA_grass1); - sounds.add("step.grass", SA_grass2); - sounds.add("step.grass", SA_grass3); - sounds.add("step.grass", SA_grass4); - sounds.add("step.gravel", SA_gravel1); - sounds.add("step.gravel", SA_gravel2); - sounds.add("step.gravel", SA_gravel3); - sounds.add("step.gravel", SA_gravel4); - sounds.add("step.sand", SA_sand1); - sounds.add("step.sand", SA_sand2); - sounds.add("step.sand", SA_sand3); - sounds.add("step.sand", SA_sand4); - sounds.add("step.stone", SA_stone1); - sounds.add("step.stone", SA_stone2); - sounds.add("step.stone", SA_stone3); - sounds.add("step.stone", SA_stone4); - sounds.add("step.wood", SA_wood1); - sounds.add("step.wood", SA_wood2); - sounds.add("step.wood", SA_wood3); - sounds.add("step.wood", SA_wood4); - - sounds.add("random.splash", SA_splash); - sounds.add("random.explode", SA_explode); - sounds.add("random.click", SA_click); - - sounds.add("random.door_open", SA_door_open); - sounds.add("random.door_close", SA_door_close); - sounds.add("random.pop", SA_pop); - sounds.add("random.pop2", SA_pop2); - sounds.add("random.hurt", SA_hurt); - sounds.add("random.glass", SA_glass1); - sounds.add("random.glass", SA_glass2); - sounds.add("random.glass", SA_glass3); - - sounds.add("mob.sheep", SA_sheep1); - sounds.add("mob.sheep", SA_sheep2); - sounds.add("mob.sheep", SA_sheep3); - sounds.add("mob.pig", SA_pig1); - sounds.add("mob.pig", SA_pig2); - sounds.add("mob.pig", SA_pig3); - sounds.add("mob.pigdeath", SA_pigdeath); - - sounds.add("mob.cow", SA_cow1); - sounds.add("mob.cow", SA_cow2); - sounds.add("mob.cow", SA_cow3); - sounds.add("mob.cow", SA_cow4); - sounds.add("mob.cowhurt", SA_cowhurt1); - sounds.add("mob.cowhurt", SA_cowhurt2); - sounds.add("mob.cowhurt", SA_cowhurt3); - - sounds.add("mob.chicken", SA_chicken2); - sounds.add("mob.chicken", SA_chicken3); - sounds.add("mob.chickenhurt", SA_chickenhurt1); - sounds.add("mob.chickenhurt", SA_chickenhurt2); - - sounds.add("mob.zombie", SA_zombie1); - sounds.add("mob.zombie", SA_zombie2); - sounds.add("mob.zombie", SA_zombie3); - sounds.add("mob.zombiedeath", SA_zombiedeath); - sounds.add("mob.zombiehurt", SA_zombiehurt1); - sounds.add("mob.zombiehurt", SA_zombiehurt2); - - sounds.add("mob.skeleton", SA_skeleton1); - sounds.add("mob.skeleton", SA_skeleton2); - sounds.add("mob.skeleton", SA_skeleton3); - sounds.add("mob.skeletonhurt", SA_skeletonhurt1); - sounds.add("mob.skeletonhurt", SA_skeletonhurt2); - sounds.add("mob.skeletonhurt", SA_skeletonhurt3); - sounds.add("mob.skeletonhurt", SA_skeletonhurt4); - - sounds.add("mob.spider", SA_spider1); - sounds.add("mob.spider", SA_spider2); - sounds.add("mob.spider", SA_spider3); - sounds.add("mob.spider", SA_spider4); - sounds.add("mob.spiderdeath", SA_spiderdeath); - - sounds.add("mob.zombiepig.zpig", SA_zpig1); - sounds.add("mob.zombiepig.zpig", SA_zpig2); - sounds.add("mob.zombiepig.zpig", SA_zpig3); - sounds.add("mob.zombiepig.zpig", SA_zpig4); - sounds.add("mob.zombiepig.zpigangry", SA_zpigangry1); - sounds.add("mob.zombiepig.zpigangry", SA_zpigangry2); - sounds.add("mob.zombiepig.zpigangry", SA_zpigangry3); - sounds.add("mob.zombiepig.zpigangry", SA_zpigangry4); - sounds.add("mob.zombiepig.zpigdeath", SA_zpigdeath); - sounds.add("mob.zombiepig.zpighurt", SA_zpighurt1); - sounds.add("mob.zombiepig.zpighurt", SA_zpighurt2); - - sounds.add("damage.fallbig", SA_fallbig1); - sounds.add("damage.fallbig", SA_fallbig2); - sounds.add("damage.fallsmall", SA_fallsmall); - - sounds.add("random.bow", SA_bow); - sounds.add("random.bowhit", SA_bowhit1); - sounds.add("random.bowhit", SA_bowhit2); - sounds.add("random.bowhit", SA_bowhit3); - sounds.add("random.bowhit", SA_bowhit4); - - sounds.add("mob.creeper", SA_creeper1); - sounds.add("mob.creeper", SA_creeper2); - sounds.add("mob.creeper", SA_creeper3); - sounds.add("mob.creeper", SA_creeper4); - sounds.add("mob.creeperdeath", SA_creeperdeath); - sounds.add("random.eat", SA_eat1); - sounds.add("random.eat", SA_eat2); - sounds.add("random.eat", SA_eat3); - sounds.add("random.fuse", SA_fuse); - -#endif -} - -void SoundEngine::enable( bool status ) -{ -#if defined(__APPLE__) - soundSystem.enable(status); -#endif -} - -void SoundEngine::updateOptions() -{ - -} - -void SoundEngine::destroy() -{ - //if (loaded) soundSystem.cleanup(); -} - -void SoundEngine::update( Mob* player, float a ) -{ - if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0) return; - if (player == NULL) return; - - _x = player->xo + (player->x - player->xo) * a; - _y = player->yo + (player->y - player->yo) * a; - _z = player->zo + (player->z - player->zo) * a; - _yRot = player->yRotO + (player->yRot - player->yRotO) * a; - - soundSystem.setListenerAngle(_yRot); - //soundSystem.setListenerPos(_x, _y, _z); //@note: not used, since we translate all sounds to Player space -} - -float SoundEngine::_getVolumeMult( float x, float y, float z ) -{ - const float dx = x - _x; - const float dy = y - _y; - const float dz = z - _z; - const float dist = Mth::sqrt(dx*dx + dy*dy + dz*dz); - const float out = Mth::clamp(1.1f - dist*_invMaxDistance, -1.0f, 1.0f); - return out; -} - -#if defined(PRE_ANDROID23) -void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) { - //volume *= (2.0f * _getVolumeMult(x, y, z)) - if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; - - volume *= _getVolumeMult(x, y, z); - mc->platform()->playSound(name, volume, pitch); -} -void SoundEngine::playUI(const std::string& name, float volume, float pitch) { - if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; - - //volume *= 2.0f; - mc->platform()->playSound(name, volume, pitch); -} -#elif defined(__APPLE__) -void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) { - if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; - - volume = Mth::clamp(volume, 0.0f, 1.0f); - - SoundDesc sound; - if (sounds.get(name, sound)) { - soundSystem.playAt(sound, x-_x, y-_y, z-_z, volume, pitch); - } -} -void SoundEngine::playUI(const std::string& name, float volume, float pitch) { - if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; - - volume = Mth::clamp(volume, 0.0f, 1.0f); - if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0 || volume <= 0) return; - - SoundDesc sound; - if (sounds.get(name, sound)) { - soundSystem.playAt(sound, 0, 0, 0, volume, pitch); - } -} -#elif defined(RPI) -void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) {} -void SoundEngine::playUI(const std::string& name, float volume, float pitch) {} -#else -void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) { - if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; - - volume = Mth::clamp( volume * _getVolumeMult(x, y, z), 0.0f, 1.0f); - if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0 || volume <= 0) return; - - SoundDesc sound; - if (sounds.get(name, sound)) { - float dist = SOUND_DISTANCE; - if (volume > 1) dist *= volume; - soundSystem.playAt(sound, x-_x, y-_y, z-_z, volume, pitch); - } -} -void SoundEngine::playUI(const std::string& name, float volume, float pitch) { - if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; - - volume = Mth::clamp(volume, 0.0f, 1.0f); - if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0 || volume <= 0) return; - - SoundDesc sound; - if (sounds.get(name, sound)) { - soundSystem.playAt(sound, 0, 0, 0, volume, pitch); - } -} -#endif +#include "SoundEngine.hpp" +#include "client/Options.hpp" +#include +#include "world/entity/Mob.hpp" + + +SoundEngine::SoundEngine( float maxDistance ) +: idCounter(0), + mc(0), + _x(0), + _y(0), + _z(0), + _yRot(0), + _invMaxDistance(1.0f / maxDistance) +{ + +} + +SoundEngine::~SoundEngine() +{ + +} + +void SoundEngine::init( Minecraft* mc, Options* options ) +{ + this->mc = mc; + this->options = options; + + if (/*!loaded && */(options == NULL || + (options->getProgressValue(OPTIONS_SOUND_VOLUME) != 0.f || + options->getProgressValue(OPTIONS_MUSIC_VOLUME) != 0.f))) + { + loadLibrary(); + } + +#if !defined(PRE_ANDROID23) && !defined(__APPLE__) && !defined(RPI) + sounds.add("step.cloth", SA_cloth1); + sounds.add("step.cloth", SA_cloth2); + sounds.add("step.cloth", SA_cloth3); + sounds.add("step.cloth", SA_cloth4); + sounds.add("step.grass", SA_grass1); + sounds.add("step.grass", SA_grass2); + sounds.add("step.grass", SA_grass3); + sounds.add("step.grass", SA_grass4); + sounds.add("step.gravel", SA_gravel1); + sounds.add("step.gravel", SA_gravel2); + sounds.add("step.gravel", SA_gravel3); + sounds.add("step.gravel", SA_gravel4); + sounds.add("step.sand", SA_sand1); + sounds.add("step.sand", SA_sand2); + sounds.add("step.sand", SA_sand3); + sounds.add("step.sand", SA_sand4); + sounds.add("step.stone", SA_stone1); + sounds.add("step.stone", SA_stone2); + sounds.add("step.stone", SA_stone3); + sounds.add("step.stone", SA_stone4); + sounds.add("step.wood", SA_wood1); + sounds.add("step.wood", SA_wood2); + sounds.add("step.wood", SA_wood3); + sounds.add("step.wood", SA_wood4); + + sounds.add("random.splash", SA_splash); + sounds.add("random.explode", SA_explode); + sounds.add("random.click", SA_click); + + sounds.add("random.door_open", SA_door_open); + sounds.add("random.door_close", SA_door_close); + sounds.add("random.pop", SA_pop); + sounds.add("random.pop2", SA_pop2); + sounds.add("random.hurt", SA_hurt); + sounds.add("random.glass", SA_glass1); + sounds.add("random.glass", SA_glass2); + sounds.add("random.glass", SA_glass3); + + sounds.add("mob.sheep", SA_sheep1); + sounds.add("mob.sheep", SA_sheep2); + sounds.add("mob.sheep", SA_sheep3); + sounds.add("mob.pig", SA_pig1); + sounds.add("mob.pig", SA_pig2); + sounds.add("mob.pig", SA_pig3); + sounds.add("mob.pigdeath", SA_pigdeath); + + sounds.add("mob.cow", SA_cow1); + sounds.add("mob.cow", SA_cow2); + sounds.add("mob.cow", SA_cow3); + sounds.add("mob.cow", SA_cow4); + sounds.add("mob.cowhurt", SA_cowhurt1); + sounds.add("mob.cowhurt", SA_cowhurt2); + sounds.add("mob.cowhurt", SA_cowhurt3); + + sounds.add("mob.chicken", SA_chicken2); + sounds.add("mob.chicken", SA_chicken3); + sounds.add("mob.chickenhurt", SA_chickenhurt1); + sounds.add("mob.chickenhurt", SA_chickenhurt2); + + sounds.add("mob.zombie", SA_zombie1); + sounds.add("mob.zombie", SA_zombie2); + sounds.add("mob.zombie", SA_zombie3); + sounds.add("mob.zombiedeath", SA_zombiedeath); + sounds.add("mob.zombiehurt", SA_zombiehurt1); + sounds.add("mob.zombiehurt", SA_zombiehurt2); + + sounds.add("mob.skeleton", SA_skeleton1); + sounds.add("mob.skeleton", SA_skeleton2); + sounds.add("mob.skeleton", SA_skeleton3); + sounds.add("mob.skeletonhurt", SA_skeletonhurt1); + sounds.add("mob.skeletonhurt", SA_skeletonhurt2); + sounds.add("mob.skeletonhurt", SA_skeletonhurt3); + sounds.add("mob.skeletonhurt", SA_skeletonhurt4); + + sounds.add("mob.spider", SA_spider1); + sounds.add("mob.spider", SA_spider2); + sounds.add("mob.spider", SA_spider3); + sounds.add("mob.spider", SA_spider4); + sounds.add("mob.spiderdeath", SA_spiderdeath); + + sounds.add("mob.zombiepig.zpig", SA_zpig1); + sounds.add("mob.zombiepig.zpig", SA_zpig2); + sounds.add("mob.zombiepig.zpig", SA_zpig3); + sounds.add("mob.zombiepig.zpig", SA_zpig4); + sounds.add("mob.zombiepig.zpigangry", SA_zpigangry1); + sounds.add("mob.zombiepig.zpigangry", SA_zpigangry2); + sounds.add("mob.zombiepig.zpigangry", SA_zpigangry3); + sounds.add("mob.zombiepig.zpigangry", SA_zpigangry4); + sounds.add("mob.zombiepig.zpigdeath", SA_zpigdeath); + sounds.add("mob.zombiepig.zpighurt", SA_zpighurt1); + sounds.add("mob.zombiepig.zpighurt", SA_zpighurt2); + + sounds.add("damage.fallbig", SA_fallbig1); + sounds.add("damage.fallbig", SA_fallbig2); + sounds.add("damage.fallsmall", SA_fallsmall); + + sounds.add("random.bow", SA_bow); + sounds.add("random.bowhit", SA_bowhit1); + sounds.add("random.bowhit", SA_bowhit2); + sounds.add("random.bowhit", SA_bowhit3); + sounds.add("random.bowhit", SA_bowhit4); + + sounds.add("mob.creeper", SA_creeper1); + sounds.add("mob.creeper", SA_creeper2); + sounds.add("mob.creeper", SA_creeper3); + sounds.add("mob.creeper", SA_creeper4); + sounds.add("mob.creeperdeath", SA_creeperdeath); + sounds.add("random.eat", SA_eat1); + sounds.add("random.eat", SA_eat2); + sounds.add("random.eat", SA_eat3); + sounds.add("random.fuse", SA_fuse); + +#endif +} + +void SoundEngine::enable( bool status ) +{ +#if defined(__APPLE__) + soundSystem.enable(status); +#endif +} + +void SoundEngine::updateOptions() +{ + +} + +void SoundEngine::destroy() +{ + //if (loaded) soundSystem.cleanup(); +} + +void SoundEngine::update( Mob* player, float a ) +{ + if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0) return; + if (player == NULL) return; + + _x = player->xo + (player->x - player->xo) * a; + _y = player->yo + (player->y - player->yo) * a; + _z = player->zo + (player->z - player->zo) * a; + _yRot = player->yRotO + (player->yRot - player->yRotO) * a; + + soundSystem.setListenerAngle(_yRot); + //soundSystem.setListenerPos(_x, _y, _z); //@note: not used, since we translate all sounds to Player space +} + +float SoundEngine::_getVolumeMult( float x, float y, float z ) +{ + const float dx = x - _x; + const float dy = y - _y; + const float dz = z - _z; + const float dist = Mth::sqrt(dx*dx + dy*dy + dz*dz); + const float out = Mth::clamp(1.1f - dist*_invMaxDistance, -1.0f, 1.0f); + return out; +} + +#if defined(PRE_ANDROID23) +void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) { + //volume *= (2.0f * _getVolumeMult(x, y, z)) + if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; + + volume *= _getVolumeMult(x, y, z); + mc->platform()->playSound(name, volume, pitch); +} +void SoundEngine::playUI(const std::string& name, float volume, float pitch) { + if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; + + //volume *= 2.0f; + mc->platform()->playSound(name, volume, pitch); +} +#elif defined(__APPLE__) +void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) { + if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; + + volume = Mth::clamp(volume, 0.0f, 1.0f); + + SoundDesc sound; + if (sounds.get(name, sound)) { + soundSystem.playAt(sound, x-_x, y-_y, z-_z, volume, pitch); + } +} +void SoundEngine::playUI(const std::string& name, float volume, float pitch) { + if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; + + volume = Mth::clamp(volume, 0.0f, 1.0f); + if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0 || volume <= 0) return; + + SoundDesc sound; + if (sounds.get(name, sound)) { + soundSystem.playAt(sound, 0, 0, 0, volume, pitch); + } +} +#elif defined(RPI) +void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) {} +void SoundEngine::playUI(const std::string& name, float volume, float pitch) {} +#else +void SoundEngine::play(const std::string& name, float x, float y, float z, float volume, float pitch) { + if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; + + volume = Mth::clamp( volume * _getVolumeMult(x, y, z), 0.0f, 1.0f); + if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0 || volume <= 0) return; + + SoundDesc sound; + if (sounds.get(name, sound)) { + float dist = SOUND_DISTANCE; + if (volume > 1) dist *= volume; + soundSystem.playAt(sound, x-_x, y-_y, z-_z, volume, pitch); + } +} +void SoundEngine::playUI(const std::string& name, float volume, float pitch) { + if ((volume *= options->getProgressValue(OPTIONS_SOUND_VOLUME)) <= 0) return; + + volume = Mth::clamp(volume, 0.0f, 1.0f); + if (/*!loaded || */options->getProgressValue(OPTIONS_SOUND_VOLUME) == 0 || volume <= 0) return; + + SoundDesc sound; + if (sounds.get(name, sound)) { + soundSystem.playAt(sound, 0, 0, 0, volume, pitch); + } +} +#endif diff --git a/src/client/sound/SoundEngine.h b/src/client/sound/SoundEngine.hpp similarity index 86% rename from src/client/sound/SoundEngine.h rename to src/client/sound/SoundEngine.hpp index 8a0027f..5cd7d97 100755 --- a/src/client/sound/SoundEngine.h +++ b/src/client/sound/SoundEngine.hpp @@ -3,14 +3,14 @@ //package net.minecraft.client.sound; #if defined(ANDROID) && !defined(PRE_ANDROID23) - #include "../../platform/audio/SoundSystemSL.h" + #include "platform/audio/SoundSystemSL.hpp" #elif (defined(__APPLE__) || defined(PLATFORM_DESKTOP)) && !defined(NO_SOUND) - #include "../../platform/audio/SoundSystemAL.h" + #include "platform/audio/SoundSystemAL.hpp" #else - #include "../../platform/audio/SoundSystem.h" + #include "platform/audio/SoundSystem.hpp" #endif -#include "SoundRepository.h" -#include "../../util/Random.h" +#include "SoundRepository.hpp" +#include "util/Random.hpp" class Minecraft; class Mob; diff --git a/src/client/sound/SoundEngine.mm b/src/client/sound/SoundEngine.mm index 9c0cf4f..047376e 100755 --- a/src/client/sound/SoundEngine.mm +++ b/src/client/sound/SoundEngine.mm @@ -1,6 +1,6 @@ #include "SoundEngine.h" #include "../Options.h" -#include +#include #include "../../world/entity/Mob.h" /* diff --git a/src/client/sound/SoundRepository.h b/src/client/sound/SoundRepository.hpp similarity index 94% rename from src/client/sound/SoundRepository.h rename to src/client/sound/SoundRepository.hpp index 693311e..cb6112f 100755 --- a/src/client/sound/SoundRepository.h +++ b/src/client/sound/SoundRepository.hpp @@ -2,9 +2,9 @@ #include #include -#include "Sound.h" -#include "../../util/Mth.h" -#include "../../platform/log.h" +#include "Sound.hpp" +#include "util/Mth.hpp" +#include "platform/log.hpp" class SoundRepository { diff --git a/src/gamemode/CreativeMode.cpp b/src/gamemode/CreativeMode.cpp index e53bee6..78f3b21 100755 --- a/src/gamemode/CreativeMode.cpp +++ b/src/gamemode/CreativeMode.cpp @@ -1,59 +1,59 @@ -#include "CreativeMode.h" -#include -#include -#include - -static const int DestructionTickDelay = 5; - -CreativeMode::CreativeMode(Minecraft& minecraft) -: super(minecraft) -{ -} - -void CreativeMode::startDestroyBlock(Player* player, int x, int y, int z, int face) { - if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == Item::bow->id) - return; - - creativeDestroyBlock(player, x, y, z, face); - destroyDelay = DestructionTickDelay; -} - -void CreativeMode::creativeDestroyBlock(Player* player, int x, int y, int z, int face) { - minecraft.level->extinguishFire(x, y, z, face); - destroyBlock(player, x, y, z, face); -} - -void CreativeMode::continueDestroyBlock(Player* player, int x, int y, int z, int face) { - destroyDelay--; - if (destroyDelay <= 0) { - destroyDelay = DestructionTickDelay; - creativeDestroyBlock(player, x, y, z, face); - } -} - -void CreativeMode::stopDestroyBlock(Player* player) { - destroyDelay = 0; -} - -void CreativeMode::initAbilities( Abilities& abilities ) { - abilities.mayfly = true; - abilities.instabuild = true; - abilities.invulnerable = true; -} - -bool CreativeMode::isCreativeType() { - return true; -} - -void CreativeMode::releaseUsingItem( Player* player ) { - if(player->getCarriedItem() != NULL) { - int oldItemId = player->getCarriedItem()->id; - int oldAux = player->getAuxData(); - super::releaseUsingItem(player); - if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == oldItemId) { - player->getCarriedItem()->setAuxValue(oldAux); - } - } else { - super::releaseUsingItem(player); - } -} +#include "CreativeMode.hpp" +#include +#include +#include + +static const int DestructionTickDelay = 5; + +CreativeMode::CreativeMode(Minecraft& minecraft) +: super(minecraft) +{ +} + +void CreativeMode::startDestroyBlock(Player* player, int x, int y, int z, int face) { + if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == Item::bow->id) + return; + + creativeDestroyBlock(player, x, y, z, face); + destroyDelay = DestructionTickDelay; +} + +void CreativeMode::creativeDestroyBlock(Player* player, int x, int y, int z, int face) { + minecraft.level->extinguishFire(x, y, z, face); + destroyBlock(player, x, y, z, face); +} + +void CreativeMode::continueDestroyBlock(Player* player, int x, int y, int z, int face) { + destroyDelay--; + if (destroyDelay <= 0) { + destroyDelay = DestructionTickDelay; + creativeDestroyBlock(player, x, y, z, face); + } +} + +void CreativeMode::stopDestroyBlock(Player* player) { + destroyDelay = 0; +} + +void CreativeMode::initAbilities( Abilities& abilities ) { + abilities.mayfly = true; + abilities.instabuild = true; + abilities.invulnerable = true; +} + +bool CreativeMode::isCreativeType() { + return true; +} + +void CreativeMode::releaseUsingItem( Player* player ) { + if(player->getCarriedItem() != NULL) { + int oldItemId = player->getCarriedItem()->id; + int oldAux = player->getAuxData(); + super::releaseUsingItem(player); + if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == oldItemId) { + player->getCarriedItem()->setAuxValue(oldAux); + } + } else { + super::releaseUsingItem(player); + } +} diff --git a/src/gamemode/CreativeMode.h b/src/gamemode/CreativeMode.hpp similarity index 95% rename from src/gamemode/CreativeMode.h rename to src/gamemode/CreativeMode.hpp index a7caf63..f59df4c 100755 --- a/src/gamemode/CreativeMode.h +++ b/src/gamemode/CreativeMode.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.gamemode; -#include "GameMode.h" +#include "GameMode.hpp" class CreativeMode: public GameMode { diff --git a/src/gamemode/CreatorMode.cpp b/src/gamemode/CreatorMode.cpp index 8664e09..e82cc55 100755 --- a/src/gamemode/CreatorMode.cpp +++ b/src/gamemode/CreatorMode.cpp @@ -1,111 +1,111 @@ -#include "CreatorMode.h" -#include "world/entity/player/Player.h" -#include "world/level/Level.h" -#include -#include - -static const int DestructionTickDelay = 5; - -class Creator: public ICreator { - //virtual void getEvents(); - -public: - Creator(/*int eventLifeTime*/) - : _tileEvents(32), - _tickId(0) - { - } - - void setTick(int tick) { - _tickId = tick; - } - - EventList& getTileEvents() { return _tileEvents; } - - void addevent_blockUse(int entityId, int x, int y, int z, int face) { - TileEvent t = { - entityId, - x,y,z, - face - }; - _tileEvents.add(t, _tickId); - } - -private: - EventList _tileEvents; - int _tickId; -}; - -CreatorMode::CreatorMode(Minecraft& minecraft) -: super(minecraft) -{ - _creator = new Creator(); -} - -CreatorMode::~CreatorMode() { - delete _creator; -} - -void CreatorMode::startDestroyBlock(Player* player, int x, int y, int z, int face) { - if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == Item::bow->id) - return; - - CreatorDestroyBlock(player, x, y, z, face); - destroyDelay = DestructionTickDelay; -} - -void CreatorMode::CreatorDestroyBlock(Player* player, int x, int y, int z, int face) { - minecraft.level->extinguishFire(x, y, z, face); - destroyBlock(player, x, y, z, face); - -} - -void CreatorMode::continueDestroyBlock(Player* player, int x, int y, int z, int face) { - destroyDelay--; - if (destroyDelay <= 0) { - destroyDelay = DestructionTickDelay; - CreatorDestroyBlock(player, x, y, z, face); - } -} - -bool CreatorMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit ) { - if (item && item->id == ((Item*)Item::sword_iron)->id) - _creator->addevent_blockUse(player->entityId, x, y, z, face); - return super::useItemOn(player, level, item, x, y, z, face, hit); -} - -void CreatorMode::stopDestroyBlock(Player* player) { - destroyDelay = 0; -} - -void CreatorMode::initAbilities( Abilities& abilities ) { - abilities.mayfly = true; - abilities.instabuild = true; - abilities.invulnerable = true; -} - -bool CreatorMode::isCreativeType() { - return true; -} - -void CreatorMode::releaseUsingItem( Player* player ) { - if(player->getCarriedItem() != NULL) { - int oldItemId = player->getCarriedItem()->id; - int oldAux = player->getAuxData(); - super::releaseUsingItem(player); - if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == oldItemId) { - player->getCarriedItem()->setAuxValue(oldAux); - } - } else { - super::releaseUsingItem(player); - } -} - -ICreator* CreatorMode::getCreator() { - return _creator; -} - -void CreatorMode::tick() { - _creator->setTick(minecraft.level->getTime()); - super::tick(); -} +#include "CreatorMode.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include +#include + +static const int DestructionTickDelay = 5; + +class Creator: public ICreator { + //virtual void getEvents(); + +public: + Creator(/*int eventLifeTime*/) + : _tileEvents(32), + _tickId(0) + { + } + + void setTick(int tick) { + _tickId = tick; + } + + EventList& getTileEvents() { return _tileEvents; } + + void addevent_blockUse(int entityId, int x, int y, int z, int face) { + TileEvent t = { + entityId, + x,y,z, + face + }; + _tileEvents.add(t, _tickId); + } + +private: + EventList _tileEvents; + int _tickId; +}; + +CreatorMode::CreatorMode(Minecraft& minecraft) +: super(minecraft) +{ + _creator = new Creator(); +} + +CreatorMode::~CreatorMode() { + delete _creator; +} + +void CreatorMode::startDestroyBlock(Player* player, int x, int y, int z, int face) { + if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == Item::bow->id) + return; + + CreatorDestroyBlock(player, x, y, z, face); + destroyDelay = DestructionTickDelay; +} + +void CreatorMode::CreatorDestroyBlock(Player* player, int x, int y, int z, int face) { + minecraft.level->extinguishFire(x, y, z, face); + destroyBlock(player, x, y, z, face); + +} + +void CreatorMode::continueDestroyBlock(Player* player, int x, int y, int z, int face) { + destroyDelay--; + if (destroyDelay <= 0) { + destroyDelay = DestructionTickDelay; + CreatorDestroyBlock(player, x, y, z, face); + } +} + +bool CreatorMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x, int y, int z, int face, const Vec3& hit ) { + if (item && item->id == ((Item*)Item::sword_iron)->id) + _creator->addevent_blockUse(player->entityId, x, y, z, face); + return super::useItemOn(player, level, item, x, y, z, face, hit); +} + +void CreatorMode::stopDestroyBlock(Player* player) { + destroyDelay = 0; +} + +void CreatorMode::initAbilities( Abilities& abilities ) { + abilities.mayfly = true; + abilities.instabuild = true; + abilities.invulnerable = true; +} + +bool CreatorMode::isCreativeType() { + return true; +} + +void CreatorMode::releaseUsingItem( Player* player ) { + if(player->getCarriedItem() != NULL) { + int oldItemId = player->getCarriedItem()->id; + int oldAux = player->getAuxData(); + super::releaseUsingItem(player); + if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == oldItemId) { + player->getCarriedItem()->setAuxValue(oldAux); + } + } else { + super::releaseUsingItem(player); + } +} + +ICreator* CreatorMode::getCreator() { + return _creator; +} + +void CreatorMode::tick() { + _creator->setTick(minecraft.level->getTime()); + super::tick(); +} diff --git a/src/gamemode/CreatorMode.h b/src/gamemode/CreatorMode.hpp similarity index 97% rename from src/gamemode/CreatorMode.h rename to src/gamemode/CreatorMode.hpp index 1cd1062..396943e 100755 --- a/src/gamemode/CreatorMode.h +++ b/src/gamemode/CreatorMode.hpp @@ -2,8 +2,8 @@ //package net.minecraft.client.gamemode; -#include "GameMode.h" -#include +#include "GameMode.hpp" +#include class ICreator { public: diff --git a/src/gamemode/GameMode.cpp b/src/gamemode/GameMode.cpp index 12f8dae..b830088 100755 --- a/src/gamemode/GameMode.cpp +++ b/src/gamemode/GameMode.cpp @@ -1,14 +1,14 @@ -#include "GameMode.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "GameMode.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /*virtual*/ diff --git a/src/gamemode/GameMode.h b/src/gamemode/GameMode.hpp similarity index 97% rename from src/gamemode/GameMode.h rename to src/gamemode/GameMode.hpp index 324ccba..60b06d3 100755 --- a/src/gamemode/GameMode.h +++ b/src/gamemode/GameMode.hpp @@ -2,7 +2,7 @@ //package net.minecraft.client.gamemode; -#include +#include class ItemInstance; class Minecraft; diff --git a/src/gamemode/SurvivalMode.cpp b/src/gamemode/SurvivalMode.cpp index 7ace84d..745d863 100755 --- a/src/gamemode/SurvivalMode.cpp +++ b/src/gamemode/SurvivalMode.cpp @@ -1,93 +1,93 @@ -#include "SurvivalMode.h" -#include -#include -#include - -SurvivalMode::SurvivalMode( Minecraft& minecraft ) -: super(minecraft), - xDestroyBlock(-1), - yDestroyBlock(-1), - zDestroyBlock(-1) -{ -} - -void SurvivalMode::continueDestroyBlock(Player* player, int x, int y, int z, int face ) { - if (destroyDelay > 0) { - destroyDelay--; - return; - } - - if (x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock) { - int t = minecraft.level->getTile(x, y, z); - if (t == 0) return; - Tile* tile = Tile::tiles[t]; - - destroyProgress += tile->getDestroyProgress(player); - - if ((++destroyTicks & 3) == 1) { -#ifndef STANDALONE_SERVER - if (tile != NULL) { - minecraft->soundEngine->play(tile->soundType->getStepSound(), x + 0.5f, y + 0.5f, z + 0.5f, (tile->soundType->getVolume() + 1) / 8, tile->soundType->getPitch() * 0.5f); - } -#endif - } - - if (destroyProgress >= 1) { - destroyBlock(player, x, y, z, face); - destroyProgress = 0; - oDestroyProgress = 0; - destroyTicks = 0; - destroyDelay = 5; - } - } else { - destroyProgress = 0; - oDestroyProgress = 0; - destroyTicks = 0; - xDestroyBlock = x; - yDestroyBlock = y; - zDestroyBlock = z; - } -} - -bool SurvivalMode::destroyBlock(Player* player, int x, int y, int z, int face ) { - int t = minecraft.level->getTile(x, y, z); - int data = minecraft.level->getData(x, y, z); - bool changed = GameMode::destroyBlock(player, x, y, z, face); - bool couldDestroy = player->canDestroy(Tile::tiles[t]); - - ItemInstance* item = player->inventory->getSelected(); - if (item != NULL) { - item->mineBlock(t, x, y, z); - if (item->count == 0) { - //item->snap(minecraft->player); - player->inventory->clearSlot(player->inventory->selected); - } - } - if (changed && couldDestroy) { - ItemInstance instance(t, 1, data); - Tile::tiles[t]->playerDestroy(minecraft.level, player, x, y, z, data); - } - return changed; -} - -void SurvivalMode::stopDestroyBlock(Player* player) { - destroyProgress = 0; - destroyDelay = 0; -} - -void SurvivalMode::initAbilities( Abilities& abilities ) { - abilities.flying = false; - abilities.mayfly = false; - abilities.instabuild = false; - abilities.invulnerable = false; -} - -void SurvivalMode::startDestroyBlock(Player* player, int x, int y, int z, int face ) { - if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == Item::bow->id) - return; - - int t = minecraft.level->getTile(x, y, z); - if (t > 0 && destroyProgress == 0) Tile::tiles[t]->attack(minecraft.level, x, y, z, player); - if (t > 0 && Tile::tiles[t]->getDestroyProgress(player) >= 1) - destroyBlock(player, x, y, z, face); -} +#include "SurvivalMode.hpp" +#include +#include +#include + +SurvivalMode::SurvivalMode( Minecraft& minecraft ) +: super(minecraft), + xDestroyBlock(-1), + yDestroyBlock(-1), + zDestroyBlock(-1) +{ +} + +void SurvivalMode::continueDestroyBlock(Player* player, int x, int y, int z, int face ) { + if (destroyDelay > 0) { + destroyDelay--; + return; + } + + if (x == xDestroyBlock && y == yDestroyBlock && z == zDestroyBlock) { + int t = minecraft.level->getTile(x, y, z); + if (t == 0) return; + Tile* tile = Tile::tiles[t]; + + destroyProgress += tile->getDestroyProgress(player); + + if ((++destroyTicks & 3) == 1) { +#ifndef STANDALONE_SERVER + if (tile != NULL) { + minecraft->soundEngine->play(tile->soundType->getStepSound(), x + 0.5f, y + 0.5f, z + 0.5f, (tile->soundType->getVolume() + 1) / 8, tile->soundType->getPitch() * 0.5f); + } +#endif + } + + if (destroyProgress >= 1) { + destroyBlock(player, x, y, z, face); + destroyProgress = 0; + oDestroyProgress = 0; + destroyTicks = 0; + destroyDelay = 5; + } + } else { + destroyProgress = 0; + oDestroyProgress = 0; + destroyTicks = 0; + xDestroyBlock = x; + yDestroyBlock = y; + zDestroyBlock = z; + } +} + +bool SurvivalMode::destroyBlock(Player* player, int x, int y, int z, int face ) { + int t = minecraft.level->getTile(x, y, z); + int data = minecraft.level->getData(x, y, z); + bool changed = GameMode::destroyBlock(player, x, y, z, face); + bool couldDestroy = player->canDestroy(Tile::tiles[t]); + + ItemInstance* item = player->inventory->getSelected(); + if (item != NULL) { + item->mineBlock(t, x, y, z); + if (item->count == 0) { + //item->snap(minecraft->player); + player->inventory->clearSlot(player->inventory->selected); + } + } + if (changed && couldDestroy) { + ItemInstance instance(t, 1, data); + Tile::tiles[t]->playerDestroy(minecraft.level, player, x, y, z, data); + } + return changed; +} + +void SurvivalMode::stopDestroyBlock(Player* player) { + destroyProgress = 0; + destroyDelay = 0; +} + +void SurvivalMode::initAbilities( Abilities& abilities ) { + abilities.flying = false; + abilities.mayfly = false; + abilities.instabuild = false; + abilities.invulnerable = false; +} + +void SurvivalMode::startDestroyBlock(Player* player, int x, int y, int z, int face ) { + if(player->getCarriedItem() != NULL && player->getCarriedItem()->id == Item::bow->id) + return; + + int t = minecraft.level->getTile(x, y, z); + if (t > 0 && destroyProgress == 0) Tile::tiles[t]->attack(minecraft.level, x, y, z, player); + if (t > 0 && Tile::tiles[t]->getDestroyProgress(player) >= 1) + destroyBlock(player, x, y, z, face); +} diff --git a/src/gamemode/SurvivalMode.h b/src/gamemode/SurvivalMode.hpp similarity index 96% rename from src/gamemode/SurvivalMode.h rename to src/gamemode/SurvivalMode.hpp index df30099..b8dbc5d 100755 --- a/src/gamemode/SurvivalMode.h +++ b/src/gamemode/SurvivalMode.hpp @@ -1,6 +1,6 @@ #pragma once -#include "GameMode.h" +#include "GameMode.hpp" class Abilities; class Minecraft; diff --git a/src/locale/I18n.cpp b/src/locale/I18n.cpp index 6487c00..51c3b91 100755 --- a/src/locale/I18n.cpp +++ b/src/locale/I18n.cpp @@ -1,114 +1,114 @@ -#include "I18n.h" -#include -#include -#include "../util/StringUtils.h" -#include "../world/level/tile/Tile.h" -#include "../world/item/ItemInstance.h" -#include - -I18n::Map I18n::_strings; - -void I18n::loadLanguage(IPlatform& platform, const std::string& languageCode ) { - _strings.clear(); - fillTranslations(platform, "lang/en_US.lang", true); - - if (languageCode != "en_US") - fillTranslations(platform, "lang/" + languageCode + ".lang", true); -} - -bool I18n::get( const std::string& id, std::string& out ) { - Map::const_iterator cit = _strings.find(id); - if (cit != _strings.end()) { - out = cit->second; - return true; - } - return false; -} - -std::string I18n::get( const std::string& id ) { - Map::const_iterator cit = _strings.find(id); - if (cit != _strings.end()) - return cit->second; - - return id + '<';//lang.getElement(id); -} - -void I18n::fillTranslations(IPlatform& platform, const std::string& filename, bool overwrite ) { - auto blob = platform.readAssetFile(filename); - if (blob.empty()) return; - - std::string data(blob.begin(), blob.end()); - std::stringstream fin(data, std::ios_base::in); - - std::string line; - while( std::getline(fin, line) ) { - int spos = line.find('='); - if (spos == std::string::npos) - continue; - - std::string key = Util::stringTrim(line.substr(0, spos)); - Map::const_iterator cit = _strings.find(key); - if (!overwrite && cit != _strings.end()) - continue; - - std::string value = Util::stringTrim(line.substr(spos + 1)); - _strings.insert( std::make_pair(key, value ) ); - } -} - -std::string I18n::getDescriptionString( const ItemInstance& item ) { - // Convert to lower. Normally std::transform would be used, but tolower might be - // implemented with a macro in certain C-implementations -> messing stuff up - const std::string desc = item.getDescriptionId(); - - std::string s = desc; - std::string trans; - - // Handle special cases - if (item.id == Tile::cloth->id) - return get(item.getAuxValue()? "desc.wool" : "desc.woolstring"); - else if (item.id == Tile::fenceGate->id) - return I18n::get("desc.fence"); - else if (item.id == Tile::stoneSlabHalf->id) - return I18n::get("desc.slab"); - - for (unsigned int i = 0; i < s.length(); ++i) - s[i] = ::tolower(s[i]); - - // Replace item./tile. with desc., hopefully it's enough - if (s[0] == 't') s = Util::stringReplace(s, "tile.", "desc."); - if (s[0] == 'i') s = Util::stringReplace(s, "item.", "desc."); - if (I18n::get(s, trans)) - return trans; - - // Remove all materials from the identifier, since swordWood should - // be read as just sword - const char* materials[] = { - "wood", - "iron", - "stone", - "diamond", - "gold", - "brick", - "emerald", - "lapis", - "cloth" - }; - - Util::removeAll(s, materials, sizeof(materials) / sizeof(const char*)); - if (I18n::get(s, trans)) - return trans; - - std::string mapping[] = { - "tile.workbench", "craftingtable", - }; - const char numMappings = sizeof(mapping) / sizeof(std::string); - for (int i = 0; i < numMappings; i += 2) { - if (desc == mapping[i]) { - if (I18n::get("desc." + mapping[i+1], trans)) - return trans; - } - } - - return desc + " : couldn't find desc"; -} +#include "I18n.hpp" +#include +#include +#include "util/StringUtils.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/item/ItemInstance.hpp" +#include + +I18n::Map I18n::_strings; + +void I18n::loadLanguage(IPlatform& platform, const std::string& languageCode ) { + _strings.clear(); + fillTranslations(platform, "lang/en_US.lang", true); + + if (languageCode != "en_US") + fillTranslations(platform, "lang/" + languageCode + ".lang", true); +} + +bool I18n::get( const std::string& id, std::string& out ) { + Map::const_iterator cit = _strings.find(id); + if (cit != _strings.end()) { + out = cit->second; + return true; + } + return false; +} + +std::string I18n::get( const std::string& id ) { + Map::const_iterator cit = _strings.find(id); + if (cit != _strings.end()) + return cit->second; + + return id + '<';//lang.getElement(id); +} + +void I18n::fillTranslations(IPlatform& platform, const std::string& filename, bool overwrite ) { + auto blob = platform.readAssetFile(filename); + if (blob.empty()) return; + + std::string data(blob.begin(), blob.end()); + std::stringstream fin(data, std::ios_base::in); + + std::string line; + while( std::getline(fin, line) ) { + int spos = line.find('='); + if (spos == std::string::npos) + continue; + + std::string key = Util::stringTrim(line.substr(0, spos)); + Map::const_iterator cit = _strings.find(key); + if (!overwrite && cit != _strings.end()) + continue; + + std::string value = Util::stringTrim(line.substr(spos + 1)); + _strings.insert( std::make_pair(key, value ) ); + } +} + +std::string I18n::getDescriptionString( const ItemInstance& item ) { + // Convert to lower. Normally std::transform would be used, but tolower might be + // implemented with a macro in certain C-implementations -> messing stuff up + const std::string desc = item.getDescriptionId(); + + std::string s = desc; + std::string trans; + + // Handle special cases + if (item.id == Tile::cloth->id) + return get(item.getAuxValue()? "desc.wool" : "desc.woolstring"); + else if (item.id == Tile::fenceGate->id) + return I18n::get("desc.fence"); + else if (item.id == Tile::stoneSlabHalf->id) + return I18n::get("desc.slab"); + + for (unsigned int i = 0; i < s.length(); ++i) + s[i] = ::tolower(s[i]); + + // Replace item./tile. with desc., hopefully it's enough + if (s[0] == 't') s = Util::stringReplace(s, "tile.", "desc."); + if (s[0] == 'i') s = Util::stringReplace(s, "item.", "desc."); + if (I18n::get(s, trans)) + return trans; + + // Remove all materials from the identifier, since swordWood should + // be read as just sword + const char* materials[] = { + "wood", + "iron", + "stone", + "diamond", + "gold", + "brick", + "emerald", + "lapis", + "cloth" + }; + + Util::removeAll(s, materials, sizeof(materials) / sizeof(const char*)); + if (I18n::get(s, trans)) + return trans; + + std::string mapping[] = { + "tile.workbench", "craftingtable", + }; + const char numMappings = sizeof(mapping) / sizeof(std::string); + for (int i = 0; i < numMappings; i += 2) { + if (desc == mapping[i]) { + if (I18n::get("desc." + mapping[i+1], trans)) + return trans; + } + } + + return desc + " : couldn't find desc"; +} diff --git a/src/locale/I18n.h b/src/locale/I18n.hpp similarity index 96% rename from src/locale/I18n.h rename to src/locale/I18n.hpp index a97fd9f..ac045bb 100755 --- a/src/locale/I18n.h +++ b/src/locale/I18n.hpp @@ -2,7 +2,7 @@ //package net.minecraft.locale; -#include "IPlatform.h" +#include "IPlatform.hpp" #include #include diff --git a/src/main.cpp b/src/main.cpp index ddd7500..0c8466c 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,9 @@ -#include "MinecraftClient.h" - -int main() { - MinecraftClient minecraft(App::CreatePlatform()); - - minecraft.run(); - - return 0; +#include "MinecraftClient.hpp" + +int main() { + MinecraftClient minecraft(App::CreatePlatform()); + + minecraft.run(); + + return 0; } \ No newline at end of file diff --git a/src/main_android.cpp b/src/main_android.cpp index dc47f35..31c33ac 100755 --- a/src/main_android.cpp +++ b/src/main_android.cpp @@ -1,224 +1,224 @@ -#include "App.h" -#include "AppPlatform_android.h" -#include - -// Horrible, I know. / A -#ifndef MAIN_CLASS -#include "main.cpp" -#endif - -#include - -// References for JNI -static pthread_mutex_t g_activityMutex = PTHREAD_MUTEX_INITIALIZER; -static jobject g_pActivity = 0; -static AppPlatform_android appPlatform; - -static void setupExternalPath(struct android_app* state, MAIN_CLASS* app) -{ - LOGI("setupExternalPath"); - - JNIEnv* env = state->activity->env; - state->activity->vm->AttachCurrentThread(&env, NULL); - - if (env) - { - LOGI("Environment exists"); - } - // try appspecific external directory first - jobject activity = state->activity->clazz; - jclass activityClass = env->GetObjectClass(activity); - jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); - - jobject file = NULL; - if (getExternalFilesDir != NULL) { - file = env->CallObjectMethod(activity, getExternalFilesDir, NULL); - } - - if (file == NULL) { - // Fallback to the legacy shared storage directory - jclass clazz = env->FindClass("android/os/Environment"); - jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;"); - if (env->ExceptionOccurred()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - file = env->CallStaticObjectMethod(clazz, method); - } - - if (!file) { - LOGI("Failed to get external storage file object, using current working dir"); - app->externalStoragePath = "."; - app->externalCacheStoragePath = "."; - return; - } - - jclass fileClass = env->GetObjectClass(file); - jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;"); - jobject pathString = env->CallObjectMethod(file, fileMethod); - - const char* str = env->GetStringUTFChars((jstring) pathString, NULL); - app->externalStoragePath = str; - app->externalCacheStoragePath = str; - LOGI("%s", str); - - // ensure the process working directory is set to a writable location - // on Android the default cwd may be '/' which isn't writable. By chdir'ing - // to the external storage path we make relative fopen calls (e.g. "options.txt") - // succeed and persist across launches, fixing the "options never save" bug. - if (chdir(str) != 0) { - LOGI("chdir to %s failed: %s", str, strerror(errno)); - } - - env->ReleaseStringUTFChars((jstring)pathString, str); - - // We're done, detach! - state->activity->vm->DetachCurrentThread(); -} - -extern "C" { -JNIEXPORT jint JNICALL - JNI_OnLoad( JavaVM * vm, void * reserved ) - { - pthread_mutex_init(&g_activityMutex, 0); - pthread_mutex_lock(&g_activityMutex); - - LOGI("Entering OnLoad %d\n", pthread_self()); - return appPlatform.init(vm); - } - - // Register/save a reference to the java main activity instance - JNIEXPORT void JNICALL - Java_com_mojang_minecraftpe_MainActivity_nativeRegisterThis(JNIEnv* env, jobject clazz) { - LOGI("@RegisterThis %d\n", pthread_self()); - g_pActivity = (jobject)env->NewGlobalRef( clazz ); - - pthread_mutex_unlock(&g_activityMutex); - } - - // Unregister/delete the reference to the java main activity instance - JNIEXPORT void JNICALL - Java_com_mojang_minecraftpe_MainActivity_nativeUnregisterThis(JNIEnv* env, jobject clazz) { - LOGI("@UnregisterThis %d\n", pthread_self()); - env->DeleteGlobalRef( g_pActivity ); - g_pActivity = 0; - - pthread_mutex_destroy(&g_activityMutex); - } - - JNIEXPORT void JNICALL - Java_com_mojang_minecraftpe_MainActivity_nativeStopThis(JNIEnv* env, jobject clazz) { - LOGI("Lost Focus!"); - } -} - -static void internal_process_input(struct android_app* app, struct android_poll_source* source) { - AInputEvent* event = NULL; - if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { - LOGV("New input event: type=%d\n", AInputEvent_getType(event)); - bool isBackButtonDown = AKeyEvent_getKeyCode(event) == AKEYCODE_BACK && AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN; - if(!(appPlatform.isKeyboardVisible() && isBackButtonDown)) { - if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { - return; - } - } - int32_t handled = 0; - if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); - AInputQueue_finishEvent(app->inputQueue, event, handled); - } else { - LOGE("Failure reading next input event: %s\n", strerror(errno)); - } -} - -void -android_main( struct android_app* state ) -{ - struct ENGINE engine; - - // Make sure glue isn't stripped. - app_dummy(); - - memset( (void*)&engine, 0, sizeof(engine) ); - state->userData = (void*)&engine; - state->onAppCmd = engine_handle_cmd; - state->onInputEvent = engine_handle_input; - state->destroyRequested = 0; - - pthread_mutex_lock(&g_activityMutex); - appPlatform.instance = g_pActivity; - pthread_mutex_unlock(&g_activityMutex); - - appPlatform.initConsts(); - - //LOGI("socket-stuff\n"); - //socketDesc = initSocket(1999); - - App* app = new MAIN_CLASS(); - - engine.userApp = app; - engine.app = state; - engine.is_inited = false; - engine.appContext.doRender = true; - engine.appContext.platform = &appPlatform; - - setupExternalPath(state, (MAIN_CLASS*)app); - - if( state->savedState != NULL ) - { - // We are starting with a previous saved state; restore from it. - app->loadState(state->savedState, state->savedStateSize); - } - - bool inited = false; - bool teardownPhase = false; - appPlatform._nativeActivity = state->activity; - // our 'main loop' - while( 1 ) - { - // Read all pending events. - int ident; - int events; - struct android_poll_source* source; - - while( (ident = ALooper_pollAll( 0, NULL, &events, (void**)&source) ) >= 0 ) - { - // Process this event. - // This will call the function pointer android_app::onInputEvent() which in our case is - // engine_handle_input() - if( source != NULL ) { - if(source->id == 2) { - // Back button is intercepted by the ime on android 4.1/4.2 resulting in the application stopping to respond. - internal_process_input( state, source ); - } else { - source->process( state, source ); - } - } - - } - // Check if we are exiting. - if( state->destroyRequested ) - { - //engine_term_display( &engine ); - delete app; - return; - } - - if (!inited && engine.is_inited) { - app->init(engine.appContext); - app->setSize(engine.width, engine.height); - inited = true; - } - - if (inited && engine.is_inited && engine.has_focus) { - app->update(); - } else { - sleepMs(50); - } - - if (!teardownPhase && app->wantToQuit()) { - teardownPhase = true; - LOGI("tearing down!"); - ANativeActivity_finish(state->activity); - } - } -} +#include "App.hpp" +#include "AppPlatform_android.hpp" +#include + +// Horrible, I know. / A +#ifndef MAIN_CLASS +#include "main.cpp" +#endif + +#include + +// References for JNI +static pthread_mutex_t g_activityMutex = PTHREAD_MUTEX_INITIALIZER; +static jobject g_pActivity = 0; +static AppPlatform_android appPlatform; + +static void setupExternalPath(struct android_app* state, MAIN_CLASS* app) +{ + LOGI("setupExternalPath"); + + JNIEnv* env = state->activity->env; + state->activity->vm->AttachCurrentThread(&env, NULL); + + if (env) + { + LOGI("Environment exists"); + } + // try appspecific external directory first + jobject activity = state->activity->clazz; + jclass activityClass = env->GetObjectClass(activity); + jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); + + jobject file = NULL; + if (getExternalFilesDir != NULL) { + file = env->CallObjectMethod(activity, getExternalFilesDir, NULL); + } + + if (file == NULL) { + // Fallback to the legacy shared storage directory + jclass clazz = env->FindClass("android/os/Environment"); + jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;"); + if (env->ExceptionOccurred()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + file = env->CallStaticObjectMethod(clazz, method); + } + + if (!file) { + LOGI("Failed to get external storage file object, using current working dir"); + app->externalStoragePath = "."; + app->externalCacheStoragePath = "."; + return; + } + + jclass fileClass = env->GetObjectClass(file); + jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;"); + jobject pathString = env->CallObjectMethod(file, fileMethod); + + const char* str = env->GetStringUTFChars((jstring) pathString, NULL); + app->externalStoragePath = str; + app->externalCacheStoragePath = str; + LOGI("%s", str); + + // ensure the process working directory is set to a writable location + // on Android the default cwd may be '/' which isn't writable. By chdir'ing + // to the external storage path we make relative fopen calls (e.g. "options.txt") + // succeed and persist across launches, fixing the "options never save" bug. + if (chdir(str) != 0) { + LOGI("chdir to %s failed: %s", str, strerror(errno)); + } + + env->ReleaseStringUTFChars((jstring)pathString, str); + + // We're done, detach! + state->activity->vm->DetachCurrentThread(); +} + +extern "C" { +JNIEXPORT jint JNICALL + JNI_OnLoad( JavaVM * vm, void * reserved ) + { + pthread_mutex_init(&g_activityMutex, 0); + pthread_mutex_lock(&g_activityMutex); + + LOGI("Entering OnLoad %d\n", pthread_self()); + return appPlatform.init(vm); + } + + // Register/save a reference to the java main activity instance + JNIEXPORT void JNICALL + Java_com_mojang_minecraftpe_MainActivity_nativeRegisterThis(JNIEnv* env, jobject clazz) { + LOGI("@RegisterThis %d\n", pthread_self()); + g_pActivity = (jobject)env->NewGlobalRef( clazz ); + + pthread_mutex_unlock(&g_activityMutex); + } + + // Unregister/delete the reference to the java main activity instance + JNIEXPORT void JNICALL + Java_com_mojang_minecraftpe_MainActivity_nativeUnregisterThis(JNIEnv* env, jobject clazz) { + LOGI("@UnregisterThis %d\n", pthread_self()); + env->DeleteGlobalRef( g_pActivity ); + g_pActivity = 0; + + pthread_mutex_destroy(&g_activityMutex); + } + + JNIEXPORT void JNICALL + Java_com_mojang_minecraftpe_MainActivity_nativeStopThis(JNIEnv* env, jobject clazz) { + LOGI("Lost Focus!"); + } +} + +static void internal_process_input(struct android_app* app, struct android_poll_source* source) { + AInputEvent* event = NULL; + if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { + LOGV("New input event: type=%d\n", AInputEvent_getType(event)); + bool isBackButtonDown = AKeyEvent_getKeyCode(event) == AKEYCODE_BACK && AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN; + if(!(appPlatform.isKeyboardVisible() && isBackButtonDown)) { + if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { + return; + } + } + int32_t handled = 0; + if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); + AInputQueue_finishEvent(app->inputQueue, event, handled); + } else { + LOGE("Failure reading next input event: %s\n", strerror(errno)); + } +} + +void +android_main( struct android_app* state ) +{ + struct ENGINE engine; + + // Make sure glue isn't stripped. + app_dummy(); + + memset( (void*)&engine, 0, sizeof(engine) ); + state->userData = (void*)&engine; + state->onAppCmd = engine_handle_cmd; + state->onInputEvent = engine_handle_input; + state->destroyRequested = 0; + + pthread_mutex_lock(&g_activityMutex); + appPlatform.instance = g_pActivity; + pthread_mutex_unlock(&g_activityMutex); + + appPlatform.initConsts(); + + //LOGI("socket-stuff\n"); + //socketDesc = initSocket(1999); + + App* app = new MAIN_CLASS(); + + engine.userApp = app; + engine.app = state; + engine.is_inited = false; + engine.appContext.doRender = true; + engine.appContext.platform = &appPlatform; + + setupExternalPath(state, (MAIN_CLASS*)app); + + if( state->savedState != NULL ) + { + // We are starting with a previous saved state; restore from it. + app->loadState(state->savedState, state->savedStateSize); + } + + bool inited = false; + bool teardownPhase = false; + appPlatform._nativeActivity = state->activity; + // our 'main loop' + while( 1 ) + { + // Read all pending events. + int ident; + int events; + struct android_poll_source* source; + + while( (ident = ALooper_pollAll( 0, NULL, &events, (void**)&source) ) >= 0 ) + { + // Process this event. + // This will call the function pointer android_app::onInputEvent() which in our case is + // engine_handle_input() + if( source != NULL ) { + if(source->id == 2) { + // Back button is intercepted by the ime on android 4.1/4.2 resulting in the application stopping to respond. + internal_process_input( state, source ); + } else { + source->process( state, source ); + } + } + + } + // Check if we are exiting. + if( state->destroyRequested ) + { + //engine_term_display( &engine ); + delete app; + return; + } + + if (!inited && engine.is_inited) { + app->init(engine.appContext); + app->setSize(engine.width, engine.height); + inited = true; + } + + if (inited && engine.is_inited && engine.has_focus) { + app->update(); + } else { + sleepMs(50); + } + + if (!teardownPhase && app->wantToQuit()) { + teardownPhase = true; + LOGI("tearing down!"); + ANativeActivity_finish(state->activity); + } + } +} diff --git a/src/main_android.h b/src/main_android.hpp similarity index 95% rename from src/main_android.h rename to src/main_android.hpp index c641936..e837bbf 100755 --- a/src/main_android.h +++ b/src/main_android.hpp @@ -1,589 +1,589 @@ -#ifndef MAIN_CLASS -#error "Error: MAIN_CLASS must have been defined to your main class (e.g. #define MAIN_CLASS MyApp)" -#endif - -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include - -#define TAG "MAIN_CLASS" - -#include "platform/log.h" -#include "platform/input/Controller.h" -#include "platform/input/Keyboard.h" -#include "platform/input/Mouse.h" -#include "platform/input/Multitouch.h" - -#include "EglConfigPrinter.h" - -const int BroadcastPort = 9991; - -/** - * Shared state for our app. - */ -struct ENGINE -{ - struct android_app* app; - - int render; - EGLDisplay display; - EGLSurface surface; - EGLContext context; - int width; - int height; - int has_focus; - App* userApp; - bool is_inited; - //bool init_gl; - struct AppContext appContext; -}; - -/** - * Initialize an EGL context for the current display. - */ -static -int -engine_init_display( struct ENGINE* engine ) -{ - LOGI("1) Initing display. Get display\n"); - // initialize OpenGL ES 2.0 and EGL - const EGLint attribs[] = \ - { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - //EGL_BUFFER_SIZE, 32, - //EGL_BLUE_SIZE, 5, - //EGL_GREEN_SIZE, 6, - //EGL_RED_SIZE, 5, - ///EGL_ALPHA_SIZE, 8, - //0x3098, 1, - //EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB, - //EGL_ALPHA_SIZE, 8,//5, - EGL_DEPTH_SIZE, 16, //8 - //EGL_STENCIL_SIZE, 8, - //EGL_DEPTH_SIZE, 16, - //EGL_CONFIG_CAVEAT, EGL_NONE, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, - EGL_NONE - }; - - EGLint w, h, format; - EGLint numConfigs; - EGLConfig config; - EGLSurface surface; - EGLContext context; - - EGLDisplay display = eglGetDisplay( EGL_DEFAULT_DISPLAY ); - - LOGI("2) Initialize egl\n"); - - if( display == NULL ) - { - LOGW( "!!! NO DISPLAY !!! eglGetDisplay" ); - } - - eglInitialize( display, 0, 0 ); - //EGLConfigPrinter::printAllConfigs(display); - LOGI("3) Choose config\n"); - - /* Here, the application chooses the configuration it desires. In this - * sample, we have a very simplified selection process, where we pick - * the first EGLConfig that matches our criteria */ - eglChooseConfig( display, attribs, &config, 1, &numConfigs ); - LOGI("4) Get config attributes\n"); - - /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is - * guaranteed to be accepted by ANativeWindow_setBuffersGeometry(). - * As soon as we picked a EGLConfig, we can safely reconfigure the - * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */ - eglGetConfigAttrib( display, config, EGL_NATIVE_VISUAL_ID, &format ); - LOGI("5) Choose config, set window geometry\n"); - - ANativeWindow_setBuffersGeometry( engine->app->window, 0, 0, format ); - - eglChooseConfig( display, attribs, NULL, 0, &numConfigs ); - - EGLConfig* configs = new EGLConfig[numConfigs]; - eglChooseConfig(display, attribs, configs, numConfigs, &numConfigs); - - for (int i = 0; i < numConfigs; ++i) { - EGLSurface surf = eglCreateWindowSurface( display, configs[i], engine->app->window, NULL ); - if (surf != EGL_NO_SURFACE) { - config = configs[i]; - surface = surf; - break; - } - } - - delete[] configs; - - - //surface = eglCreateWindowSurface( display, config, engine->app->window, NULL ); - LOGI("6) Creating context\n"); - - context = eglCreateContext( display, config, NULL, NULL ); - LOGI("7) Make current\n"); - - if( eglMakeCurrent( display, surface, surface, context ) == EGL_FALSE ) - { - LOGW("Unable to eglMakeCurrent"); - return -1; - } - LOGI("8) Query stats and set values\n"); - - eglQuerySurface( display, surface, EGL_WIDTH, &w ); - eglQuerySurface( display, surface, EGL_HEIGHT, &h ); - - if (w < h) { - int tmp = w; - w = h; - h = tmp; - } - - engine->display = engine->appContext.display = display; - engine->context = engine->appContext.context = context; - engine->surface = engine->appContext.surface = surface; - engine->width = w; - engine->height = h; - //Minecraft::width = w; - //Minecraft::height = h; - LOGI("9) Set-up viewport\n"); - - // Initialize GL state. - glViewport( 0, 0, w, h ); - LOGI("X) Graphics set-up finished!\n"); - - // Don't need to reload graphics first time - if (engine->is_inited) { - engine->userApp->onGraphicsReset(engine->appContext); - engine->userApp->setSize(w, h); - } - - eglSwapInterval(eglGetCurrentDisplay(), 2); - engine->is_inited = true; - - return 0; -} - -/** - * Tear down the EGL context currently associated with the display. - */ -static -void -engine_term_display( struct ENGINE* engine ) -{ - //LOGI( "engine_term_display" ); - - if( engine->display != EGL_NO_DISPLAY ) - { - eglMakeCurrent( engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); - - if( engine->context != EGL_NO_CONTEXT ) - { - eglDestroyContext( engine->display, engine->context ); - } - - if( engine->surface != EGL_NO_SURFACE ) - { - eglDestroySurface( engine->display, engine->surface ); - } - - eglTerminate( engine->display ); - } - - engine->display = EGL_NO_DISPLAY; - engine->context = EGL_NO_CONTEXT; - engine->surface = EGL_NO_SURFACE; -} - -static int socketDesc; - -static int broadcastData(int port, void* msg, int msgLen) -{ - struct sockaddr_in broadcastAddr; - - broadcastAddr.sin_family = AF_INET; - broadcastAddr.sin_port = htons(port); - broadcastAddr.sin_addr.s_addr = inet_addr("192.168.0.255"); - - return sendto(socketDesc, msg, msgLen, 0, (struct sockaddr*)&broadcastAddr, sizeof(broadcastAddr)); -} - -static void mouseDown(int buttonId, int x, int y) { - int msg[] = {buttonId, 0, x, y}; - //broadcastData(BroadcastPort, msg, sizeof(msg)); - - Mouse::feed(buttonId, 1, x, y); -} - -static void mouseUp(int buttonId, int x, int y) { - int msg[] = {buttonId, 0, x, y}; - //broadcastData(BroadcastPort, msg, sizeof(msg)); - - Mouse::feed(buttonId, 0, x, y); -} - -static void mouseMove(int x, int y) { - int msg[] = {0, 0, x, y}; - //broadcastData(BroadcastPort, msg, sizeof(msg)); - - Mouse::feed(0, 0, x, y); -} - -static void pointerDown(int pointerId, int x, int y) { - Multitouch::feed(1, 1, x, y, pointerId); -} -static void pointerUp(int pointerId, int x, int y) { - Multitouch::feed(1, 0, x, y, pointerId); -} -static void pointerMove(int pointerId, int x, int y) { - Multitouch::feed(0, 0, x, y, pointerId); -} - -inline static const float padXtoSigned(int x) { - return (x - 483.0f) * 0.002070393374741201f; -} -inline static const float padYtoSigned(int y) { - return (y - 180.0f) * 0.005555555555555556f; -} - -static void trackpadPress(int x, int y) { - Controller::feed(1, Controller::STATE_TOUCH, padXtoSigned(x), padYtoSigned(y)); -} -static void trackpadMove(int x, int y) { - Controller::feed(1, Controller::STATE_MOVE, padXtoSigned(x), padYtoSigned(y)); -} -static void trackpadRelease(int x, int y) { - Controller::feed(1, Controller::STATE_RELEASE, padXtoSigned(x), padYtoSigned(y)); -} - -static int isTouchpadTouched = 0; - -static -int32_t -handle_xperia_input( struct android_app* app, AInputEvent* event ) -{ - if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION ) - { - struct ENGINE* engine = (struct ENGINE*)app->userData; - int nPointerCount = AMotionEvent_getPointerCount( event ); - int nSourceId = AInputEvent_getSource( event ); - int nAction = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction( event ); - int isTrackpad =(nSourceId == AINPUT_SOURCE_TOUCHPAD); - int n; - - for( n = 0 ; n < nPointerCount ; ++n ) - { - int nPointerId = AMotionEvent_getPointerId( event, n ); - - // We don't care about secondary pointers right now - if( !isTrackpad ) { - if (nAction == AMOTION_EVENT_ACTION_POINTER_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_UP ) - continue; - } - - int x = AMotionEvent_getX( event, n ); - int y = AMotionEvent_getY( event, n ); - - if( nAction == AMOTION_EVENT_ACTION_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_DOWN ) { - //LOGI("action down %d\n", isTrackpad); - if (isTrackpad) { - trackpadPress(x, y); - } else { - mouseDown(1, x, y); - //LOGI("mouse-pointer down"); - } - } - else if( nAction == AMOTION_EVENT_ACTION_UP || nAction == AMOTION_EVENT_ACTION_POINTER_UP /*|| nAction == AMOTION_EVENT_ACTION_CANCEL*/ ) { - //LOGI("action up %d\n", isTrackpad); - if (isTrackpad) { - //LOGI("trackpad-up\n"); - trackpadRelease(x, y); - } - else { - //LOGI("mouse-pointer up\n"); - mouseUp(1, x, y); - } - } else if (nAction == AMOTION_EVENT_ACTION_MOVE ) { - if (isTrackpad) - trackpadMove(x, y); - else - mouseMove(x, y); - } - } - return 1; - } -} -static int convertAndroidKeyCodeToWindowsKeyCode(int keyCode) { - switch(keyCode) { - /* - case 29: return Keyboard::KEY_A; - case 30: return Keyboard::KEY_B; - case 31: return Keyboard::KEY_C; - case 32: return Keyboard::KEY_D; - case 33: return Keyboard::KEY_E; - case 34: return Keyboard::KEY_F; - case 35: return Keyboard::KEY_G; - case 36: return Keyboard::KEY_H; - case 37: return Keyboard::KEY_I; - case 38: return Keyboard::KEY_J; - case 39: return Keyboard::KEY_K; - case 40: return Keyboard::KEY_L; - case 41: return Keyboard::KEY_M; - case 42: return Keyboard::KEY_N; - case 43: return Keyboard::KEY_O; - case 44: return Keyboard::KEY_P; - case 45: return Keyboard::KEY_Q; - case 46: return Keyboard::KEY_R; - case 47: return Keyboard::KEY_S; - case 48: return Keyboard::KEY_T; - case 49: return Keyboard::KEY_U; - case 50: return Keyboard::KEY_V; - case 51: return Keyboard::KEY_W; - case 52: return Keyboard::KEY_X; - case 53: return Keyboard::KEY_Y; - case 54: return Keyboard::KEY_Z; - */ - case 67: return Keyboard::KEY_BACKSPACE; - case 66: return Keyboard::KEY_RETURN; -// case 62: return Keyboard::KEY_SPACE; - default: return 0; - } -} -static -int32_t -handle_keyboard_input( struct android_app* app, AInputEvent* event ) -{ - if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY ) - { - struct ENGINE* engine = (struct ENGINE*)app->userData; - bool isDown = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN; - int keyCode = AKeyEvent_getKeyCode(event); - int metaState = AKeyEvent_getMetaState(event); - int deviceId = AInputEvent_getDeviceId(event); - bool pressedBack = (keyCode == 4) && ((AKeyEvent_getMetaState(event) & AMETA_ALT_ON) == 0); - bool isRepeat = AKeyEvent_getRepeatCount(event) > 0; - if (!isRepeat){ - //int scanCode = AKeyEvent_getScanCode(event); - //LOGI("key-%s : %d", isDown?"key-down":"key-up", keyCode); - //LOGI("getId: %d\n", AInputEvent_getDeviceId(event)); - //LOGI("flags: %d\n", AKeyEvent_getFlags(event)); - //LOGI("scancode: %d\n", AKeyEvent_getScanCode(event)); - - //unsigned char msg[2] = {(unsigned char)(keyCode), (unsigned char)(isDown)}; - //broadcastData(BroadcastPort, msg, 2); - LOGW("New keycode: %d", keyCode); - if (!pressedBack) { - - int key = convertAndroidKeyCodeToWindowsKeyCode(keyCode); - if (key == 0) key = keyCode; - Keyboard::feed(key, isDown); - if(isDown) { - int uniChar = ((struct ENGINE*)app->userData)->appContext.platform->getKeyFromKeyCode(keyCode, metaState, deviceId); - char charI = (char)uniChar; - LOGW("Unichar: %d", uniChar); - if(charI > 31) { - LOGW("New Char %c[%d]", charI, uniChar); - Keyboard::feedText((char)charI); - } - } - } - } - if (pressedBack) - { - if (!isRepeat && !engine->userApp->handleBack(isDown)) - { - //LOGI("Returning 0 from engine_handle_input\n"); - return 0; - } - return 1; - } - - bool volumeButton = (keyCode == 24) || (keyCode == 25); - bool handled = !pressedBack && !volumeButton; - return handled; - } - - return 0; -} - -static -int32_t -handle_touch_input( struct android_app* app, AInputEvent* event ) -{ - if( AInputEvent_getType(event) != AINPUT_EVENT_TYPE_MOTION ) - return 0; - - int nSourceId = AInputEvent_getSource( event ); - if (nSourceId == AINPUT_SOURCE_TOUCHPAD) - return 0; - - struct ENGINE* engine = (struct ENGINE*)app->userData; - - int fullAction = AMotionEvent_getAction( event ); - int nAction = AMOTION_EVENT_ACTION_MASK & fullAction; - int pointerIndex = (fullAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - int pointerId = AMotionEvent_getPointerId(event, pointerIndex); - int x = (int)AMotionEvent_getX(event, pointerIndex); - int y = (int)AMotionEvent_getY(event, pointerIndex); - - //LOGI("xy:\t%d, %d\n", x, y); - - switch (nAction) { - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_DOWN: - mouseDown(1, x, y); - Multitouch::feed(1, 1, x, y, pointerId); - break; - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_UP: - mouseUp(1, x, y); - Multitouch::feed(1, 0, x, y, pointerId); - break; - case AMOTION_EVENT_ACTION_MOVE: - int pcount = AMotionEvent_getPointerCount(event); - for (int i = 0; i < pcount; ++i) { - int pp = AMotionEvent_getPointerId(event, i); // @attn wtf? - float xx = AMotionEvent_getX(event, i); - float yy = AMotionEvent_getY(event, i); - // System.err.println(" " + p + " @ " + x + ", " + y); - //LOGI("> %.2f, %.2f\n", xx, yy); - mouseMove(xx, yy); - Multitouch::feed(0, 0, xx, yy, pp); - } - break; - } - return 0; -} - -/** - * Process the next input event. - */ -static -int32_t -engine_handle_input( struct android_app* app, AInputEvent* event ) -{ - if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) - return handle_keyboard_input(app, event); - - const bool isTouchscreen = ((struct ENGINE*)app->userData)->appContext.platform->supportsTouchscreen();; - if (isTouchscreen) { - return handle_touch_input(app, event); - } else { - // We only have xperia by now, but in the best of worlds - // one function will feed all controllers - return handle_xperia_input(app, event); - } -} - -/** - * Process the next main command. - */ -static -void -engine_handle_cmd( struct android_app* app, int32_t cmd ) -{ - struct ENGINE* engine = (struct ENGINE*)app->userData; - switch( cmd ) - { - case APP_CMD_SAVE_STATE: - { - //LOGI("save-state\n"); - // The system has asked us to save our current state. Do so if needed - - // query first - void* savedState = 0; - int savedStateSize = 0; - engine->userApp->saveState(&savedState, &savedStateSize); - - // Seems OK - save - if (savedStateSize > 0) { - app->savedState = savedState; - app->savedStateSize = savedStateSize; - } - } - break; - - case APP_CMD_INIT_WINDOW: - //LOGI("init-window\n"); - // The window is being shown, get it ready. - if( engine->app->window != NULL ) - { - engine_init_display( engine ); - //engine->has_focus = 1; - // LOGI("has-inited-display\n"); - //ANativeWindow_setBuffersGeometry(engine->app->window, engine->width, engine->height, 1); - } - break; - - case APP_CMD_TERM_WINDOW: - //LOGI("term-window\n"); - // The window is being hidden or closed, clean it up. - engine_term_display( engine ); - break; - - case APP_CMD_GAINED_FOCUS: - //LOGI("gained-focus\n"); - //engine->has_focus = 1; - break; - - case APP_CMD_LOST_FOCUS: - //engine->has_focus = 0; - //engine_draw_frame( engine ); - break; - - case APP_CMD_PAUSE: - engine->has_focus = 0; - break; - case APP_CMD_RESUME: - engine->has_focus = 1; - break; - default: - //LOGI("unknown: %d\n", cmd); - break; - } -} - -static int initSocket(int port) -{ - int s = socket(PF_INET, SOCK_DGRAM, 0); - - struct addrinfo hints; - struct addrinfo *res; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_PASSIVE; - - getaddrinfo("192.168.0.110", "1999", &hints, &res); // ... - - int b = bind(s, res->ai_addr, res->ai_addrlen); - - int broadcast = 1; - if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast, - sizeof(broadcast)) == -1) { - perror("setsockopt (SO_BROADCAST)"); - return 0; - } - - return s; -} - -/** - * This is the main entry point of a native application that is using - * android_native_app_glue. It runs in its own thread, with its own - * event loop for receiving input events and doing other things (rendering). - */ -void -android_main( struct android_app* state ); +#ifndef MAIN_CLASS +#error "Error: MAIN_CLASS must have been defined to your main class (e.g. #define MAIN_CLASS MyApp)" +#endif + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#define TAG "MAIN_CLASS" + +#include "platform/log.hpp" +#include "platform/input/Controller.hpp" +#include "platform/input/Keyboard.hpp" +#include "platform/input/Mouse.hpp" +#include "platform/input/Multitouch.hpp" + +#include "EglConfigPrinter.hpp" + +const int BroadcastPort = 9991; + +/** + * Shared state for our app. + */ +struct ENGINE +{ + struct android_app* app; + + int render; + EGLDisplay display; + EGLSurface surface; + EGLContext context; + int width; + int height; + int has_focus; + App* userApp; + bool is_inited; + //bool init_gl; + struct AppContext appContext; +}; + +/** + * Initialize an EGL context for the current display. + */ +static +int +engine_init_display( struct ENGINE* engine ) +{ + LOGI("1) Initing display. Get display\n"); + // initialize OpenGL ES 2.0 and EGL + const EGLint attribs[] = \ + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + //EGL_BUFFER_SIZE, 32, + //EGL_BLUE_SIZE, 5, + //EGL_GREEN_SIZE, 6, + //EGL_RED_SIZE, 5, + ///EGL_ALPHA_SIZE, 8, + //0x3098, 1, + //EGL_TRANSPARENT_TYPE, EGL_TRANSPARENT_RGB, + //EGL_ALPHA_SIZE, 8,//5, + EGL_DEPTH_SIZE, 16, //8 + //EGL_STENCIL_SIZE, 8, + //EGL_DEPTH_SIZE, 16, + //EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, + EGL_NONE + }; + + EGLint w, h, format; + EGLint numConfigs; + EGLConfig config; + EGLSurface surface; + EGLContext context; + + EGLDisplay display = eglGetDisplay( EGL_DEFAULT_DISPLAY ); + + LOGI("2) Initialize egl\n"); + + if( display == NULL ) + { + LOGW( "!!! NO DISPLAY !!! eglGetDisplay" ); + } + + eglInitialize( display, 0, 0 ); + //EGLConfigPrinter::printAllConfigs(display); + LOGI("3) Choose config\n"); + + /* Here, the application chooses the configuration it desires. In this + * sample, we have a very simplified selection process, where we pick + * the first EGLConfig that matches our criteria */ + eglChooseConfig( display, attribs, &config, 1, &numConfigs ); + LOGI("4) Get config attributes\n"); + + /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is + * guaranteed to be accepted by ANativeWindow_setBuffersGeometry(). + * As soon as we picked a EGLConfig, we can safely reconfigure the + * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */ + eglGetConfigAttrib( display, config, EGL_NATIVE_VISUAL_ID, &format ); + LOGI("5) Choose config, set window geometry\n"); + + ANativeWindow_setBuffersGeometry( engine->app->window, 0, 0, format ); + + eglChooseConfig( display, attribs, NULL, 0, &numConfigs ); + + EGLConfig* configs = new EGLConfig[numConfigs]; + eglChooseConfig(display, attribs, configs, numConfigs, &numConfigs); + + for (int i = 0; i < numConfigs; ++i) { + EGLSurface surf = eglCreateWindowSurface( display, configs[i], engine->app->window, NULL ); + if (surf != EGL_NO_SURFACE) { + config = configs[i]; + surface = surf; + break; + } + } + + delete[] configs; + + + //surface = eglCreateWindowSurface( display, config, engine->app->window, NULL ); + LOGI("6) Creating context\n"); + + context = eglCreateContext( display, config, NULL, NULL ); + LOGI("7) Make current\n"); + + if( eglMakeCurrent( display, surface, surface, context ) == EGL_FALSE ) + { + LOGW("Unable to eglMakeCurrent"); + return -1; + } + LOGI("8) Query stats and set values\n"); + + eglQuerySurface( display, surface, EGL_WIDTH, &w ); + eglQuerySurface( display, surface, EGL_HEIGHT, &h ); + + if (w < h) { + int tmp = w; + w = h; + h = tmp; + } + + engine->display = engine->appContext.display = display; + engine->context = engine->appContext.context = context; + engine->surface = engine->appContext.surface = surface; + engine->width = w; + engine->height = h; + //Minecraft::width = w; + //Minecraft::height = h; + LOGI("9) Set-up viewport\n"); + + // Initialize GL state. + glViewport( 0, 0, w, h ); + LOGI("X) Graphics set-up finished!\n"); + + // Don't need to reload graphics first time + if (engine->is_inited) { + engine->userApp->onGraphicsReset(engine->appContext); + engine->userApp->setSize(w, h); + } + + eglSwapInterval(eglGetCurrentDisplay(), 2); + engine->is_inited = true; + + return 0; +} + +/** + * Tear down the EGL context currently associated with the display. + */ +static +void +engine_term_display( struct ENGINE* engine ) +{ + //LOGI( "engine_term_display" ); + + if( engine->display != EGL_NO_DISPLAY ) + { + eglMakeCurrent( engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); + + if( engine->context != EGL_NO_CONTEXT ) + { + eglDestroyContext( engine->display, engine->context ); + } + + if( engine->surface != EGL_NO_SURFACE ) + { + eglDestroySurface( engine->display, engine->surface ); + } + + eglTerminate( engine->display ); + } + + engine->display = EGL_NO_DISPLAY; + engine->context = EGL_NO_CONTEXT; + engine->surface = EGL_NO_SURFACE; +} + +static int socketDesc; + +static int broadcastData(int port, void* msg, int msgLen) +{ + struct sockaddr_in broadcastAddr; + + broadcastAddr.sin_family = AF_INET; + broadcastAddr.sin_port = htons(port); + broadcastAddr.sin_addr.s_addr = inet_addr("192.168.0.255"); + + return sendto(socketDesc, msg, msgLen, 0, (struct sockaddr*)&broadcastAddr, sizeof(broadcastAddr)); +} + +static void mouseDown(int buttonId, int x, int y) { + int msg[] = {buttonId, 0, x, y}; + //broadcastData(BroadcastPort, msg, sizeof(msg)); + + Mouse::feed(buttonId, 1, x, y); +} + +static void mouseUp(int buttonId, int x, int y) { + int msg[] = {buttonId, 0, x, y}; + //broadcastData(BroadcastPort, msg, sizeof(msg)); + + Mouse::feed(buttonId, 0, x, y); +} + +static void mouseMove(int x, int y) { + int msg[] = {0, 0, x, y}; + //broadcastData(BroadcastPort, msg, sizeof(msg)); + + Mouse::feed(0, 0, x, y); +} + +static void pointerDown(int pointerId, int x, int y) { + Multitouch::feed(1, 1, x, y, pointerId); +} +static void pointerUp(int pointerId, int x, int y) { + Multitouch::feed(1, 0, x, y, pointerId); +} +static void pointerMove(int pointerId, int x, int y) { + Multitouch::feed(0, 0, x, y, pointerId); +} + +inline static const float padXtoSigned(int x) { + return (x - 483.0f) * 0.002070393374741201f; +} +inline static const float padYtoSigned(int y) { + return (y - 180.0f) * 0.005555555555555556f; +} + +static void trackpadPress(int x, int y) { + Controller::feed(1, Controller::STATE_TOUCH, padXtoSigned(x), padYtoSigned(y)); +} +static void trackpadMove(int x, int y) { + Controller::feed(1, Controller::STATE_MOVE, padXtoSigned(x), padYtoSigned(y)); +} +static void trackpadRelease(int x, int y) { + Controller::feed(1, Controller::STATE_RELEASE, padXtoSigned(x), padYtoSigned(y)); +} + +static int isTouchpadTouched = 0; + +static +int32_t +handle_xperia_input( struct android_app* app, AInputEvent* event ) +{ + if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION ) + { + struct ENGINE* engine = (struct ENGINE*)app->userData; + int nPointerCount = AMotionEvent_getPointerCount( event ); + int nSourceId = AInputEvent_getSource( event ); + int nAction = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction( event ); + int isTrackpad =(nSourceId == AINPUT_SOURCE_TOUCHPAD); + int n; + + for( n = 0 ; n < nPointerCount ; ++n ) + { + int nPointerId = AMotionEvent_getPointerId( event, n ); + + // We don't care about secondary pointers right now + if( !isTrackpad ) { + if (nAction == AMOTION_EVENT_ACTION_POINTER_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_UP ) + continue; + } + + int x = AMotionEvent_getX( event, n ); + int y = AMotionEvent_getY( event, n ); + + if( nAction == AMOTION_EVENT_ACTION_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_DOWN ) { + //LOGI("action down %d\n", isTrackpad); + if (isTrackpad) { + trackpadPress(x, y); + } else { + mouseDown(1, x, y); + //LOGI("mouse-pointer down"); + } + } + else if( nAction == AMOTION_EVENT_ACTION_UP || nAction == AMOTION_EVENT_ACTION_POINTER_UP /*|| nAction == AMOTION_EVENT_ACTION_CANCEL*/ ) { + //LOGI("action up %d\n", isTrackpad); + if (isTrackpad) { + //LOGI("trackpad-up\n"); + trackpadRelease(x, y); + } + else { + //LOGI("mouse-pointer up\n"); + mouseUp(1, x, y); + } + } else if (nAction == AMOTION_EVENT_ACTION_MOVE ) { + if (isTrackpad) + trackpadMove(x, y); + else + mouseMove(x, y); + } + } + return 1; + } +} +static int convertAndroidKeyCodeToWindowsKeyCode(int keyCode) { + switch(keyCode) { + /* + case 29: return Keyboard::KEY_A; + case 30: return Keyboard::KEY_B; + case 31: return Keyboard::KEY_C; + case 32: return Keyboard::KEY_D; + case 33: return Keyboard::KEY_E; + case 34: return Keyboard::KEY_F; + case 35: return Keyboard::KEY_G; + case 36: return Keyboard::KEY_H; + case 37: return Keyboard::KEY_I; + case 38: return Keyboard::KEY_J; + case 39: return Keyboard::KEY_K; + case 40: return Keyboard::KEY_L; + case 41: return Keyboard::KEY_M; + case 42: return Keyboard::KEY_N; + case 43: return Keyboard::KEY_O; + case 44: return Keyboard::KEY_P; + case 45: return Keyboard::KEY_Q; + case 46: return Keyboard::KEY_R; + case 47: return Keyboard::KEY_S; + case 48: return Keyboard::KEY_T; + case 49: return Keyboard::KEY_U; + case 50: return Keyboard::KEY_V; + case 51: return Keyboard::KEY_W; + case 52: return Keyboard::KEY_X; + case 53: return Keyboard::KEY_Y; + case 54: return Keyboard::KEY_Z; + */ + case 67: return Keyboard::KEY_BACKSPACE; + case 66: return Keyboard::KEY_RETURN; +// case 62: return Keyboard::KEY_SPACE; + default: return 0; + } +} +static +int32_t +handle_keyboard_input( struct android_app* app, AInputEvent* event ) +{ + if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY ) + { + struct ENGINE* engine = (struct ENGINE*)app->userData; + bool isDown = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN; + int keyCode = AKeyEvent_getKeyCode(event); + int metaState = AKeyEvent_getMetaState(event); + int deviceId = AInputEvent_getDeviceId(event); + bool pressedBack = (keyCode == 4) && ((AKeyEvent_getMetaState(event) & AMETA_ALT_ON) == 0); + bool isRepeat = AKeyEvent_getRepeatCount(event) > 0; + if (!isRepeat){ + //int scanCode = AKeyEvent_getScanCode(event); + //LOGI("key-%s : %d", isDown?"key-down":"key-up", keyCode); + //LOGI("getId: %d\n", AInputEvent_getDeviceId(event)); + //LOGI("flags: %d\n", AKeyEvent_getFlags(event)); + //LOGI("scancode: %d\n", AKeyEvent_getScanCode(event)); + + //unsigned char msg[2] = {(unsigned char)(keyCode), (unsigned char)(isDown)}; + //broadcastData(BroadcastPort, msg, 2); + LOGW("New keycode: %d", keyCode); + if (!pressedBack) { + + int key = convertAndroidKeyCodeToWindowsKeyCode(keyCode); + if (key == 0) key = keyCode; + Keyboard::feed(key, isDown); + if(isDown) { + int uniChar = ((struct ENGINE*)app->userData)->appContext.platform->getKeyFromKeyCode(keyCode, metaState, deviceId); + char charI = (char)uniChar; + LOGW("Unichar: %d", uniChar); + if(charI > 31) { + LOGW("New Char %c[%d]", charI, uniChar); + Keyboard::feedText((char)charI); + } + } + } + } + if (pressedBack) + { + if (!isRepeat && !engine->userApp->handleBack(isDown)) + { + //LOGI("Returning 0 from engine_handle_input\n"); + return 0; + } + return 1; + } + + bool volumeButton = (keyCode == 24) || (keyCode == 25); + bool handled = !pressedBack && !volumeButton; + return handled; + } + + return 0; +} + +static +int32_t +handle_touch_input( struct android_app* app, AInputEvent* event ) +{ + if( AInputEvent_getType(event) != AINPUT_EVENT_TYPE_MOTION ) + return 0; + + int nSourceId = AInputEvent_getSource( event ); + if (nSourceId == AINPUT_SOURCE_TOUCHPAD) + return 0; + + struct ENGINE* engine = (struct ENGINE*)app->userData; + + int fullAction = AMotionEvent_getAction( event ); + int nAction = AMOTION_EVENT_ACTION_MASK & fullAction; + int pointerIndex = (fullAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; + int pointerId = AMotionEvent_getPointerId(event, pointerIndex); + int x = (int)AMotionEvent_getX(event, pointerIndex); + int y = (int)AMotionEvent_getY(event, pointerIndex); + + //LOGI("xy:\t%d, %d\n", x, y); + + switch (nAction) { + case AMOTION_EVENT_ACTION_POINTER_DOWN: + case AMOTION_EVENT_ACTION_DOWN: + mouseDown(1, x, y); + Multitouch::feed(1, 1, x, y, pointerId); + break; + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_UP: + mouseUp(1, x, y); + Multitouch::feed(1, 0, x, y, pointerId); + break; + case AMOTION_EVENT_ACTION_MOVE: + int pcount = AMotionEvent_getPointerCount(event); + for (int i = 0; i < pcount; ++i) { + int pp = AMotionEvent_getPointerId(event, i); // @attn wtf? + float xx = AMotionEvent_getX(event, i); + float yy = AMotionEvent_getY(event, i); + // System.err.println(" " + p + " @ " + x + ", " + y); + //LOGI("> %.2f, %.2f\n", xx, yy); + mouseMove(xx, yy); + Multitouch::feed(0, 0, xx, yy, pp); + } + break; + } + return 0; +} + +/** + * Process the next input event. + */ +static +int32_t +engine_handle_input( struct android_app* app, AInputEvent* event ) +{ + if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) + return handle_keyboard_input(app, event); + + const bool isTouchscreen = ((struct ENGINE*)app->userData)->appContext.platform->supportsTouchscreen();; + if (isTouchscreen) { + return handle_touch_input(app, event); + } else { + // We only have xperia by now, but in the best of worlds + // one function will feed all controllers + return handle_xperia_input(app, event); + } +} + +/** + * Process the next main command. + */ +static +void +engine_handle_cmd( struct android_app* app, int32_t cmd ) +{ + struct ENGINE* engine = (struct ENGINE*)app->userData; + switch( cmd ) + { + case APP_CMD_SAVE_STATE: + { + //LOGI("save-state\n"); + // The system has asked us to save our current state. Do so if needed + + // query first + void* savedState = 0; + int savedStateSize = 0; + engine->userApp->saveState(&savedState, &savedStateSize); + + // Seems OK - save + if (savedStateSize > 0) { + app->savedState = savedState; + app->savedStateSize = savedStateSize; + } + } + break; + + case APP_CMD_INIT_WINDOW: + //LOGI("init-window\n"); + // The window is being shown, get it ready. + if( engine->app->window != NULL ) + { + engine_init_display( engine ); + //engine->has_focus = 1; + // LOGI("has-inited-display\n"); + //ANativeWindow_setBuffersGeometry(engine->app->window, engine->width, engine->height, 1); + } + break; + + case APP_CMD_TERM_WINDOW: + //LOGI("term-window\n"); + // The window is being hidden or closed, clean it up. + engine_term_display( engine ); + break; + + case APP_CMD_GAINED_FOCUS: + //LOGI("gained-focus\n"); + //engine->has_focus = 1; + break; + + case APP_CMD_LOST_FOCUS: + //engine->has_focus = 0; + //engine_draw_frame( engine ); + break; + + case APP_CMD_PAUSE: + engine->has_focus = 0; + break; + case APP_CMD_RESUME: + engine->has_focus = 1; + break; + default: + //LOGI("unknown: %d\n", cmd); + break; + } +} + +static int initSocket(int port) +{ + int s = socket(PF_INET, SOCK_DGRAM, 0); + + struct addrinfo hints; + struct addrinfo *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; + + getaddrinfo("192.168.0.110", "1999", &hints, &res); // ... + + int b = bind(s, res->ai_addr, res->ai_addrlen); + + int broadcast = 1; + if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &broadcast, + sizeof(broadcast)) == -1) { + perror("setsockopt (SO_BROADCAST)"); + return 0; + } + + return s; +} + +/** + * This is the main entry point of a native application that is using + * android_native_app_glue. It runs in its own thread, with its own + * event loop for receiving input events and doing other things (rendering). + */ +void +android_main( struct android_app* state ); diff --git a/src/main_android_java.cpp b/src/main_android_java.cpp index c89ae03..aab7638 100755 --- a/src/main_android_java.cpp +++ b/src/main_android_java.cpp @@ -1,271 +1,271 @@ -#include "App.h" -#include "AppPlatform_android.h" - -// JNI keycode constants -#include - -//#include "main_android_java.h" -#include "platform/input/Multitouch.h" -#include -#include - -// Horrible, I know. / A -#ifndef MAIN_CLASS -#include "main.cpp" -#endif - - -// References for JNI -static jobject g_pActivity = 0; -static AppPlatform_android appPlatform; - -static void setupExternalPath(JNIEnv* env, MAIN_CLASS* app) -{ - //JVMAttacher ta(vm); - //JNIEnv* env = ta.getEnv(); - - LOGI("setupExternalPath"); - - if (env) - { - LOGI("Environment exists"); - } - // try appspecific external directory first - jobject activity = g_pActivity; - jclass activityClass = env->GetObjectClass(activity); - jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); - - jobject file = NULL; - if (getExternalFilesDir != NULL) { - file = env->CallObjectMethod(activity, getExternalFilesDir, NULL); - } - - if (file == NULL) { - // Fallback to the legacy shared storage directory - jclass clazz = env->FindClass("android/os/Environment"); - jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;"); - if (env->ExceptionOccurred()) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } - file = env->CallStaticObjectMethod(clazz, method); - } - - if (!file) { - LOGI("Failed to get external storage file object, using current working dir"); - app->externalStoragePath = "."; - app->externalCacheStoragePath = "."; - return; - } - - jclass fileClass = env->GetObjectClass(file); - jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;"); - jobject pathString = env->CallObjectMethod(file, fileMethod); - - const char* str = env->GetStringUTFChars((jstring) pathString, NULL); - app->externalStoragePath = str; - app->externalCacheStoragePath = str; - LOGI("%s", str); - - // same fix as the native entry point: make sure cwd is writable - if (chdir(str) != 0) { - LOGI("chdir to %s failed: %s", str, strerror(errno)); - } - - env->ReleaseStringUTFChars((jstring)pathString, str); -} - -static void pointerDown(int pointerId, int x, int y) { - Multitouch::feed(1, 1, x, y, pointerId); -} -static void pointerUp(int pointerId, int x, int y) { - Multitouch::feed(1, 0, x, y, pointerId); -} -static void pointerMove(int pointerId, int x, int y) { - Multitouch::feed(0, 0, x, y, pointerId); -} - - -static App* gApp = 0; -static AppContext gContext; -static bool g_inNativeOnCreate = false; - -extern "C" { -JNIEXPORT jint JNICALL -JNI_OnLoad( JavaVM * vm, void * reserved ) -{ - LOGI("Entering OnLoad\n"); - return appPlatform.init(vm); -} - -// Register/save a reference to the java main activity instance -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeRegisterThis(JNIEnv* env, jobject clazz) { - LOGI("@RegisterThis\n"); - g_pActivity = (jobject)env->NewGlobalRef( clazz ); -} - -// Unregister/delete the reference to the java main activity instance -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeUnregisterThis(JNIEnv* env, jobject clazz) { - LOGI("@UnregisterThis\n"); - env->DeleteGlobalRef( g_pActivity ); -} - -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeOnCreate(JNIEnv* env, jobject thiz, jint screenWidth, jint screenHeight) { - LOGI("@nativeOnCreate w=%d h=%d\n", (int)screenWidth, (int)screenHeight); - g_inNativeOnCreate = true; - - appPlatform.instance = g_pActivity; - appPlatform.setScreenDimensions((int)screenWidth, (int)screenHeight); - LOGI("nativeOnCreate: screen set, no initConsts needed\n"); - gContext.doRender = false; - gContext.platform = &appPlatform; - - LOGI("nativeOnCreate: creating gApp\n"); - gApp = new MAIN_CLASS(); - LOGI("nativeOnCreate: gApp=%p\n", gApp); - setupExternalPath(env, (MAIN_CLASS*)gApp); - if (env->ExceptionOccurred()) { - LOGI("nativeOnCreate: exception after setupExternalPath!\n"); - env->ExceptionDescribe(); - env->ExceptionClear(); - } - LOGI("nativeOnCreate: done\n"); - g_inNativeOnCreate = false; - //gApp->init(gContext); -} - -static int s_surfaceCreatedCount = 0; - -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_GLRenderer_nativeOnSurfaceCreated(JNIEnv* env) { - s_surfaceCreatedCount++; - if (g_inNativeOnCreate) { - // Skip re-entrant surface callbacks that fire during nativeOnCreate - return; - } - LOGI("@nativeOnSurfaceCreated #%d tid=%d\n", s_surfaceCreatedCount, (int)gettid()); - - if (gApp) { - // Don't call onGraphicsReset the first time - if (gApp->isInited()) { - LOGI("nativeOnSurfaceCreated: calling onGraphicsReset\n"); - gApp->onGraphicsReset(gContext); - } - - if (!gApp->isInited()) { - LOGI("nativeOnSurfaceCreated: calling init\n"); - gApp->init(gContext); - LOGI("nativeOnSurfaceCreated: init done, isInited=%d\n", (int)gApp->isInited()); - } - } -} - -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_GLRenderer_nativeOnSurfaceChanged(JNIEnv* env, jclass cls, jint w, jint h) { - LOGI("@nativeOnSurfaceChanged: %lu\n", (unsigned long)pthread_self()); - - if (gApp) { - gApp->setSize(w, h); - - if (!gApp->isInited()) - gApp->init(gContext); - - if (!gApp->isInited()) - LOGI("nativeOnSurfaceChanged: NOT INITED!\n"); - } -} - -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeOnDestroy(JNIEnv* env) { - LOGI("@nativeOnDestroy\n"); - - delete gApp; - gApp = 0; - //gApp->onGraphicsReset(gContext); -} - -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_GLRenderer_nativeUpdate(JNIEnv* env) { - //LOGI("@nativeUpdate: %p\n", pthread_self()); - if (gApp) { - if (!gApp->isInited()) - gApp->init(gContext); - - gApp->update(); - - if (gApp->wantToQuit()) - appPlatform.finish(); - } -} - -// -// Keyboard events -// -// helper to convert Android keycodes to our internal Keyboard constants -static int androidKeyToInternal(int androidKey) { - switch(androidKey) { - case AKEYCODE_DEL: return Keyboard::KEY_BACKSPACE; - case AKEYCODE_ENTER: - case AKEYCODE_NUMPAD_ENTER: - return Keyboard::KEY_RETURN; - // letters are delivered via nativeTextChar so no need to map here - default: - return androidKey; // fall back to raw code - } -} - -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeOnKeyDown(JNIEnv* env, jclass cls, jint keyCode) { - LOGI("@nativeOnKeyDown: %d\n", keyCode); - int mapped = androidKeyToInternal(keyCode); - Keyboard::feed(mapped, true); -} -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeTextChar(JNIEnv* env, jclass cls, jint unicodeChar) { - // soft-keyboards may send a backspace as a character code - if (unicodeChar == 8) { - Keyboard::feed(Keyboard::KEY_BACKSPACE, true); - Keyboard::feed(Keyboard::KEY_BACKSPACE, false); - } else if (unicodeChar > 0 && unicodeChar < 128) { - Keyboard::feedText((char)unicodeChar); - } -} -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeOnKeyUp(JNIEnv* env, jclass cls, jint keyCode) { - LOGI("@nativeOnKeyUp: %d\n", (int)keyCode); - int mapped = androidKeyToInternal(keyCode); - Keyboard::feed(mapped, false); -} - -JNIEXPORT jboolean JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeHandleBack(JNIEnv* env, jclass cls, jboolean isDown) { - LOGI("@nativeHandleBack: %d\n", isDown); - if (gApp) return gApp->handleBack(isDown)? JNI_TRUE : JNI_FALSE; - return JNI_FALSE; -} - -// -// Mouse events -// -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeMouseDown(JNIEnv* env, jclass cls, jint pointerId, jint buttonId, jfloat x, jfloat y) { - //LOGI("@nativeMouseDown: %f %f\n", x, y); - mouseDown(1, x, y); - pointerDown(pointerId, x, y); -} -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeMouseUp(JNIEnv* env, jclass cls, jint pointerId, jint buttonId, jfloat x, jfloat y) { - //LOGI("@nativeMouseUp: %f %f\n", x, y); - mouseUp(1, x, y); - pointerUp(pointerId, x, y); -} -JNIEXPORT void JNICALL -Java_com_mojang_minecraftpe_MainActivity_nativeMouseMove(JNIEnv* env, jclass cls, jint pointerId, jfloat x, jfloat y) { - //LOGI("@nativeMouseMove: %f %f\n", x, y); - mouseMove(x, y); - pointerMove(pointerId, x, y); -} -} +#include "App.hpp" +#include "AppPlatform_android.hpp" + +// JNI keycode constants +#include + +//#include "main_android_java.hpp" +#include "platform/input/Multitouch.hpp" +#include +#include + +// Horrible, I know. / A +#ifndef MAIN_CLASS +#include "main.cpp" +#endif + + +// References for JNI +static jobject g_pActivity = 0; +static AppPlatform_android appPlatform; + +static void setupExternalPath(JNIEnv* env, MAIN_CLASS* app) +{ + //JVMAttacher ta(vm); + //JNIEnv* env = ta.getEnv(); + + LOGI("setupExternalPath"); + + if (env) + { + LOGI("Environment exists"); + } + // try appspecific external directory first + jobject activity = g_pActivity; + jclass activityClass = env->GetObjectClass(activity); + jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;"); + + jobject file = NULL; + if (getExternalFilesDir != NULL) { + file = env->CallObjectMethod(activity, getExternalFilesDir, NULL); + } + + if (file == NULL) { + // Fallback to the legacy shared storage directory + jclass clazz = env->FindClass("android/os/Environment"); + jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;"); + if (env->ExceptionOccurred()) { + env->ExceptionDescribe(); + env->ExceptionClear(); + } + file = env->CallStaticObjectMethod(clazz, method); + } + + if (!file) { + LOGI("Failed to get external storage file object, using current working dir"); + app->externalStoragePath = "."; + app->externalCacheStoragePath = "."; + return; + } + + jclass fileClass = env->GetObjectClass(file); + jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;"); + jobject pathString = env->CallObjectMethod(file, fileMethod); + + const char* str = env->GetStringUTFChars((jstring) pathString, NULL); + app->externalStoragePath = str; + app->externalCacheStoragePath = str; + LOGI("%s", str); + + // same fix as the native entry point: make sure cwd is writable + if (chdir(str) != 0) { + LOGI("chdir to %s failed: %s", str, strerror(errno)); + } + + env->ReleaseStringUTFChars((jstring)pathString, str); +} + +static void pointerDown(int pointerId, int x, int y) { + Multitouch::feed(1, 1, x, y, pointerId); +} +static void pointerUp(int pointerId, int x, int y) { + Multitouch::feed(1, 0, x, y, pointerId); +} +static void pointerMove(int pointerId, int x, int y) { + Multitouch::feed(0, 0, x, y, pointerId); +} + + +static App* gApp = 0; +static AppContext gContext; +static bool g_inNativeOnCreate = false; + +extern "C" { +JNIEXPORT jint JNICALL +JNI_OnLoad( JavaVM * vm, void * reserved ) +{ + LOGI("Entering OnLoad\n"); + return appPlatform.init(vm); +} + +// Register/save a reference to the java main activity instance +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeRegisterThis(JNIEnv* env, jobject clazz) { + LOGI("@RegisterThis\n"); + g_pActivity = (jobject)env->NewGlobalRef( clazz ); +} + +// Unregister/delete the reference to the java main activity instance +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeUnregisterThis(JNIEnv* env, jobject clazz) { + LOGI("@UnregisterThis\n"); + env->DeleteGlobalRef( g_pActivity ); +} + +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeOnCreate(JNIEnv* env, jobject thiz, jint screenWidth, jint screenHeight) { + LOGI("@nativeOnCreate w=%d h=%d\n", (int)screenWidth, (int)screenHeight); + g_inNativeOnCreate = true; + + appPlatform.instance = g_pActivity; + appPlatform.setScreenDimensions((int)screenWidth, (int)screenHeight); + LOGI("nativeOnCreate: screen set, no initConsts needed\n"); + gContext.doRender = false; + gContext.platform = &appPlatform; + + LOGI("nativeOnCreate: creating gApp\n"); + gApp = new MAIN_CLASS(); + LOGI("nativeOnCreate: gApp=%p\n", gApp); + setupExternalPath(env, (MAIN_CLASS*)gApp); + if (env->ExceptionOccurred()) { + LOGI("nativeOnCreate: exception after setupExternalPath!\n"); + env->ExceptionDescribe(); + env->ExceptionClear(); + } + LOGI("nativeOnCreate: done\n"); + g_inNativeOnCreate = false; + //gApp->init(gContext); +} + +static int s_surfaceCreatedCount = 0; + +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_GLRenderer_nativeOnSurfaceCreated(JNIEnv* env) { + s_surfaceCreatedCount++; + if (g_inNativeOnCreate) { + // Skip re-entrant surface callbacks that fire during nativeOnCreate + return; + } + LOGI("@nativeOnSurfaceCreated #%d tid=%d\n", s_surfaceCreatedCount, (int)gettid()); + + if (gApp) { + // Don't call onGraphicsReset the first time + if (gApp->isInited()) { + LOGI("nativeOnSurfaceCreated: calling onGraphicsReset\n"); + gApp->onGraphicsReset(gContext); + } + + if (!gApp->isInited()) { + LOGI("nativeOnSurfaceCreated: calling init\n"); + gApp->init(gContext); + LOGI("nativeOnSurfaceCreated: init done, isInited=%d\n", (int)gApp->isInited()); + } + } +} + +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_GLRenderer_nativeOnSurfaceChanged(JNIEnv* env, jclass cls, jint w, jint h) { + LOGI("@nativeOnSurfaceChanged: %lu\n", (unsigned long)pthread_self()); + + if (gApp) { + gApp->setSize(w, h); + + if (!gApp->isInited()) + gApp->init(gContext); + + if (!gApp->isInited()) + LOGI("nativeOnSurfaceChanged: NOT INITED!\n"); + } +} + +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeOnDestroy(JNIEnv* env) { + LOGI("@nativeOnDestroy\n"); + + delete gApp; + gApp = 0; + //gApp->onGraphicsReset(gContext); +} + +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_GLRenderer_nativeUpdate(JNIEnv* env) { + //LOGI("@nativeUpdate: %p\n", pthread_self()); + if (gApp) { + if (!gApp->isInited()) + gApp->init(gContext); + + gApp->update(); + + if (gApp->wantToQuit()) + appPlatform.finish(); + } +} + +// +// Keyboard events +// +// helper to convert Android keycodes to our internal Keyboard constants +static int androidKeyToInternal(int androidKey) { + switch(androidKey) { + case AKEYCODE_DEL: return Keyboard::KEY_BACKSPACE; + case AKEYCODE_ENTER: + case AKEYCODE_NUMPAD_ENTER: + return Keyboard::KEY_RETURN; + // letters are delivered via nativeTextChar so no need to map here + default: + return androidKey; // fall back to raw code + } +} + +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeOnKeyDown(JNIEnv* env, jclass cls, jint keyCode) { + LOGI("@nativeOnKeyDown: %d\n", keyCode); + int mapped = androidKeyToInternal(keyCode); + Keyboard::feed(mapped, true); +} +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeTextChar(JNIEnv* env, jclass cls, jint unicodeChar) { + // soft-keyboards may send a backspace as a character code + if (unicodeChar == 8) { + Keyboard::feed(Keyboard::KEY_BACKSPACE, true); + Keyboard::feed(Keyboard::KEY_BACKSPACE, false); + } else if (unicodeChar > 0 && unicodeChar < 128) { + Keyboard::feedText((char)unicodeChar); + } +} +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeOnKeyUp(JNIEnv* env, jclass cls, jint keyCode) { + LOGI("@nativeOnKeyUp: %d\n", (int)keyCode); + int mapped = androidKeyToInternal(keyCode); + Keyboard::feed(mapped, false); +} + +JNIEXPORT jboolean JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeHandleBack(JNIEnv* env, jclass cls, jboolean isDown) { + LOGI("@nativeHandleBack: %d\n", isDown); + if (gApp) return gApp->handleBack(isDown)? JNI_TRUE : JNI_FALSE; + return JNI_FALSE; +} + +// +// Mouse events +// +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeMouseDown(JNIEnv* env, jclass cls, jint pointerId, jint buttonId, jfloat x, jfloat y) { + //LOGI("@nativeMouseDown: %f %f\n", x, y); + mouseDown(1, x, y); + pointerDown(pointerId, x, y); +} +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeMouseUp(JNIEnv* env, jclass cls, jint pointerId, jint buttonId, jfloat x, jfloat y) { + //LOGI("@nativeMouseUp: %f %f\n", x, y); + mouseUp(1, x, y); + pointerUp(pointerId, x, y); +} +JNIEXPORT void JNICALL +Java_com_mojang_minecraftpe_MainActivity_nativeMouseMove(JNIEnv* env, jclass cls, jint pointerId, jfloat x, jfloat y) { + //LOGI("@nativeMouseMove: %f %f\n", x, y); + mouseMove(x, y); + pointerMove(pointerId, x, y); +} +} diff --git a/src/main_android_java.h b/src/main_android_java.hpp similarity index 93% rename from src/main_android_java.h rename to src/main_android_java.hpp index 89f8bb0..e7fc357 100755 --- a/src/main_android_java.h +++ b/src/main_android_java.hpp @@ -1,174 +1,174 @@ -#ifndef MAIN_CLASS -#error "Error: MAIN_CLASS must have been defined to your main class (e.g. #define MAIN_CLASS MyApp)" -#endif - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#define TAG "MAIN_CLASS" - -#include "platform/log.h" -#include "platform/input/Keyboard.h" -#include "platform/input/Mouse.h" -#include "platform/input/Controller.h" - -#include "EglConfigPrinter.h" - -const int BroadcastPort = 9991; - -/** - * Shared state for our app. - */ -struct ENGINE -{ - struct android_app* app; - - int render; - EGLDisplay display; - EGLSurface surface; - EGLContext context; - int width; - int height; - int has_focus; - App* userApp; - bool is_inited; - //bool init_gl; - struct AppContext appContext; -}; - -static void mouseDown(int buttonId, int x, int y) { - int msg[] = {buttonId, 0, x, y}; - //broadcastData(BroadcastPort, msg, sizeof(msg)); - - Mouse::feed(buttonId, 1, x, y); -} - -static void mouseUp(int buttonId, int x, int y) { - int msg[] = {buttonId, 0, x, y}; - //broadcastData(BroadcastPort, msg, sizeof(msg)); - - Mouse::feed(buttonId, 0, x, y); -} - -static void mouseMove(int x, int y) { - int msg[] = {0, 0, x, y}; - //broadcastData(BroadcastPort, msg, sizeof(msg)); - - Mouse::feed(0, 0, x, y); -} - -#if 0 - -/** - * Process the next input event. - */ -static -int32_t -engine_handle_input( struct android_app* app, AInputEvent* event ) -{ - struct ENGINE* engine = (struct ENGINE*)app->userData; - if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION ) - { - //engine->render = 1; - int nPointerCount = AMotionEvent_getPointerCount( event ); - int nSourceId = AInputEvent_getSource( event ); - int n; - - for( n = 0 ; n < nPointerCount ; ++n ) - { - int nPointerId = AMotionEvent_getPointerId( event, n ); - int nAction = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction( event ); - int isTrackpad = nSourceId == AINPUT_SOURCE_TOUCHPAD; - - // We don't care about secondary pointers right now - if( !isTrackpad && (nAction == AMOTION_EVENT_ACTION_POINTER_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_UP )) - continue; - - int x = AMotionEvent_getX( event, n ); - int y = AMotionEvent_getY( event, n ); - - if( nAction == AMOTION_EVENT_ACTION_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_DOWN ) { - //LOGI("action down %d\n", isTrackpad); - if (isTrackpad) { - trackpadPress(x, y); - } else { - mouseDown(1, x, y); - //LOGI("mouse-pointer down"); - } - } - else if( nAction == AMOTION_EVENT_ACTION_UP || nAction == AMOTION_EVENT_ACTION_POINTER_UP /*|| nAction == AMOTION_EVENT_ACTION_CANCEL*/ ) { - //LOGI("action up %d\n", isTrackpad); - if (isTrackpad) { - //LOGI("trackpad-up\n"); - trackpadRelease(x, y); - } - else { - //LOGI("mouse-pointer up\n"); - mouseUp(1, x, y); - } - } else if (nAction == AMOTION_EVENT_ACTION_MOVE ) { - if (isTrackpad) - trackpadMove(x, y); - else - mouseMove(x, y); - } - } - return 1; - } - else if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY ) - { - bool isDown = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN; - int keyCode = AKeyEvent_getKeyCode(event); - bool pressedBack = keyCode == 4 && AInputEvent_getDeviceId(event) == 0; - bool isRepeat = AKeyEvent_getRepeatCount(event) > 0; - if (!isRepeat){ - //int scanCode = AKeyEvent_getScanCode(event); - //LOGI("key-%s : %d", isDown?"key-down":"key-up", keyCode); - //LOGI("getId: %d\n", AInputEvent_getDeviceId(event)); - //LOGI("flags: %d\n", AKeyEvent_getFlags(event)); - //LOGI("scancode: %d\n", AKeyEvent_getScanCode(event)); - - //unsigned char msg[2] = {(unsigned char)(keyCode), (unsigned char)(isDown)}; - //broadcastData(BroadcastPort, msg, 2); - - if (!pressedBack) - Keyboard::feed(keyCode, isDown); - } - if (keyCode == 4) - { - if (!isRepeat && !engine->userApp->handleBack(isDown)) - { - //LOGI("Returning 0 from engine_handle_input\n"); - return 0; - } - return 1; - } - - bool volumeButton = (keyCode == 24) || (keyCode == 25); - bool handled = !pressedBack && !volumeButton; - return handled; - } - - return 0; -} - -#endif - -/** - * This is the main entry point of a native application that is using - * android_native_app_glue. It runs in its own thread, with its own - * event loop for receiving input events and doing other things (rendering). - */ -void -android_main( struct android_app* state ); +#ifndef MAIN_CLASS +#error "Error: MAIN_CLASS must have been defined to your main class (e.g. #define MAIN_CLASS MyApp)" +#endif + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#define TAG "MAIN_CLASS" + +#include "platform/log.hpp" +#include "platform/input/Keyboard.hpp" +#include "platform/input/Mouse.hpp" +#include "platform/input/Controller.hpp" + +#include "EglConfigPrinter.hpp" + +const int BroadcastPort = 9991; + +/** + * Shared state for our app. + */ +struct ENGINE +{ + struct android_app* app; + + int render; + EGLDisplay display; + EGLSurface surface; + EGLContext context; + int width; + int height; + int has_focus; + App* userApp; + bool is_inited; + //bool init_gl; + struct AppContext appContext; +}; + +static void mouseDown(int buttonId, int x, int y) { + int msg[] = {buttonId, 0, x, y}; + //broadcastData(BroadcastPort, msg, sizeof(msg)); + + Mouse::feed(buttonId, 1, x, y); +} + +static void mouseUp(int buttonId, int x, int y) { + int msg[] = {buttonId, 0, x, y}; + //broadcastData(BroadcastPort, msg, sizeof(msg)); + + Mouse::feed(buttonId, 0, x, y); +} + +static void mouseMove(int x, int y) { + int msg[] = {0, 0, x, y}; + //broadcastData(BroadcastPort, msg, sizeof(msg)); + + Mouse::feed(0, 0, x, y); +} + +#if 0 + +/** + * Process the next input event. + */ +static +int32_t +engine_handle_input( struct android_app* app, AInputEvent* event ) +{ + struct ENGINE* engine = (struct ENGINE*)app->userData; + if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION ) + { + //engine->render = 1; + int nPointerCount = AMotionEvent_getPointerCount( event ); + int nSourceId = AInputEvent_getSource( event ); + int n; + + for( n = 0 ; n < nPointerCount ; ++n ) + { + int nPointerId = AMotionEvent_getPointerId( event, n ); + int nAction = AMOTION_EVENT_ACTION_MASK & AMotionEvent_getAction( event ); + int isTrackpad = nSourceId == AINPUT_SOURCE_TOUCHPAD; + + // We don't care about secondary pointers right now + if( !isTrackpad && (nAction == AMOTION_EVENT_ACTION_POINTER_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_UP )) + continue; + + int x = AMotionEvent_getX( event, n ); + int y = AMotionEvent_getY( event, n ); + + if( nAction == AMOTION_EVENT_ACTION_DOWN || nAction == AMOTION_EVENT_ACTION_POINTER_DOWN ) { + //LOGI("action down %d\n", isTrackpad); + if (isTrackpad) { + trackpadPress(x, y); + } else { + mouseDown(1, x, y); + //LOGI("mouse-pointer down"); + } + } + else if( nAction == AMOTION_EVENT_ACTION_UP || nAction == AMOTION_EVENT_ACTION_POINTER_UP /*|| nAction == AMOTION_EVENT_ACTION_CANCEL*/ ) { + //LOGI("action up %d\n", isTrackpad); + if (isTrackpad) { + //LOGI("trackpad-up\n"); + trackpadRelease(x, y); + } + else { + //LOGI("mouse-pointer up\n"); + mouseUp(1, x, y); + } + } else if (nAction == AMOTION_EVENT_ACTION_MOVE ) { + if (isTrackpad) + trackpadMove(x, y); + else + mouseMove(x, y); + } + } + return 1; + } + else if( AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY ) + { + bool isDown = AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN; + int keyCode = AKeyEvent_getKeyCode(event); + bool pressedBack = keyCode == 4 && AInputEvent_getDeviceId(event) == 0; + bool isRepeat = AKeyEvent_getRepeatCount(event) > 0; + if (!isRepeat){ + //int scanCode = AKeyEvent_getScanCode(event); + //LOGI("key-%s : %d", isDown?"key-down":"key-up", keyCode); + //LOGI("getId: %d\n", AInputEvent_getDeviceId(event)); + //LOGI("flags: %d\n", AKeyEvent_getFlags(event)); + //LOGI("scancode: %d\n", AKeyEvent_getScanCode(event)); + + //unsigned char msg[2] = {(unsigned char)(keyCode), (unsigned char)(isDown)}; + //broadcastData(BroadcastPort, msg, 2); + + if (!pressedBack) + Keyboard::feed(keyCode, isDown); + } + if (keyCode == 4) + { + if (!isRepeat && !engine->userApp->handleBack(isDown)) + { + //LOGI("Returning 0 from engine_handle_input\n"); + return 0; + } + return 1; + } + + bool volumeButton = (keyCode == 24) || (keyCode == 25); + bool handled = !pressedBack && !volumeButton; + return handled; + } + + return 0; +} + +#endif + +/** + * This is the main entry point of a native application that is using + * android_native_app_glue. It runs in its own thread, with its own + * event loop for receiving input events and doing other things (rendering). + */ +void +android_main( struct android_app* state ); diff --git a/src/main_dedicated.cpp b/src/main_dedicated.cpp index 8701798..ab19661 100755 --- a/src/main_dedicated.cpp +++ b/src/main_dedicated.cpp @@ -1,18 +1,18 @@ #include -#include +#include #include #include #include #include #include -#include "MinecraftServer.h" -#include "platform/server/PlatformServer.h" -#include "world/level/LevelSettings.h" -#include "world/level/Level.h" -#include "server/ArgumentsSettings.h" -#include "platform/time.h" -#include "SharedConstants.h" +#include "MinecraftServer.hpp" +#include "platform/server/PlatformServer.hpp" +#include "world/level/LevelSettings.hpp" +#include "world/level/Level.hpp" +#include "server/ArgumentsSettings.hpp" +#include "platform/time.hpp" +#include "SharedConstants.hpp" static App* g_app = 0; static int g_exitCode = 0; diff --git a/src/main_glfw.h b/src/main_glfw.hpp similarity index 82% rename from src/main_glfw.h rename to src/main_glfw.hpp index 45770c2..b34c864 100755 --- a/src/main_glfw.h +++ b/src/main_glfw.hpp @@ -1,18 +1,18 @@ #pragma once -#include "App.h" -#include "NinecraftApp.h" -#include "client/renderer/entity/PlayerRenderer.h" -#include "client/renderer/gles.h" -#include "GLFW/glfw3.h" +#include "App.hpp" +#include "NinecraftApp.hpp" +#include "client/renderer/entity/PlayerRenderer.hpp" +#include "client/renderer/gles.hpp" +#include "GLFW/glfw3.hpp" #include #include #include -#include "platform/input/Keyboard.h" -#include "platform/input/Mouse.h" -#include "platform/input/Multitouch.h" -#include "AppPlatform_glfw.h" +#include "platform/input/Keyboard.hpp" +#include "platform/input/Mouse.hpp" +#include "platform/input/Multitouch.hpp" +#include "AppPlatform_glfw.hpp" #ifdef __EMSCRIPTEN__ #include #endif diff --git a/src/main_rpi.cpp b/src/main_rpi.cpp index f05ef00..d970937 100755 --- a/src/main_rpi.cpp +++ b/src/main_rpi.cpp @@ -1,4 +1,4 @@ -//#include "main_rpi.h" +//#include "main_rpi.hpp" #include diff --git a/src/main_rpi.h b/src/main_rpi.hpp similarity index 97% rename from src/main_rpi.h rename to src/main_rpi.hpp index b882bcb..e14659d 100755 --- a/src/main_rpi.h +++ b/src/main_rpi.hpp @@ -2,11 +2,11 @@ #include -#include "bcm_host.h" +#include "bcm_host.hpp" -//#include "GLES/gl.h" -#include "EGL/egl.h" -#include "EGL/eglext.h" +//#include "GLES/gl.hpp" +#include "EGL/egl.hpp" +#include "EGL/eglext.hpp" #include #include @@ -15,10 +15,10 @@ #define check() assert(glGetError() == 0) -#include "App.h" -#include "platform/input/Mouse.h" -#include "platform/input/Multitouch.h" -#include "platform/input/Keyboard.h" +#include "App.hpp" +#include "platform/input/Mouse.hpp" +#include "platform/input/Multitouch.hpp" +#include "platform/input/Keyboard.hpp" int width = 848; int height = 480; diff --git a/src/main_win32.h b/src/main_win32.hpp similarity index 97% rename from src/main_win32.h rename to src/main_win32.hpp index 01bd7ce..410ebb1 100755 --- a/src/main_win32.h +++ b/src/main_win32.hpp @@ -6,7 +6,7 @@ #include */ -#include "client/renderer/gles.h" +#include "client/renderer/gles.hpp" #include // #include #define WIN32_LEAN_AND_MEAN 1 @@ -15,13 +15,13 @@ #include #include -#include "SharedConstants.h" +#include "SharedConstants.hpp" #include -#include "platform/input/Mouse.h" -#include "platform/input/Multitouch.h" -#include "util/Mth.h" -#include "AppPlatform_win32.h" +#include "platform/input/Mouse.hpp" +#include "platform/input/Multitouch.hpp" +#include "util/Mth.hpp" +#include "AppPlatform_win32.hpp" static App* g_app = 0; static volatile bool g_running = true; diff --git a/src/nbt/ByteArrayTag.h b/src/nbt/ByteArrayTag.hpp similarity index 98% rename from src/nbt/ByteArrayTag.h rename to src/nbt/ByteArrayTag.hpp index a609850..08fff20 100755 --- a/src/nbt/ByteArrayTag.h +++ b/src/nbt/ByteArrayTag.hpp @@ -4,7 +4,7 @@ /* import java.io.* */ -#include "Tag.h" +#include "Tag.hpp" #include typedef struct TagMemoryChunk { diff --git a/src/nbt/ByteTag.h b/src/nbt/ByteTag.hpp similarity index 97% rename from src/nbt/ByteTag.h rename to src/nbt/ByteTag.hpp index 0ec0da2..740be33 100755 --- a/src/nbt/ByteTag.h +++ b/src/nbt/ByteTag.hpp @@ -4,7 +4,7 @@ /* import java.io.* */ -#include "Tag.h" +#include "Tag.hpp" #include class ByteTag: public Tag diff --git a/src/nbt/CompoundTag.h b/src/nbt/CompoundTag.hpp similarity index 95% rename from src/nbt/CompoundTag.h rename to src/nbt/CompoundTag.hpp index ab83a78..860724e 100755 --- a/src/nbt/CompoundTag.h +++ b/src/nbt/CompoundTag.hpp @@ -2,22 +2,22 @@ //package com.mojang.nbt; -#include "Tag.h" +#include "Tag.hpp" #include #include #include #include -#include "../util/CollectionUtils.h" +#include "util/CollectionUtils.hpp" -#include "ByteTag.h" -#include "ShortTag.h" -#include "IntTag.h" -#include "LongTag.h" -#include "FloatTag.h" -#include "DoubleTag.h" -#include "ListTag.h" -#include "StringTag.h" -#include "ByteArrayTag.h" +#include "ByteTag.hpp" +#include "ShortTag.hpp" +#include "IntTag.hpp" +#include "LongTag.hpp" +#include "FloatTag.hpp" +#include "DoubleTag.hpp" +#include "ListTag.hpp" +#include "StringTag.hpp" +#include "ByteArrayTag.hpp" class CompoundTag: public Tag { diff --git a/src/nbt/DoubleTag.h b/src/nbt/DoubleTag.hpp similarity index 98% rename from src/nbt/DoubleTag.h rename to src/nbt/DoubleTag.hpp index ea6b8a8..37cb5b6 100755 --- a/src/nbt/DoubleTag.h +++ b/src/nbt/DoubleTag.hpp @@ -4,7 +4,7 @@ /* import java.io.* */ -#include "Tag.h" +#include "Tag.hpp" #include class DoubleTag: public Tag { diff --git a/src/nbt/EndTag.h b/src/nbt/EndTag.hpp similarity index 100% rename from src/nbt/EndTag.h rename to src/nbt/EndTag.hpp diff --git a/src/nbt/FloatTag.h b/src/nbt/FloatTag.hpp similarity index 98% rename from src/nbt/FloatTag.h rename to src/nbt/FloatTag.hpp index d8576de..73b1042 100755 --- a/src/nbt/FloatTag.h +++ b/src/nbt/FloatTag.hpp @@ -4,7 +4,7 @@ /* import java.io.* */ -#include "Tag.h" +#include "Tag.hpp" #include class FloatTag: public Tag { diff --git a/src/nbt/IntTag.h b/src/nbt/IntTag.hpp similarity index 98% rename from src/nbt/IntTag.h rename to src/nbt/IntTag.hpp index ca288d5..9c1fa21 100755 --- a/src/nbt/IntTag.h +++ b/src/nbt/IntTag.hpp @@ -2,7 +2,7 @@ //package com.mojang.nbt; -#include "Tag.h" +#include "Tag.hpp" #include /* import java.io.* */ diff --git a/src/nbt/ListTag.h b/src/nbt/ListTag.hpp similarity index 99% rename from src/nbt/ListTag.h rename to src/nbt/ListTag.hpp index 868c48b..8ad8127 100755 --- a/src/nbt/ListTag.h +++ b/src/nbt/ListTag.hpp @@ -2,7 +2,7 @@ //package com.mojang.nbt; -#include "Tag.h" +#include "Tag.hpp" #include //template diff --git a/src/nbt/LongTag.h b/src/nbt/LongTag.hpp similarity index 98% rename from src/nbt/LongTag.h rename to src/nbt/LongTag.hpp index f4e0029..f595ba2 100755 --- a/src/nbt/LongTag.h +++ b/src/nbt/LongTag.hpp @@ -1,7 +1,7 @@ #pragma once //package com.mojang.nbt; -#include "Tag.h" +#include "Tag.hpp" #include class LongTag: public Tag { diff --git a/src/nbt/NbtIo.h b/src/nbt/NbtIo.hpp similarity index 87% rename from src/nbt/NbtIo.h rename to src/nbt/NbtIo.hpp index 50db256..b891b4a 100755 --- a/src/nbt/NbtIo.h +++ b/src/nbt/NbtIo.hpp @@ -2,8 +2,8 @@ //package com.mojang.nbt; -#include "CompoundTag.h" -#include "../util/DataIO.h" +#include "CompoundTag.hpp" +#include "util/DataIO.hpp" class NbtIo { diff --git a/src/nbt/ShortTag.h b/src/nbt/ShortTag.hpp similarity index 98% rename from src/nbt/ShortTag.h rename to src/nbt/ShortTag.hpp index fcdf195..8978f7e 100755 --- a/src/nbt/ShortTag.h +++ b/src/nbt/ShortTag.hpp @@ -4,7 +4,7 @@ /* import java.io.* */ -#include "Tag.h" +#include "Tag.hpp" #include class ShortTag: public Tag { diff --git a/src/nbt/StringTag.h b/src/nbt/StringTag.hpp similarity index 98% rename from src/nbt/StringTag.h rename to src/nbt/StringTag.hpp index a151201..8964c34 100755 --- a/src/nbt/StringTag.h +++ b/src/nbt/StringTag.hpp @@ -2,7 +2,7 @@ //package com.mojang.nbt; -#include "Tag.h" +#include "Tag.hpp" #include class StringTag: public Tag diff --git a/src/nbt/Tag.cpp b/src/nbt/Tag.cpp index b1ce3ae..402bbb6 100755 --- a/src/nbt/Tag.cpp +++ b/src/nbt/Tag.cpp @@ -1,139 +1,139 @@ -#include "Tag.h" - -#include "EndTag.h" -#include "ByteTag.h" -#include "ShortTag.h" -#include "IntTag.h" -#include "LongTag.h" -#include "FloatTag.h" -#include "DoubleTag.h" -#include "ByteArrayTag.h" -#include "StringTag.h" -#include "ListTag.h" -#include "CompoundTag.h" - - -/*static*/ const std::string Tag::NullString = ""; - - -Tag::Tag(const std::string& name) -: name(name), - errorState(0) -{ -} - -/*virtual*/ -bool Tag::equals(const Tag& rhs) const { - return getId() == rhs.getId() - && name == rhs.name; -} - -/*virtual*/ -void Tag::print(PrintStream& out) const { - print("", out); -} - -/*virtual*/ -void Tag::print(const std::string& prefix, PrintStream& out) const { - std::string name = getName(); - - out.print(prefix); - out.print(getTagName(getId())); - if (name.length() > 0) { - out.print("(\"" + name + "\")"); - } - out.print(": "); - out.println(toString()); -} - -/*virtual*/ -Tag* Tag::setName(const std::string& name) { - this->name = name; - return this; -} - -/*virtual*/ -std::string Tag::getName() const { - return name; -} - -/*static*/ -Tag* Tag::readNamedTag(IDataInput* dis) /*throws IOException*/ { - char type = dis->readByte(); - if (type == Tag::TAG_End) return new EndTag(); - - Tag* tag = newTag(type, dis->readString()); - if (!tag) - return NULL; - - tag->load(dis); - return tag; -} - -/*static*/ -void Tag::writeNamedTag(Tag* tag, IDataOutput* dos) /*throws IOException*/ { - dos->writeByte(tag->getId()); - if (tag->getId() == Tag::TAG_End) return; - - dos->writeString(tag->getName()); - tag->write(dos); -} - -/*static*/ -Tag* Tag::newTag(char type, const std::string& name) -{ - switch (type) { - case TAG_End: - return new EndTag(); - case TAG_Byte: - return new ByteTag(name); - case TAG_Short: - return new ShortTag(name); - case TAG_Int: - return new IntTag(name); - case TAG_Long: - return new LongTag(name); - case TAG_Float: - return new FloatTag(name); - case TAG_Double: - return new DoubleTag(name); - case TAG_Byte_Array: - return new ByteArrayTag(name); - case TAG_String: - return new StringTag(name); - case TAG_List: - return new ListTag(name); - case TAG_Compound: - return new CompoundTag(name); - } - return NULL; -} - -/*static*/ -std::string Tag::getTagName(char type) { - switch (type) { - case TAG_End: - return "TAG_End"; - case TAG_Byte: - return "TAG_Byte"; - case TAG_Short: - return "TAG_Short"; - case TAG_Int: - return "TAG_Int"; - case TAG_Long: - return "TAG_Long"; - case TAG_Float: - return "TAG_Float"; - case TAG_Double: - return "TAG_Double"; - case TAG_Byte_Array: - return "TAG_Byte_Array"; - case TAG_String: - return "TAG_String"; - case TAG_List: - return "TAG_List"; - case TAG_Compound: - return "TAG_Compound"; - } - return "UNKNOWN"; -} +#include "Tag.hpp" + +#include "EndTag.hpp" +#include "ByteTag.hpp" +#include "ShortTag.hpp" +#include "IntTag.hpp" +#include "LongTag.hpp" +#include "FloatTag.hpp" +#include "DoubleTag.hpp" +#include "ByteArrayTag.hpp" +#include "StringTag.hpp" +#include "ListTag.hpp" +#include "CompoundTag.hpp" + + +/*static*/ const std::string Tag::NullString = ""; + + +Tag::Tag(const std::string& name) +: name(name), + errorState(0) +{ +} + +/*virtual*/ +bool Tag::equals(const Tag& rhs) const { + return getId() == rhs.getId() + && name == rhs.name; +} + +/*virtual*/ +void Tag::print(PrintStream& out) const { + print("", out); +} + +/*virtual*/ +void Tag::print(const std::string& prefix, PrintStream& out) const { + std::string name = getName(); + + out.print(prefix); + out.print(getTagName(getId())); + if (name.length() > 0) { + out.print("(\"" + name + "\")"); + } + out.print(": "); + out.println(toString()); +} + +/*virtual*/ +Tag* Tag::setName(const std::string& name) { + this->name = name; + return this; +} + +/*virtual*/ +std::string Tag::getName() const { + return name; +} + +/*static*/ +Tag* Tag::readNamedTag(IDataInput* dis) /*throws IOException*/ { + char type = dis->readByte(); + if (type == Tag::TAG_End) return new EndTag(); + + Tag* tag = newTag(type, dis->readString()); + if (!tag) + return NULL; + + tag->load(dis); + return tag; +} + +/*static*/ +void Tag::writeNamedTag(Tag* tag, IDataOutput* dos) /*throws IOException*/ { + dos->writeByte(tag->getId()); + if (tag->getId() == Tag::TAG_End) return; + + dos->writeString(tag->getName()); + tag->write(dos); +} + +/*static*/ +Tag* Tag::newTag(char type, const std::string& name) +{ + switch (type) { + case TAG_End: + return new EndTag(); + case TAG_Byte: + return new ByteTag(name); + case TAG_Short: + return new ShortTag(name); + case TAG_Int: + return new IntTag(name); + case TAG_Long: + return new LongTag(name); + case TAG_Float: + return new FloatTag(name); + case TAG_Double: + return new DoubleTag(name); + case TAG_Byte_Array: + return new ByteArrayTag(name); + case TAG_String: + return new StringTag(name); + case TAG_List: + return new ListTag(name); + case TAG_Compound: + return new CompoundTag(name); + } + return NULL; +} + +/*static*/ +std::string Tag::getTagName(char type) { + switch (type) { + case TAG_End: + return "TAG_End"; + case TAG_Byte: + return "TAG_Byte"; + case TAG_Short: + return "TAG_Short"; + case TAG_Int: + return "TAG_Int"; + case TAG_Long: + return "TAG_Long"; + case TAG_Float: + return "TAG_Float"; + case TAG_Double: + return "TAG_Double"; + case TAG_Byte_Array: + return "TAG_Byte_Array"; + case TAG_String: + return "TAG_String"; + case TAG_List: + return "TAG_List"; + case TAG_Compound: + return "TAG_Compound"; + } + return "UNKNOWN"; +} diff --git a/src/nbt/Tag.h b/src/nbt/Tag.hpp similarity index 98% rename from src/nbt/Tag.h rename to src/nbt/Tag.hpp index 052421f..0ac1c8d 100755 --- a/src/nbt/Tag.h +++ b/src/nbt/Tag.hpp @@ -4,7 +4,7 @@ /* import java.io.* */ -#include "../util/DataIO.h" +#include "util/DataIO.hpp" #include diff --git a/src/network/ClientSideNetworkHandler.cpp b/src/network/ClientSideNetworkHandler.cpp index 58db3f3..d932e12 100755 --- a/src/network/ClientSideNetworkHandler.cpp +++ b/src/network/ClientSideNetworkHandler.cpp @@ -1,917 +1,917 @@ -#include "ClientSideNetworkHandler.h" -#include -#include "client/Options.h" -#include "gamemode/GameMode.h" -#include "packet/PacketInclude.h" -#include "RakNetInstance.h" -#include "../world/level/chunk/ChunkSource.h" -#include "../world/level/Level.h" -#include "../world/level/storage/LevelStorageSource.h" -#include "../world/entity/player/Player.h" -#include "../world/entity/player/Inventory.h" -#include -#include "../client/player/LocalPlayer.h" -#include "../client/multiplayer/MultiPlayerLevel.h" -#include "../client/player/input/KeyboardInput.h" -#include "../client/sound/SoundEngine.h" -#include "../world/entity/MobFactory.h" -#include "../raknet/RakPeerInterface.h" -#include "../world/level/Explosion.h" -#include "../world/level/tile/entity/FurnaceTileEntity.h" -#include "../world/inventory/BaseContainerMenu.h" -#include "../world/entity/EntityFactory.h" -#include "../world/entity/item/PrimedTnt.h" -#include "../world/entity/projectile/Arrow.h" -#include "../world/level/tile/entity/ChestTileEntity.h" -#include "../client/player/RemotePlayer.h" -#include "../world/level/tile/LevelEvent.h" -#include "../world/entity/item/FallingTile.h" - -static MultiPlayerLevel* mpcast(Level* l) { return (MultiPlayerLevel*) l; } - -ClientSideNetworkHandler::ClientSideNetworkHandler(MinecraftClient& minecraft, IRakNetInstance* raknetInstance) -: minecraft(minecraft), - raknetInstance(raknetInstance) -{ - rakPeer = raknetInstance->getPeer(); -} - -ClientSideNetworkHandler::~ClientSideNetworkHandler() -{ -} - -void ClientSideNetworkHandler::requestNextChunk() -{ - if (requestNextChunkIndex < NumRequestChunks) - { - IntPair& chunk = requestNextChunkIndexList[requestNextChunkIndex]; - RequestChunkPacket packet(chunk.x, chunk.y); - raknetInstance->send(packet); - - //LOGI("requesting chunks @ (%d, %d)\n", chunk.x, chunk.y); - - //raknetInstance->send(new RequestChunkPacket(requestNextChunkPosition % CHUNK_CACHE_WIDTH, requestNextChunkPosition / CHUNK_CACHE_WIDTH)); - requestNextChunkIndex++; - requestNextChunkPosition++; - } -} - -bool ClientSideNetworkHandler::areAllChunksLoaded() -{ - return (requestNextChunkPosition >= (CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH)); -} - -bool ClientSideNetworkHandler::isChunkLoaded(int x, int z) -{ - if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH) { - LOGE("Error: Tried to request chunk (%d, %d)\n", x, z); - return true; - } - return chunksLoaded[x * CHUNK_CACHE_WIDTH + z]; - //return areAllChunksLoaded(); -} - -void ClientSideNetworkHandler::onConnect(const RakNet::RakNetGUID& hostGuid) -{ - LOGI("onConnect, server guid: %s, local guid: %s\n", hostGuid.ToString(), rakPeer->GetMyGUID().ToString()); - serverGuid = hostGuid; - - clearChunksLoaded(); - LoginPacket packet(minecraft.options().getStringValue(OPTIONS_USERNAME).c_str(), SharedConstants::NetworkProtocolVersion); - raknetInstance->send(packet); -} - -void ClientSideNetworkHandler::onUnableToConnect() -{ - LOGI("onUnableToConnect\n"); -} - -void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) -{ - LOGI("onDisconnect\n"); - if (level) - { - level->isClientSide = false; - for (int i = (int)level->players.size()-1; i >= 0; --i ) { - Player* p = level->players[i]; - if (p != minecraft.getPlayer()) { - p->reallyRemoveIfPlayer = true; - level->removeEntity(p); - } - } - } -#ifndef STANDALONE_SERVER - minecraft.gui.addMessage("Disconnected from server"); -#endif -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginStatusPacket* packet) { - if (packet->status == LoginStatus::Success) { - raknetInstance->setIsLoggedIn(true); - return; - } - - if (packet->status == LoginStatus::Failed_ClientOld) { - LOGI("Disconnect! Client is outdated!\n"); -#ifndef STANDALONE_SERVER - minecraft.setScreen(new DisconnectionScreen("Could not connect: Outdated client!")); -#endif - } - if (packet->status == LoginStatus::Failed_ServerOld) { - LOGI("Disconnect! Server is outdated!\n"); -#ifndef STANDALONE_SERVER - minecraft.setScreen(new DisconnectionScreen("Could not connect: Outdated server!")); -#endif - } -} - - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, StartGamePacket* packet) -{ - LOGI("StartGamePacket\n"); - -#ifdef RPI - if (packet->gameType != GameType::Creative) { - minecraft.setScreen(new DisconnectionScreen("Could not connect: Incompatible server!")); - return; - } -#endif - - const std::string& levelId = LevelStorageSource::TempLevelId; - LevelStorageSource* storageSource = minecraft.getLevelSource(); - storageSource->deleteLevel(levelId); - //level = new Level(storageSource->selectLevel(levelId, true), "temp", packet->levelSeed, SharedConstants::StorageVersion); - MultiPlayerLevel* level = new MultiPlayerLevel( - storageSource->selectLevel(levelId, true), - "temp", - LevelSettings(packet->levelSeed, LevelSettings::validateGameType(packet->gameType)), - SharedConstants::StorageVersion); - level->isClientSide = true; - - bool isCreative = (packet->gameType == GameType::Creative); - LocalPlayer* player = new LocalPlayer(minecraft, level, minecraft.options().getStringValue(OPTIONS_USERNAME), level->dimension->id, isCreative); - player->owner = rakPeer->GetMyGUID(); - player->entityId = packet->entityId; - player->moveTo(packet->x, packet->y, packet->z, player->yRot, player->xRot); - - LOGI("new pos: %f, %f [%f - %f]\n", player->x, player->z, player->bb.y0, player->bb.y1); - - minecraft.setLevel(level, "ClientSideNetworkHandler -> setLevel", player); - minecraft.setIsCreativeMode(isCreative); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MessagePacket* packet) -{ - LOGI("MessagePacket\n"); -#ifndef STANDALONE_SERVER - minecraft.gui.addMessage(packet->message.C_String()); -#endif -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetTimePacket* packet) -{ - if (!level) - return; - - LOGI("SetTimePacket\n"); - level->setTime(packet->time); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddEntityPacket* packet) -{ - if (!level) - return; - - Entity* e = EntityFactory::CreateEntity(packet->type, level); - if (!e) - return; - - e->entityId = packet->entityId; - e->setPos(packet->x, packet->y, packet->z); - - // Entity Specific stuff here - switch (packet->type) - { - case EntityTypes::IdFallingTile: { - int data = -packet->data(); - FallingTile* ft = (FallingTile*) e; - ft->tile = data & 0xff; - ft->data = data >> 16; - } - case EntityTypes::IdArrow: { - Entity* owner = level->getEntity(packet->data()); - if (owner && owner->isMob()) - ((Arrow*)e)->ownerId = owner->entityId; - break; - } - default: - break; - } - - if (packet->hasMovementData()) { - /* - e->xd = packet->xd; - e->yd = packet->yd; - e->zd = packet->zd; - */ - e->lerpMotion(packet->xd, packet->yd, packet->zd); - //LOGI("Client: reading entity with %f, %f, %f\n", e->xd, e->yd, e->zd); - } - - mpcast(level)->putEntity(packet->entityId, e); -} -void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, AddPaintingPacket* packet ) { - if (!level) - return; - - Painting* painting = new Painting(level, packet->xTile, packet->yTile, packet->zTile, packet->dir, packet->motive); - mpcast(level)->putEntity(packet->entityId, painting); -} -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddMobPacket* packet) -{ - LOGI("AddMobPacket (%p)\n", level); - - if (!level) { - LOGW("Trying to add a mob with no level!\n"); - //we skip this since we will get this player anyway when we request level - return; - } - if (!packet->type) { - LOGE("Trying to add a mob without a type id\n"); - return; - } - - Mob* mob = MobFactory::CreateMob(packet->type, level); - if (!mob) { - LOGE("Server tried to add an unknown mob type! :%d\n", packet->type); - return; - } - - mob->entityId = packet->entityId; - mob->moveTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot); - mob->getEntityData()->assignValues(&packet->unpack); - level->addEntity(mob); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddPlayerPacket* packet) -{ - if (!level) { - //we skip this since we will get this player anyway when we request level - return; - } - LOGI("AddPlayerPacket\n"); - - Player* player = new RemotePlayer(level, minecraft.isCreativeMode()); - minecraft.gameMode->initAbilities(player->abilities); - player->entityId = packet->entityId; - level->addEntity(player); - - player->moveTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot); - player->name = packet->name.C_String(); - player->owner = packet->owner; - player->getEntityData()->assignValues(&packet->unpack); - int slot = Inventory::MAX_SELECTION_SIZE; - if (packet->carriedItemId == 0) { - player->inventory->clearSlot(slot); - } else { - ItemInstance newItem(packet->carriedItemId, 1, packet->carriedItemAuxValue); - player->inventory->replaceSlot(slot, &newItem); - } - player->inventory->moveToSelectedSlot(slot, true); - //player->resetPos(); - - std::string message = packet->name.C_String(); - message += " joined the game"; -#ifndef STANDALONE_SERVER - minecraft.gui.addMessage(message); -#endif -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemovePlayerPacket* packet) { - if (!level || source == minecraft.getPlayer()->owner) return; - - if (Player* player = findPlayer(level, packet->entityId, &packet->owner)) { - player->reallyRemoveIfPlayer = true; - level->removeEntity(player); - } - - //for (int i = (int)level->players.size()-1; i >= 0; --i) { - // if (level->players[i]->owner == source) { - // level->players[i]->reallyRemoveIfPlayer = true; - // level->players.erase(level->players.begin() + i); - // break; - // } - //} - - //if (!player) return; - - //std::string message = packet->name.C_String(); - //message += " joined the game"; - //minecraft.gui.addMessage(message); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveEntityPacket* packet) -{ - if (!level) return; - - Entity* entity = level->getEntity(packet->entityId); - LOGI("RemoveEntityPacket %p %p, %d\n", entity, minecraft.getPlayer(), entity?(int)(entity->isPlayer()): -1); - if (!entity) return; - - level->removeEntity(entity); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddItemEntityPacket* packet) -{ - if (!level) return; - - ItemEntity* entity = new ItemEntity(level, packet->x, packet->y, packet->z, ItemInstance(packet->itemId, packet->itemCount, packet->auxValue)); - entity->xd = packet->xa(); - entity->yd = packet->ya(); - entity->zd = packet->za(); - //LOGI("item-entity @ client: %f, %f, %f\n", entity->xd, entity->yd, entity->zd); - - mpcast(level)->putEntity(packet->id, entity); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TakeItemEntityPacket* packet) { - if (!level) return; - - Entity* e = level->getEntity(packet->itemId); - if (!e) - return; - - ItemInstance item; - if (e->isItemEntity()) { - item = ((ItemEntity*) e)->item; -#ifndef STANDALONE_SERVER - if (Entity* to = level->getEntity(packet->playerId)) - minecraft.particleEngine->add(new TakeAnimationParticle(level, (ItemEntity*)e, to, -0.5f)); -#endif - } - else if (e->getEntityTypeId() == EntityTypes::IdArrow) - item = ItemInstance(Item::arrow); - - if (item.isNull()) - return; - - // try take it and if we don't have space; re-throw it - if (minecraft.getPlayer()->entityId == packet->playerId - && !minecraft.getPlayer()->inventory->add(&item)) { - DropItemPacket dropPacket(packet->playerId, item); - minecraft.raknetInstance->send(dropPacket); - } - level->playSound(e, "random.pop", 0.2f, 1.0f * 2.f); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlayerPacket* packet) -{ - if (!level) - return; - - //printf("MovePlayerPacket\n"); - Entity* entity = level->getEntity(packet->entityId); - if (entity) - { - entity->lerpTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot, 3); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MoveEntityPacket* packet) -{ - if (!level) - return; - - //printf("MovePlayerPacket\n"); - Entity* entity = level->getEntity(packet->entityId); - if (entity) - { - float xRot = packet->hasRot? packet->xRot : entity->xRot; - float yRot = packet->hasRot? packet->yRot : entity->yRot; - entity->lerpTo(packet->x, packet->y, packet->z, yRot, xRot, 3); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UpdateBlockPacket* packet) -{ - if (!level) return; - - //LOGI("UpdateBlockPacket @ %d, %d, %d\n", packet->x, packet->y, packet->z); - - int x = packet->x, z = packet->z; - - if (isChunkLoaded(x >> 4, z >> 4)) - { - //LOGI("chunk is loaded - UPDATE @ %d, %d, %d -- %d, %d\n", x, packet->y, z, packet->blockId, packet->blockData); - - int y = packet->y; - int tileId = Tile::transformToValidBlockId(packet->blockId, x, y, z); - level->setTileAndData(x, y, z, tileId, packet->blockData); - } else { - SBufferedBlockUpdate update; - update.blockId = packet->blockId; - update.blockData = packet->blockData; - update.setData = true; - update.x = packet->x; - update.y = packet->y; - update.z = packet->z; - bufferedBlockUpdates.push_back(update); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ExplodePacket* packet) { - if (!level) return; - Explosion explosion(level, NULL, packet->x, packet->y, packet->z, packet->r); - explosion.toBlow.insert(packet->toBlow.begin(), packet->toBlow.end()); - explosion.finalizeExplosion(); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LevelEventPacket* packet) { - if (!level) return; - if(packet->eventId == LevelEvent::ALL_PLAYERS_SLEEPING) { - minecraft.getPlayer()->setAllPlayersSleeping(); - } - else { - minecraft.level->levelEvent(NULL, packet->eventId, packet->x, packet->y, packet->z, packet->data); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TileEventPacket* packet) { - if (!level) return; - minecraft.level->tileEvent(packet->x, packet->y, packet->z, packet->b0, packet->b1); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, EntityEventPacket* packet) { - if (!level) return; - - Entity* e = level->getEntity(packet->entityId); - if (e) e->handleEntityEvent(packet->eventId); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDataPacket* packet) -{ - if (!level) { - LOGI("level @ handle ChunkDataPacket is 0\n"); - return; - } - //LOGI("ChunkDataPacket\n"); - - LevelChunk* chunk = level->getChunkSource()->create(packet->x, packet->z); - if (!chunk || chunk->isEmpty()) - { - LOGI("Failed to find write-able chunk\n"); - return; - } - - //unsigned char* blockIds = chunk->getBlockData(); - DataLayer& blockData = chunk->data; - - const int setSize = LEVEL_HEIGHT / 8; - const int setShift = 4; // power of LEVEL_HEIGHT / 8 - - bool recalcHeight = false; - - int x0 = 16, x1 = 0, z0 = 16, z1 = 0, y0 = LEVEL_HEIGHT, y1 = 0; - int rx = packet->x << 4; - int rz = packet->z << 4; - - unsigned char readBlockBuffer[setSize]; - unsigned char readDataBuffer[setSize / 2]; - - for (int i = 0; i < CHUNK_COLUMNS; i++) - { - unsigned char updateBits = 0; - packet->chunkData.Read(updateBits); - - if (updateBits > 0) - { - recalcHeight = true; - - int colX = (i % CHUNK_WIDTH); - int colZ = (i / CHUNK_WIDTH); - int colDataPosition = colX << 11 | colZ << 7; - - for (int set = 0; set < 8; set++) - { - if ((updateBits & (1 << set)) != 0) - { - packet->chunkData.Read((char*)readBlockBuffer, setSize); - packet->chunkData.Read((char*)readDataBuffer, setSize / 2); - - for (int part = 0; part < setSize; part++) - { - //if (readBlockBuffer[part] == ((Tile*)Tile::grass)->id) - // readBlockBuffer[part] = 255; - int x = rx + colX; - int y = (set << setShift) + part; - int z = rz + colZ; - - int tileId = Tile::transformToValidBlockId(readBlockBuffer[part], x, y, z); - level->setTileNoUpdate(x, y, z, tileId); - } - // ((part & 1) == 0) ? readDataBuffer[part >> 1] & 0xf : (readDataBuffer[part >> 1] & 0xf0) >> 4 - - //packet->chunkData.Read((char*)(&blockIds[colDataPosition + (set << setShift)]), setSize); - // block data is only 4 bits per block - //packet->chunkData.Read((char*)(&blockData.data[(colDataPosition + (set << setShift)) >> 1]), setSize >> 1); - - memcpy(&blockData.data[(colDataPosition + (set << setShift)) >> 1], readDataBuffer, setSize >> 1); - } - - if (((1 << set) << setShift) < y0) - { - y0 = ((1 << set) << setShift); - } - if (((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1 > y1) - { - y1 = ((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1; - } - } - if ((i % CHUNK_WIDTH) < x0) - { - x0 = (i % CHUNK_WIDTH); - } - if ((i % CHUNK_WIDTH) > x1) - { - x1 = (i % CHUNK_WIDTH); - } - if ((i / CHUNK_WIDTH) < z0) - { - z0 = (i / CHUNK_WIDTH); - } - if ((i / CHUNK_WIDTH) > z1) - { - z1 = (i / CHUNK_WIDTH); - } - } - } - - if (recalcHeight) - { -// chunk->recalcHeightmap(); -// //chunk->recalcBlockLights(); - level->setTilesDirty((packet->x << 4) + x0, y0, (packet->z << 4) + z0, (packet->x << 4) + x1, y1, (packet->z << 4) + z1); -// int rx = packet->x << 4; -// int rz = packet->z << 4; -// level->updateLight(LightLayer::Block, x0 + rx - 1, y0, z0 + rz - 1, x1 + rx + 1, y1, z1 + rz + 1); -// //for (int cx = x0; cx < x1; cx++) -// //{ -// // for (int cz = z0; cz < z1; cz++) -// // { -// // for (int cy = y0; cy < y1; cy++) -// // { -// //level->updateLight(LightLayer::Sky, cx + rx, cy, cz + rz, cx + rx, cy, cz + rz); -// // level->updateLight(LightLayer::Block, cx + rx - 1, cy, cz + rz - 1, cx + rx + 1, cy, cz + rz + 1); -// // } -// // } -// //} -// - } - //chunk->terrainPopulated = true; - chunk->unsaved = false; - - chunksLoaded[packet->x * CHUNK_CACHE_WIDTH + packet->z] = true; - - if (areAllChunksLoaded()) - { - ReadyPacket packet(ReadyPacket::READY_REQUESTEDCHUNKS); - raknetInstance->send(packet); - - for (unsigned int i = 0; i < bufferedBlockUpdates.size(); i++) - { - const SBufferedBlockUpdate& update = bufferedBlockUpdates[i]; - int tileId = Tile::transformToValidBlockId( update.blockId, update.x, update.y, update.z ); - if (update.setData) - level->setTileAndData(update.x, update.y, update.z, tileId, update.blockData); - else - level->setTile(update.x, update.y, update.z, tileId); - } - bufferedBlockUpdates.clear(); - } - else - { - requestNextChunk(); - } -} - -class _ChunkSorter -{ -public: - _ChunkSorter(int x, int z) - : x(x), - y(z) - { - } - - bool operator() (const IntPair& a, const IntPair& b) { - const int ax = a.x - x, ay = a.y - y; - const int bx = b.x - x, by = b.y - y; - return (ax*ax + ay*ay) < (bx*bx + by*by); - } -private: - int x; - int y; -}; - - -void ClientSideNetworkHandler::arrangeRequestChunkOrder() { - clearChunksLoaded(); - - // Default sort is around center of the world - int cx = CHUNK_CACHE_WIDTH / 2; - int cz = CHUNK_CACHE_WIDTH / 2; - - // If player exists, let's sort around him - Player* p = minecraft.getPlayer(); - if (p) { - cx = Mth::floor(p->x / (float)CHUNK_WIDTH); - cz = Mth::floor(p->z / (float)CHUNK_DEPTH); - } - - _ChunkSorter sorter(cx, cz); - std::sort(requestNextChunkIndexList, requestNextChunkIndexList + NumRequestChunks, sorter); -} - -void ClientSideNetworkHandler::levelGenerated(Level* level) -{ - this->level = level; - ReadyPacket packet(ReadyPacket::READY_CLIENTGENERATION); - raknetInstance->send(packet); - - arrangeRequestChunkOrder(); - requestNextChunk(); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerEquipmentPacket* packet) -{ - if (!level) - return; - - Entity* entity = level->getEntity(packet->entityId); - if (!entity || !entity->isPlayer()) - return; - - Player* player = (Player*)entity; - // make sure it's not our local player - if (player->owner == rakPeer->GetMyGUID()) - { - printf("Attempted to modify local player's inventory\n"); - return; - } - // override the player's inventory - //int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue); - //if (slot >= 0) { - // player->inventory->moveToSelectedSlot(slot, true); - //item->id = packet->itemId; - //item->setAuxValue(packet->itemAuxValue); - //item->count = 63; - int slot = Inventory::MAX_SELECTION_SIZE; - if (slot >= 0) { - if (packet->itemId == 0) { - player->inventory->clearSlot(slot); - } else { - ItemInstance newItem(packet->itemId, 63, packet->itemAuxValue); - player->inventory->replaceSlot(slot, &newItem); - } - player->inventory->moveToSelectedSlot(slot, true); - } else { - LOGW("Warning: Remote player doesn't have his thing, Odd!\n"); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerArmorEquipmentPacket* packet) { - if (!level) - return; - - Entity* entity = level->getEntity(packet->entityId); - if (!entity || !entity->isPlayer()) - return; - - Player* player = (Player*)entity; - // make sure it's not our local player, since that should be UpdateArmorPacket - if (player->owner == rakPeer->GetMyGUID()) { - printf("Attempted to modify local player's armor visually\n"); - return; - } - - packet->fillIn(player); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, InteractPacket* packet) -{ - if (!level) - return; - - Entity* src = level->getEntity(packet->sourceId); - Entity* entity = level->getEntity(packet->targetId); - if (src && entity && src->isPlayer()) - { - Player* player = (Player*) src; - if (InteractPacket::Attack == packet->action) - minecraft.gameMode->attack(player, entity); - if (InteractPacket::Interact == packet->action) - minecraft.gameMode->interact(player, entity); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetEntityDataPacket* packet) -{ - if (!level) - return; - - LOGI("SetEntityDataPacket\n"); - - Entity* e = level->getEntity(packet->id); - if (e) { - SynchedEntityData* data = e->getEntityData(); - if (data) - data->assignValues(&packet->getUnpackedData()); - } -} - -void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SetEntityMotionPacket* packet ) -{ - if (!level) - return; - - if (Entity* e = level->getEntity(packet->id)) { - /* - e->xd = packet->xd; - e->yd = packet->yd; - e->zd = packet->zd; - */ - e->lerpMotion(packet->xd, packet->yd, packet->zd); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimatePacket* packet) -{ - if (!level) - return; - - // Own player - Then don't play... : - if (minecraft.getPlayer()->entityId == packet->entityId) { - if (packet->action == AnimatePacket::Swing) return; - } - - Entity* entity = level->getEntity(packet->entityId); - if (!entity || !entity->isPlayer()) - return; - - Player* player = (Player*) entity; - - switch (packet->action) { - case AnimatePacket::Swing: - player->swing(); - break; - case AnimatePacket::WAKE_UP: - player->stopSleepInBed(false, false, false); - break; - default: - LOGW("Unknown Animate action: %d\n", packet->action); - break; - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) -{ -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetHealthPacket* packet) -{ - if (!level || !minecraft.getPlayer()) - return; - - minecraft.getPlayer()->hurtTo(packet->health); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetSpawnPositionPacket* packet) { - if (!level || !minecraft.getPlayer()) return; - if (!level->inRange(packet->x, packet->y, packet->z)) return; - - minecraft.getPlayer()->setRespawnPosition(Pos(packet->x, packet->y, packet->z)); - level->getLevelData()->setSpawn(packet->x, packet->y, packet->z); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, HurtArmorPacket* packet) { - if (!level || !minecraft.getPlayer()) { - return; - } - - minecraft.getPlayer()->hurtArmor(packet->dmg); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RespawnPacket* packet) -{ - if (level) { - //LOGI("RespawnPacket! %d\n", findPlayer(level, packet->entityId, NULL)); - NetEventCallback::handle(level, source, packet ); - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerOpenPacket* packet) -{ - if (!level) - return; - - if (packet->type == ContainerType::FURNACE) { - FurnaceTileEntity* te = new FurnaceTileEntity(); - te->clientSideOnly = true; - minecraft.getPlayer()->openFurnace(te); - if (minecraft.getPlayer()->containerMenu) - minecraft.getPlayer()->containerMenu->containerId = packet->containerId; - } - if (packet->type == ContainerType::CONTAINER) { - ChestTileEntity* te = new ChestTileEntity(); - te->clientSideOnly = true; - minecraft.getPlayer()->openContainer(te); - if (minecraft.getPlayer()->containerMenu) - minecraft.getPlayer()->containerMenu->containerId = packet->containerId; - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet) -{ - if (minecraft.getPlayer() && minecraft.getPlayer()->containerMenu) - minecraft.getPlayer()->closeContainer(); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetContentPacket* packet) -{ - if (!minecraft.getPlayer()) - return; - - if (packet->containerId == 0) { - for (unsigned int i = 0; i < packet->items.size(); ++i) { - minecraft.getPlayer()->inventory->setItem(Inventory::MAX_SELECTION_SIZE + i, &packet->items[i]); - } - } else if (minecraft.getPlayer()->containerMenu && minecraft.getPlayer()->containerMenu->containerId == packet->containerId) { - for (unsigned int i = 0; i < packet->items.size(); ++i) { - minecraft.getPlayer()->containerMenu->setSlot(i, &packet->items[i]); - } - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetSlotPacket* packet) -{ - //LOGI("ContainerSetSlot\n"); - - if (!minecraft.getPlayer() - || !minecraft.getPlayer()->containerMenu - || minecraft.getPlayer()->containerMenu->containerId != packet->containerId) - return; - - //minecraft.getPlayer()->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); - minecraft.getPlayer()->containerMenu->setSlot(packet->slot, &packet->item); -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetDataPacket* packet) -{ - //LOGI("ContainerSetData\n"); - if (minecraft.getPlayer() && minecraft.getPlayer()->containerMenu && minecraft.getPlayer()->containerMenu->containerId == packet->containerId) { - //LOGI("client: SetData2 %d, %d\n", packet->id, packet->value); - minecraft.getPlayer()->containerMenu->setData(packet->id, packet->value); - } -} - -void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, ChatPacket* packet ) -{ -#ifndef STANDALONE_SERVER - minecraft.gui.displayClientMessage(packet->message); -#endif -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet) -{ - if (!level) - return; - - TileEntity* te = level->getTileEntity(packet->x, packet->y, packet->z); - if (TileEntity::isType(te, TileEntityType::Sign)) { - SignTileEntity* ste = (SignTileEntity*) te; - if (ste->isEditable()) { - for (int i = 0; i < SignTileEntity::NUM_LINES; i++) { - ste->messages[i] = packet->lines[i]; - } - //ste->setChanged(); - } - } -} - -void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet) { - if (!level) - return; - //assert(level != NULL && "level is NULL @ handle(AdventureSettingsPacket*)"); - - packet->fillIn(level->adventureSettings); -} - -void ClientSideNetworkHandler::clearChunksLoaded() -{ - // Init the chunk positions - for (int i = 0; i < NumRequestChunks; ++i) { - requestNextChunkIndexList[i].x = i/CHUNK_WIDTH; - requestNextChunkIndexList[i].y = i%CHUNK_WIDTH; - chunksLoaded[i] = false; - } -} +#include "ClientSideNetworkHandler.hpp" +#include +#include "client/Options.hpp" +#include "gamemode/GameMode.hpp" +#include "packet/PacketInclude.hpp" +#include "RakNetInstance.hpp" +#include "world/level/chunk/ChunkSource.hpp" +#include "world/level/Level.hpp" +#include "world/level/storage/LevelStorageSource.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/player/Inventory.hpp" +#include +#include "client/player/LocalPlayer.hpp" +#include "client/multiplayer/MultiPlayerLevel.hpp" +#include "client/player/input/KeyboardInput.hpp" +#include "client/sound/SoundEngine.hpp" +#include "world/entity/MobFactory.hpp" +#include "raknet/RakPeerInterface.h" +#include "world/level/Explosion.hpp" +#include "world/level/tile/entity/FurnaceTileEntity.hpp" +#include "world/inventory/BaseContainerMenu.hpp" +#include "world/entity/EntityFactory.hpp" +#include "world/entity/item/PrimedTnt.hpp" +#include "world/entity/projectile/Arrow.hpp" +#include "world/level/tile/entity/ChestTileEntity.hpp" +#include "client/player/RemotePlayer.hpp" +#include "world/level/tile/LevelEvent.hpp" +#include "world/entity/item/FallingTile.hpp" + +static MultiPlayerLevel* mpcast(Level* l) { return (MultiPlayerLevel*) l; } + +ClientSideNetworkHandler::ClientSideNetworkHandler(MinecraftClient& minecraft, IRakNetInstance* raknetInstance) +: minecraft(minecraft), + raknetInstance(raknetInstance) +{ + rakPeer = raknetInstance->getPeer(); +} + +ClientSideNetworkHandler::~ClientSideNetworkHandler() +{ +} + +void ClientSideNetworkHandler::requestNextChunk() +{ + if (requestNextChunkIndex < NumRequestChunks) + { + IntPair& chunk = requestNextChunkIndexList[requestNextChunkIndex]; + RequestChunkPacket packet(chunk.x, chunk.y); + raknetInstance->send(packet); + + //LOGI("requesting chunks @ (%d, %d)\n", chunk.x, chunk.y); + + //raknetInstance->send(new RequestChunkPacket(requestNextChunkPosition % CHUNK_CACHE_WIDTH, requestNextChunkPosition / CHUNK_CACHE_WIDTH)); + requestNextChunkIndex++; + requestNextChunkPosition++; + } +} + +bool ClientSideNetworkHandler::areAllChunksLoaded() +{ + return (requestNextChunkPosition >= (CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH)); +} + +bool ClientSideNetworkHandler::isChunkLoaded(int x, int z) +{ + if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH) { + LOGE("Error: Tried to request chunk (%d, %d)\n", x, z); + return true; + } + return chunksLoaded[x * CHUNK_CACHE_WIDTH + z]; + //return areAllChunksLoaded(); +} + +void ClientSideNetworkHandler::onConnect(const RakNet::RakNetGUID& hostGuid) +{ + LOGI("onConnect, server guid: %s, local guid: %s\n", hostGuid.ToString(), rakPeer->GetMyGUID().ToString()); + serverGuid = hostGuid; + + clearChunksLoaded(); + LoginPacket packet(minecraft.options().getStringValue(OPTIONS_USERNAME).c_str(), SharedConstants::NetworkProtocolVersion); + raknetInstance->send(packet); +} + +void ClientSideNetworkHandler::onUnableToConnect() +{ + LOGI("onUnableToConnect\n"); +} + +void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) +{ + LOGI("onDisconnect\n"); + if (level) + { + level->isClientSide = false; + for (int i = (int)level->players.size()-1; i >= 0; --i ) { + Player* p = level->players[i]; + if (p != minecraft.getPlayer()) { + p->reallyRemoveIfPlayer = true; + level->removeEntity(p); + } + } + } +#ifndef STANDALONE_SERVER + minecraft.gui.addMessage("Disconnected from server"); +#endif +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginStatusPacket* packet) { + if (packet->status == LoginStatus::Success) { + raknetInstance->setIsLoggedIn(true); + return; + } + + if (packet->status == LoginStatus::Failed_ClientOld) { + LOGI("Disconnect! Client is outdated!\n"); +#ifndef STANDALONE_SERVER + minecraft.setScreen(new DisconnectionScreen("Could not connect: Outdated client!")); +#endif + } + if (packet->status == LoginStatus::Failed_ServerOld) { + LOGI("Disconnect! Server is outdated!\n"); +#ifndef STANDALONE_SERVER + minecraft.setScreen(new DisconnectionScreen("Could not connect: Outdated server!")); +#endif + } +} + + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, StartGamePacket* packet) +{ + LOGI("StartGamePacket\n"); + +#ifdef RPI + if (packet->gameType != GameType::Creative) { + minecraft.setScreen(new DisconnectionScreen("Could not connect: Incompatible server!")); + return; + } +#endif + + const std::string& levelId = LevelStorageSource::TempLevelId; + LevelStorageSource* storageSource = minecraft.getLevelSource(); + storageSource->deleteLevel(levelId); + //level = new Level(storageSource->selectLevel(levelId, true), "temp", packet->levelSeed, SharedConstants::StorageVersion); + MultiPlayerLevel* level = new MultiPlayerLevel( + storageSource->selectLevel(levelId, true), + "temp", + LevelSettings(packet->levelSeed, LevelSettings::validateGameType(packet->gameType)), + SharedConstants::StorageVersion); + level->isClientSide = true; + + bool isCreative = (packet->gameType == GameType::Creative); + LocalPlayer* player = new LocalPlayer(minecraft, level, minecraft.options().getStringValue(OPTIONS_USERNAME), level->dimension->id, isCreative); + player->owner = rakPeer->GetMyGUID(); + player->entityId = packet->entityId; + player->moveTo(packet->x, packet->y, packet->z, player->yRot, player->xRot); + + LOGI("new pos: %f, %f [%f - %f]\n", player->x, player->z, player->bb.y0, player->bb.y1); + + minecraft.setLevel(level, "ClientSideNetworkHandler -> setLevel", player); + minecraft.setIsCreativeMode(isCreative); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MessagePacket* packet) +{ + LOGI("MessagePacket\n"); +#ifndef STANDALONE_SERVER + minecraft.gui.addMessage(packet->message.C_String()); +#endif +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetTimePacket* packet) +{ + if (!level) + return; + + LOGI("SetTimePacket\n"); + level->setTime(packet->time); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddEntityPacket* packet) +{ + if (!level) + return; + + Entity* e = EntityFactory::CreateEntity(packet->type, level); + if (!e) + return; + + e->entityId = packet->entityId; + e->setPos(packet->x, packet->y, packet->z); + + // Entity Specific stuff here + switch (packet->type) + { + case EntityTypes::IdFallingTile: { + int data = -packet->data(); + FallingTile* ft = (FallingTile*) e; + ft->tile = data & 0xff; + ft->data = data >> 16; + } + case EntityTypes::IdArrow: { + Entity* owner = level->getEntity(packet->data()); + if (owner && owner->isMob()) + ((Arrow*)e)->ownerId = owner->entityId; + break; + } + default: + break; + } + + if (packet->hasMovementData()) { + /* + e->xd = packet->xd; + e->yd = packet->yd; + e->zd = packet->zd; + */ + e->lerpMotion(packet->xd, packet->yd, packet->zd); + //LOGI("Client: reading entity with %f, %f, %f\n", e->xd, e->yd, e->zd); + } + + mpcast(level)->putEntity(packet->entityId, e); +} +void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, AddPaintingPacket* packet ) { + if (!level) + return; + + Painting* painting = new Painting(level, packet->xTile, packet->yTile, packet->zTile, packet->dir, packet->motive); + mpcast(level)->putEntity(packet->entityId, painting); +} +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddMobPacket* packet) +{ + LOGI("AddMobPacket (%p)\n", level); + + if (!level) { + LOGW("Trying to add a mob with no level!\n"); + //we skip this since we will get this player anyway when we request level + return; + } + if (!packet->type) { + LOGE("Trying to add a mob without a type id\n"); + return; + } + + Mob* mob = MobFactory::CreateMob(packet->type, level); + if (!mob) { + LOGE("Server tried to add an unknown mob type! :%d\n", packet->type); + return; + } + + mob->entityId = packet->entityId; + mob->moveTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot); + mob->getEntityData()->assignValues(&packet->unpack); + level->addEntity(mob); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddPlayerPacket* packet) +{ + if (!level) { + //we skip this since we will get this player anyway when we request level + return; + } + LOGI("AddPlayerPacket\n"); + + Player* player = new RemotePlayer(level, minecraft.isCreativeMode()); + minecraft.gameMode->initAbilities(player->abilities); + player->entityId = packet->entityId; + level->addEntity(player); + + player->moveTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot); + player->name = packet->name.C_String(); + player->owner = packet->owner; + player->getEntityData()->assignValues(&packet->unpack); + int slot = Inventory::MAX_SELECTION_SIZE; + if (packet->carriedItemId == 0) { + player->inventory->clearSlot(slot); + } else { + ItemInstance newItem(packet->carriedItemId, 1, packet->carriedItemAuxValue); + player->inventory->replaceSlot(slot, &newItem); + } + player->inventory->moveToSelectedSlot(slot, true); + //player->resetPos(); + + std::string message = packet->name.C_String(); + message += " joined the game"; +#ifndef STANDALONE_SERVER + minecraft.gui.addMessage(message); +#endif +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemovePlayerPacket* packet) { + if (!level || source == minecraft.getPlayer()->owner) return; + + if (Player* player = findPlayer(level, packet->entityId, &packet->owner)) { + player->reallyRemoveIfPlayer = true; + level->removeEntity(player); + } + + //for (int i = (int)level->players.size()-1; i >= 0; --i) { + // if (level->players[i]->owner == source) { + // level->players[i]->reallyRemoveIfPlayer = true; + // level->players.erase(level->players.begin() + i); + // break; + // } + //} + + //if (!player) return; + + //std::string message = packet->name.C_String(); + //message += " joined the game"; + //minecraft.gui.addMessage(message); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveEntityPacket* packet) +{ + if (!level) return; + + Entity* entity = level->getEntity(packet->entityId); + LOGI("RemoveEntityPacket %p %p, %d\n", entity, minecraft.getPlayer(), entity?(int)(entity->isPlayer()): -1); + if (!entity) return; + + level->removeEntity(entity); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddItemEntityPacket* packet) +{ + if (!level) return; + + ItemEntity* entity = new ItemEntity(level, packet->x, packet->y, packet->z, ItemInstance(packet->itemId, packet->itemCount, packet->auxValue)); + entity->xd = packet->xa(); + entity->yd = packet->ya(); + entity->zd = packet->za(); + //LOGI("item-entity @ client: %f, %f, %f\n", entity->xd, entity->yd, entity->zd); + + mpcast(level)->putEntity(packet->id, entity); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TakeItemEntityPacket* packet) { + if (!level) return; + + Entity* e = level->getEntity(packet->itemId); + if (!e) + return; + + ItemInstance item; + if (e->isItemEntity()) { + item = ((ItemEntity*) e)->item; +#ifndef STANDALONE_SERVER + if (Entity* to = level->getEntity(packet->playerId)) + minecraft.particleEngine->add(new TakeAnimationParticle(level, (ItemEntity*)e, to, -0.5f)); +#endif + } + else if (e->getEntityTypeId() == EntityTypes::IdArrow) + item = ItemInstance(Item::arrow); + + if (item.isNull()) + return; + + // try take it and if we don't have space; re-throw it + if (minecraft.getPlayer()->entityId == packet->playerId + && !minecraft.getPlayer()->inventory->add(&item)) { + DropItemPacket dropPacket(packet->playerId, item); + minecraft.raknetInstance->send(dropPacket); + } + level->playSound(e, "random.pop", 0.2f, 1.0f * 2.f); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlayerPacket* packet) +{ + if (!level) + return; + + //printf("MovePlayerPacket\n"); + Entity* entity = level->getEntity(packet->entityId); + if (entity) + { + entity->lerpTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot, 3); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MoveEntityPacket* packet) +{ + if (!level) + return; + + //printf("MovePlayerPacket\n"); + Entity* entity = level->getEntity(packet->entityId); + if (entity) + { + float xRot = packet->hasRot? packet->xRot : entity->xRot; + float yRot = packet->hasRot? packet->yRot : entity->yRot; + entity->lerpTo(packet->x, packet->y, packet->z, yRot, xRot, 3); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UpdateBlockPacket* packet) +{ + if (!level) return; + + //LOGI("UpdateBlockPacket @ %d, %d, %d\n", packet->x, packet->y, packet->z); + + int x = packet->x, z = packet->z; + + if (isChunkLoaded(x >> 4, z >> 4)) + { + //LOGI("chunk is loaded - UPDATE @ %d, %d, %d -- %d, %d\n", x, packet->y, z, packet->blockId, packet->blockData); + + int y = packet->y; + int tileId = Tile::transformToValidBlockId(packet->blockId, x, y, z); + level->setTileAndData(x, y, z, tileId, packet->blockData); + } else { + SBufferedBlockUpdate update; + update.blockId = packet->blockId; + update.blockData = packet->blockData; + update.setData = true; + update.x = packet->x; + update.y = packet->y; + update.z = packet->z; + bufferedBlockUpdates.push_back(update); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ExplodePacket* packet) { + if (!level) return; + Explosion explosion(level, NULL, packet->x, packet->y, packet->z, packet->r); + explosion.toBlow.insert(packet->toBlow.begin(), packet->toBlow.end()); + explosion.finalizeExplosion(); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LevelEventPacket* packet) { + if (!level) return; + if(packet->eventId == LevelEvent::ALL_PLAYERS_SLEEPING) { + minecraft.getPlayer()->setAllPlayersSleeping(); + } + else { + minecraft.level->levelEvent(NULL, packet->eventId, packet->x, packet->y, packet->z, packet->data); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TileEventPacket* packet) { + if (!level) return; + minecraft.level->tileEvent(packet->x, packet->y, packet->z, packet->b0, packet->b1); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, EntityEventPacket* packet) { + if (!level) return; + + Entity* e = level->getEntity(packet->entityId); + if (e) e->handleEntityEvent(packet->eventId); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDataPacket* packet) +{ + if (!level) { + LOGI("level @ handle ChunkDataPacket is 0\n"); + return; + } + //LOGI("ChunkDataPacket\n"); + + LevelChunk* chunk = level->getChunkSource()->create(packet->x, packet->z); + if (!chunk || chunk->isEmpty()) + { + LOGI("Failed to find write-able chunk\n"); + return; + } + + //unsigned char* blockIds = chunk->getBlockData(); + DataLayer& blockData = chunk->data; + + const int setSize = LEVEL_HEIGHT / 8; + const int setShift = 4; // power of LEVEL_HEIGHT / 8 + + bool recalcHeight = false; + + int x0 = 16, x1 = 0, z0 = 16, z1 = 0, y0 = LEVEL_HEIGHT, y1 = 0; + int rx = packet->x << 4; + int rz = packet->z << 4; + + unsigned char readBlockBuffer[setSize]; + unsigned char readDataBuffer[setSize / 2]; + + for (int i = 0; i < CHUNK_COLUMNS; i++) + { + unsigned char updateBits = 0; + packet->chunkData.Read(updateBits); + + if (updateBits > 0) + { + recalcHeight = true; + + int colX = (i % CHUNK_WIDTH); + int colZ = (i / CHUNK_WIDTH); + int colDataPosition = colX << 11 | colZ << 7; + + for (int set = 0; set < 8; set++) + { + if ((updateBits & (1 << set)) != 0) + { + packet->chunkData.Read((char*)readBlockBuffer, setSize); + packet->chunkData.Read((char*)readDataBuffer, setSize / 2); + + for (int part = 0; part < setSize; part++) + { + //if (readBlockBuffer[part] == ((Tile*)Tile::grass)->id) + // readBlockBuffer[part] = 255; + int x = rx + colX; + int y = (set << setShift) + part; + int z = rz + colZ; + + int tileId = Tile::transformToValidBlockId(readBlockBuffer[part], x, y, z); + level->setTileNoUpdate(x, y, z, tileId); + } + // ((part & 1) == 0) ? readDataBuffer[part >> 1] & 0xf : (readDataBuffer[part >> 1] & 0xf0) >> 4 + + //packet->chunkData.Read((char*)(&blockIds[colDataPosition + (set << setShift)]), setSize); + // block data is only 4 bits per block + //packet->chunkData.Read((char*)(&blockData.data[(colDataPosition + (set << setShift)) >> 1]), setSize >> 1); + + memcpy(&blockData.data[(colDataPosition + (set << setShift)) >> 1], readDataBuffer, setSize >> 1); + } + + if (((1 << set) << setShift) < y0) + { + y0 = ((1 << set) << setShift); + } + if (((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1 > y1) + { + y1 = ((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1; + } + } + if ((i % CHUNK_WIDTH) < x0) + { + x0 = (i % CHUNK_WIDTH); + } + if ((i % CHUNK_WIDTH) > x1) + { + x1 = (i % CHUNK_WIDTH); + } + if ((i / CHUNK_WIDTH) < z0) + { + z0 = (i / CHUNK_WIDTH); + } + if ((i / CHUNK_WIDTH) > z1) + { + z1 = (i / CHUNK_WIDTH); + } + } + } + + if (recalcHeight) + { +// chunk->recalcHeightmap(); +// //chunk->recalcBlockLights(); + level->setTilesDirty((packet->x << 4) + x0, y0, (packet->z << 4) + z0, (packet->x << 4) + x1, y1, (packet->z << 4) + z1); +// int rx = packet->x << 4; +// int rz = packet->z << 4; +// level->updateLight(LightLayer::Block, x0 + rx - 1, y0, z0 + rz - 1, x1 + rx + 1, y1, z1 + rz + 1); +// //for (int cx = x0; cx < x1; cx++) +// //{ +// // for (int cz = z0; cz < z1; cz++) +// // { +// // for (int cy = y0; cy < y1; cy++) +// // { +// //level->updateLight(LightLayer::Sky, cx + rx, cy, cz + rz, cx + rx, cy, cz + rz); +// // level->updateLight(LightLayer::Block, cx + rx - 1, cy, cz + rz - 1, cx + rx + 1, cy, cz + rz + 1); +// // } +// // } +// //} +// + } + //chunk->terrainPopulated = true; + chunk->unsaved = false; + + chunksLoaded[packet->x * CHUNK_CACHE_WIDTH + packet->z] = true; + + if (areAllChunksLoaded()) + { + ReadyPacket packet(ReadyPacket::READY_REQUESTEDCHUNKS); + raknetInstance->send(packet); + + for (unsigned int i = 0; i < bufferedBlockUpdates.size(); i++) + { + const SBufferedBlockUpdate& update = bufferedBlockUpdates[i]; + int tileId = Tile::transformToValidBlockId( update.blockId, update.x, update.y, update.z ); + if (update.setData) + level->setTileAndData(update.x, update.y, update.z, tileId, update.blockData); + else + level->setTile(update.x, update.y, update.z, tileId); + } + bufferedBlockUpdates.clear(); + } + else + { + requestNextChunk(); + } +} + +class _ChunkSorter +{ +public: + _ChunkSorter(int x, int z) + : x(x), + y(z) + { + } + + bool operator() (const IntPair& a, const IntPair& b) { + const int ax = a.x - x, ay = a.y - y; + const int bx = b.x - x, by = b.y - y; + return (ax*ax + ay*ay) < (bx*bx + by*by); + } +private: + int x; + int y; +}; + + +void ClientSideNetworkHandler::arrangeRequestChunkOrder() { + clearChunksLoaded(); + + // Default sort is around center of the world + int cx = CHUNK_CACHE_WIDTH / 2; + int cz = CHUNK_CACHE_WIDTH / 2; + + // If player exists, let's sort around him + Player* p = minecraft.getPlayer(); + if (p) { + cx = Mth::floor(p->x / (float)CHUNK_WIDTH); + cz = Mth::floor(p->z / (float)CHUNK_DEPTH); + } + + _ChunkSorter sorter(cx, cz); + std::sort(requestNextChunkIndexList, requestNextChunkIndexList + NumRequestChunks, sorter); +} + +void ClientSideNetworkHandler::levelGenerated(Level* level) +{ + this->level = level; + ReadyPacket packet(ReadyPacket::READY_CLIENTGENERATION); + raknetInstance->send(packet); + + arrangeRequestChunkOrder(); + requestNextChunk(); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerEquipmentPacket* packet) +{ + if (!level) + return; + + Entity* entity = level->getEntity(packet->entityId); + if (!entity || !entity->isPlayer()) + return; + + Player* player = (Player*)entity; + // make sure it's not our local player + if (player->owner == rakPeer->GetMyGUID()) + { + printf("Attempted to modify local player's inventory\n"); + return; + } + // override the player's inventory + //int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue); + //if (slot >= 0) { + // player->inventory->moveToSelectedSlot(slot, true); + //item->id = packet->itemId; + //item->setAuxValue(packet->itemAuxValue); + //item->count = 63; + int slot = Inventory::MAX_SELECTION_SIZE; + if (slot >= 0) { + if (packet->itemId == 0) { + player->inventory->clearSlot(slot); + } else { + ItemInstance newItem(packet->itemId, 63, packet->itemAuxValue); + player->inventory->replaceSlot(slot, &newItem); + } + player->inventory->moveToSelectedSlot(slot, true); + } else { + LOGW("Warning: Remote player doesn't have his thing, Odd!\n"); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerArmorEquipmentPacket* packet) { + if (!level) + return; + + Entity* entity = level->getEntity(packet->entityId); + if (!entity || !entity->isPlayer()) + return; + + Player* player = (Player*)entity; + // make sure it's not our local player, since that should be UpdateArmorPacket + if (player->owner == rakPeer->GetMyGUID()) { + printf("Attempted to modify local player's armor visually\n"); + return; + } + + packet->fillIn(player); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, InteractPacket* packet) +{ + if (!level) + return; + + Entity* src = level->getEntity(packet->sourceId); + Entity* entity = level->getEntity(packet->targetId); + if (src && entity && src->isPlayer()) + { + Player* player = (Player*) src; + if (InteractPacket::Attack == packet->action) + minecraft.gameMode->attack(player, entity); + if (InteractPacket::Interact == packet->action) + minecraft.gameMode->interact(player, entity); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetEntityDataPacket* packet) +{ + if (!level) + return; + + LOGI("SetEntityDataPacket\n"); + + Entity* e = level->getEntity(packet->id); + if (e) { + SynchedEntityData* data = e->getEntityData(); + if (data) + data->assignValues(&packet->getUnpackedData()); + } +} + +void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SetEntityMotionPacket* packet ) +{ + if (!level) + return; + + if (Entity* e = level->getEntity(packet->id)) { + /* + e->xd = packet->xd; + e->yd = packet->yd; + e->zd = packet->zd; + */ + e->lerpMotion(packet->xd, packet->yd, packet->zd); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimatePacket* packet) +{ + if (!level) + return; + + // Own player - Then don't play... : + if (minecraft.getPlayer()->entityId == packet->entityId) { + if (packet->action == AnimatePacket::Swing) return; + } + + Entity* entity = level->getEntity(packet->entityId); + if (!entity || !entity->isPlayer()) + return; + + Player* player = (Player*) entity; + + switch (packet->action) { + case AnimatePacket::Swing: + player->swing(); + break; + case AnimatePacket::WAKE_UP: + player->stopSleepInBed(false, false, false); + break; + default: + LOGW("Unknown Animate action: %d\n", packet->action); + break; + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) +{ +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetHealthPacket* packet) +{ + if (!level || !minecraft.getPlayer()) + return; + + minecraft.getPlayer()->hurtTo(packet->health); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetSpawnPositionPacket* packet) { + if (!level || !minecraft.getPlayer()) return; + if (!level->inRange(packet->x, packet->y, packet->z)) return; + + minecraft.getPlayer()->setRespawnPosition(Pos(packet->x, packet->y, packet->z)); + level->getLevelData()->setSpawn(packet->x, packet->y, packet->z); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, HurtArmorPacket* packet) { + if (!level || !minecraft.getPlayer()) { + return; + } + + minecraft.getPlayer()->hurtArmor(packet->dmg); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RespawnPacket* packet) +{ + if (level) { + //LOGI("RespawnPacket! %d\n", findPlayer(level, packet->entityId, NULL)); + NetEventCallback::handle(level, source, packet ); + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerOpenPacket* packet) +{ + if (!level) + return; + + if (packet->type == ContainerType::FURNACE) { + FurnaceTileEntity* te = new FurnaceTileEntity(); + te->clientSideOnly = true; + minecraft.getPlayer()->openFurnace(te); + if (minecraft.getPlayer()->containerMenu) + minecraft.getPlayer()->containerMenu->containerId = packet->containerId; + } + if (packet->type == ContainerType::CONTAINER) { + ChestTileEntity* te = new ChestTileEntity(); + te->clientSideOnly = true; + minecraft.getPlayer()->openContainer(te); + if (minecraft.getPlayer()->containerMenu) + minecraft.getPlayer()->containerMenu->containerId = packet->containerId; + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet) +{ + if (minecraft.getPlayer() && minecraft.getPlayer()->containerMenu) + minecraft.getPlayer()->closeContainer(); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetContentPacket* packet) +{ + if (!minecraft.getPlayer()) + return; + + if (packet->containerId == 0) { + for (unsigned int i = 0; i < packet->items.size(); ++i) { + minecraft.getPlayer()->inventory->setItem(Inventory::MAX_SELECTION_SIZE + i, &packet->items[i]); + } + } else if (minecraft.getPlayer()->containerMenu && minecraft.getPlayer()->containerMenu->containerId == packet->containerId) { + for (unsigned int i = 0; i < packet->items.size(); ++i) { + minecraft.getPlayer()->containerMenu->setSlot(i, &packet->items[i]); + } + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetSlotPacket* packet) +{ + //LOGI("ContainerSetSlot\n"); + + if (!minecraft.getPlayer() + || !minecraft.getPlayer()->containerMenu + || minecraft.getPlayer()->containerMenu->containerId != packet->containerId) + return; + + //minecraft.getPlayer()->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); + minecraft.getPlayer()->containerMenu->setSlot(packet->slot, &packet->item); +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetDataPacket* packet) +{ + //LOGI("ContainerSetData\n"); + if (minecraft.getPlayer() && minecraft.getPlayer()->containerMenu && minecraft.getPlayer()->containerMenu->containerId == packet->containerId) { + //LOGI("client: SetData2 %d, %d\n", packet->id, packet->value); + minecraft.getPlayer()->containerMenu->setData(packet->id, packet->value); + } +} + +void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, ChatPacket* packet ) +{ +#ifndef STANDALONE_SERVER + minecraft.gui.displayClientMessage(packet->message); +#endif +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet) +{ + if (!level) + return; + + TileEntity* te = level->getTileEntity(packet->x, packet->y, packet->z); + if (TileEntity::isType(te, TileEntityType::Sign)) { + SignTileEntity* ste = (SignTileEntity*) te; + if (ste->isEditable()) { + for (int i = 0; i < SignTileEntity::NUM_LINES; i++) { + ste->messages[i] = packet->lines[i]; + } + //ste->setChanged(); + } + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet) { + if (!level) + return; + //assert(level != NULL && "level is NULL @ handle(AdventureSettingsPacket*)"); + + packet->fillIn(level->adventureSettings); +} + +void ClientSideNetworkHandler::clearChunksLoaded() +{ + // Init the chunk positions + for (int i = 0; i < NumRequestChunks; ++i) { + requestNextChunkIndexList[i].x = i/CHUNK_WIDTH; + requestNextChunkIndexList[i].y = i%CHUNK_WIDTH; + chunksLoaded[i] = false; + } +} diff --git a/src/network/ClientSideNetworkHandler.h b/src/network/ClientSideNetworkHandler.hpp similarity index 97% rename from src/network/ClientSideNetworkHandler.h rename to src/network/ClientSideNetworkHandler.hpp index 8843aec..a0a7f33 100755 --- a/src/network/ClientSideNetworkHandler.h +++ b/src/network/ClientSideNetworkHandler.hpp @@ -1,9 +1,9 @@ #pragma once -#include "NetEventCallback.h" -#include "../raknet/RakNetTypes.h" -#include "../world/level/LevelConstants.h" +#include "NetEventCallback.hpp" +#include "raknet/RakNetTypes.h" +#include "world/level/LevelConstants.hpp" #include diff --git a/src/network/NATPunchHandler.cpp b/src/network/NATPunchHandler.cpp index 35108b0..33b4942 100755 --- a/src/network/NATPunchHandler.cpp +++ b/src/network/NATPunchHandler.cpp @@ -1,33 +1,33 @@ -#include "NATPunchHandler.h" -#include "../raknet/TCPInterface.h" -#include "../raknet/HTTPConnection.h" -#include "PHPDirectoryServer2.h" - -using namespace RakNet; -NATPuchHandler::NATPuchHandler() { - tcpInterface = new TCPInterface; -} -NATPuchHandler::~NATPuchHandler() { - delete tcpInterface; -} - -void NATPuchHandler::initialize() { - tcpInterface->Start(0, 64); -} - -void NATPuchHandler::registerToGameList(const RakNet::RakString& serverName, int port) { - HTTPConnection httpConnection; - httpConnection.Init(tcpInterface, "johanbernhardsson.se"); - PHPDirectoryServer2 directoryServer; - directoryServer.Init(&httpConnection, "/DirectoryServer.php"); - directoryServer.UploadTable("", serverName, port, true); -} - -void NATPuchHandler::removeFromGameList() { - -} - -void NATPuchHandler::close() { - -} - +#include "NATPunchHandler.h" +#include "raknet/TCPInterface.h" +#include "raknet/HTTPConnection.h" +#include "PHPDirectoryServer2.hpp" + +using namespace RakNet; +NATPuchHandler::NATPuchHandler() { + tcpInterface = new TCPInterface; +} +NATPuchHandler::~NATPuchHandler() { + delete tcpInterface; +} + +void NATPuchHandler::initialize() { + tcpInterface->Start(0, 64); +} + +void NATPuchHandler::registerToGameList(const RakNet::RakString& serverName, int port) { + HTTPConnection httpConnection; + httpConnection.Init(tcpInterface, "johanbernhardsson.se"); + PHPDirectoryServer2 directoryServer; + directoryServer.Init(&httpConnection, "/DirectoryServer.php"); + directoryServer.UploadTable("", serverName, port, true); +} + +void NATPuchHandler::removeFromGameList() { + +} + +void NATPuchHandler::close() { + +} + diff --git a/src/network/NATPunchHandler.h b/src/network/NATPunchHandler.hpp similarity index 86% rename from src/network/NATPunchHandler.h rename to src/network/NATPunchHandler.hpp index 4f2ff05..70cfad3 100755 --- a/src/network/NATPunchHandler.h +++ b/src/network/NATPunchHandler.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../raknet/TCPInterface.h" -#include "../raknet/RakString.h" +#include "raknet/TCPInterface.h" +#include "raknet/RakString.h" class NATPuchHandler { public: enum NATPuchHandlerStatus { diff --git a/src/network/NetEventCallback.cpp b/src/network/NetEventCallback.cpp index aa10752..3b5bdf2 100755 --- a/src/network/NetEventCallback.cpp +++ b/src/network/NetEventCallback.cpp @@ -1,59 +1,59 @@ -#include "NetEventCallback.h" -#include "../world/level/Level.h" -#include "packet/RespawnPacket.h" - -// -// Common packet handling implementation for Client and Server -// -/* -void NetEventCallback::handle( const RakNet::RakNetGUID& source, AnimatePacket* packet ) -{ - Entity* entity = level->getEntity(packet->entityId); - if (entity && entity->isPlayer()) { - Player* player = (Player*) entity; - - switch (packet->action) { - case AnimatePacket::Swing: - player->swing(); - break; - default: - LOGW("Unknown Animate action: %d\n", packet->action); - break; - } - } -} -*/ - - -Player* NetEventCallback::findPlayer(Level* level, int entityId) { - Entity* e = level->getEntity(entityId); - if (e) { - if (e->isPlayer()) return (Player*) e; - LOGE("Entity: %p is supposed to be a player but is not (type %d)!\n", e, e->getEntityTypeId()); - } - return NULL; -} - -Player* NetEventCallback::findPlayer(Level* level, const RakNet::RakNetGUID* source) { - for (unsigned int i = 0; i < level->players.size(); ++i) - if (level->players[i]->owner == *source) return level->players[i]; - return NULL; -} - -Player* NetEventCallback::findPlayer( Level* level, int entityId, const RakNet::RakNetGUID* source ) -{ - if (entityId != -1) - if (Player* p = findPlayer(level, entityId)) return p; - if (source != NULL) - if (Player* p = findPlayer(level, source)) return p; - return NULL; -} - -void NetEventCallback::handle( Level* level, const RakNet::RakNetGUID& source, RespawnPacket* packet ) -{ - if (Player* p = findPlayer(level, packet->entityId, NULL)) { - p->moveTo(packet->x, packet->y, packet->z, p->yRot, p->xRot); - p->reset(); - p->resetPos(true); - } -} +#include "NetEventCallback.hpp" +#include "world/level/Level.hpp" +#include "packet/RespawnPacket.hpp" + +// +// Common packet handling implementation for Client and Server +// +/* +void NetEventCallback::handle( const RakNet::RakNetGUID& source, AnimatePacket* packet ) +{ + Entity* entity = level->getEntity(packet->entityId); + if (entity && entity->isPlayer()) { + Player* player = (Player*) entity; + + switch (packet->action) { + case AnimatePacket::Swing: + player->swing(); + break; + default: + LOGW("Unknown Animate action: %d\n", packet->action); + break; + } + } +} +*/ + + +Player* NetEventCallback::findPlayer(Level* level, int entityId) { + Entity* e = level->getEntity(entityId); + if (e) { + if (e->isPlayer()) return (Player*) e; + LOGE("Entity: %p is supposed to be a player but is not (type %d)!\n", e, e->getEntityTypeId()); + } + return NULL; +} + +Player* NetEventCallback::findPlayer(Level* level, const RakNet::RakNetGUID* source) { + for (unsigned int i = 0; i < level->players.size(); ++i) + if (level->players[i]->owner == *source) return level->players[i]; + return NULL; +} + +Player* NetEventCallback::findPlayer( Level* level, int entityId, const RakNet::RakNetGUID* source ) +{ + if (entityId != -1) + if (Player* p = findPlayer(level, entityId)) return p; + if (source != NULL) + if (Player* p = findPlayer(level, source)) return p; + return NULL; +} + +void NetEventCallback::handle( Level* level, const RakNet::RakNetGUID& source, RespawnPacket* packet ) +{ + if (Player* p = findPlayer(level, packet->entityId, NULL)) { + p->moveTo(packet->x, packet->y, packet->z, p->yRot, p->xRot); + p->reset(); + p->resetPos(true); + } +} diff --git a/src/network/NetEventCallback.h b/src/network/NetEventCallback.hpp similarity index 99% rename from src/network/NetEventCallback.h rename to src/network/NetEventCallback.hpp index da9c5a5..3b9cffc 100755 --- a/src/network/NetEventCallback.h +++ b/src/network/NetEventCallback.hpp @@ -52,7 +52,7 @@ class SignUpdatePacket; class Minecraft; class Level; -#include "../world/level/tile/Tile.h" +#include "world/level/tile/Tile.hpp" namespace RakNet { diff --git a/src/network/PHPDirectoryServer2.cpp b/src/network/PHPDirectoryServer2.cpp index 7d26e1f..f10bef4 100755 --- a/src/network/PHPDirectoryServer2.cpp +++ b/src/network/PHPDirectoryServer2.cpp @@ -14,17 +14,17 @@ /// License as published by the Free /// Software Foundation -#include "PHPDirectoryServer2.h" -#include "../raknet/HTTPConnection.h" -#include "../raknet/RakSleep.h" -#include "../raknet/RakString.h" -#include "../raknet/RakNetTypes.h" -#include "../raknet/GetTime.h" -#include "../raknet/RakAssert.h" +#include "PHPDirectoryServer2.hpp" +#include "raknet/HTTPConnection.h" +#include "raknet/RakSleep.h" +#include "raknet/RakString.h" +#include "raknet/RakNetTypes.h" +#include "raknet/GetTime.h" +#include "raknet/RakAssert.h" #include #include #include -#include "../raknet/Itoa.h" +#include "raknet/Itoa.h" // Column with this header contains the name of the game, passed to UploadTable() static const char *GAME_NAME_COMMAND="__GAME_NAME"; diff --git a/src/network/PHPDirectoryServer2.h b/src/network/PHPDirectoryServer2.hpp similarity index 95% rename from src/network/PHPDirectoryServer2.h rename to src/network/PHPDirectoryServer2.hpp index 40bc73c..c89858f 100755 --- a/src/network/PHPDirectoryServer2.h +++ b/src/network/PHPDirectoryServer2.hpp @@ -1,137 +1,137 @@ -/// \file -/// \brief Contains PHPDirectoryServer2, a client for communicating with a HTTP list of game servers -/// -/// This file is part of RakNet Copyright 2008 Kevin Jenkins. -/// -/// Usage of RakNet is subject to the appropriate license agreement. -/// Creative Commons Licensees are subject to the -/// license found at -/// http://creativecommons.org/licenses/by-nc/2.5/ -/// Single application licensees are subject to the license found at -/// http://www.jenkinssoftware.com/SingleApplicationLicense.html -/// Custom license users are subject to the terms therein. -/// GPL license users are subject to the GNU General Public -/// License as published by the Free -/// Software Foundation; either version 2 of the License, or (at your -/// option) any later version. - -#ifndef __PHP_DIRECTORY_SERVER_2 -#define __PHP_DIRECTORY_SERVER_2 - -#include "../raknet/RakString.h" -#include "../raknet/HTTPConnection.h" -#include "../raknet/RakNetTypes.h" -#include "../raknet/DS_Queue.h" -#include "../raknet/DS_Table.h" -#include "../raknet/DS_Map.h" - -namespace RakNet { - -struct SystemAddress; - -enum HTTPReadResult -{ - HTTP_RESULT_GOT_TABLE, - HTTP_RESULT_EMPTY -}; - -/// \brief Use PHPDirectoryServer2 as a C++ client to DirectoryServer.php -/// -/// PHPDirectoryServer2 works with the HTTPConnection class (which works with the TCPInterface class) in order to communiate with DirectoryServer.php found under Samples/PHPDirectoryServer2 -class PHPDirectoryServer2 -{ -public: - PHPDirectoryServer2(); - virtual ~PHPDirectoryServer2(); - - /// Associate PHPDirectoryServer2 with the HTTPConnection class it will communicate through - /// \param[in] _http The instance of HTTP connection we will communicate through - /// \param[in] _path The path to the PHP file on the remote server. For example, if the path is mysite.com/raknet/DirectoryServer.php then you would enter raknet/DirectoryServer.php - void Init(HTTPConnection *_http, const char *_path); - - /// Set a parameter (these are passed to the server) - /// To delete a column, just pass an empty string for value - /// Store the game name and port with UploadTable, rather than SetField, as these columns are required and use reserved column names - /// \param[in] columnName The name of the column to store - /// \param[in] value What value to hold for the uploaded row (only one row can be uploaded at a time) - void SetField(RakNet::RakString columnName, RakNet::RakString value); - - /// Returns the number of fields set with SetField() - unsigned int GetFieldCount(void) const; - - /// Returns a field set with SetField() - /// \param[in] index The 0 based index into the field list - /// \param[out] columnName The \a columnName parameter passed to SetField() - /// \param[out] value The \a value parameter passed to SetField() - void GetField(unsigned int index, RakNet::RakString &columnName, RakNet::RakString &value); - - /// Set all parameters at once from a table - /// \param[in] table A table containing the values you want to send. Note that all values are stored as strings in PHP - void SetFields(DataStructures::Table *table); - - /// Clear all fields - void ClearFields(void); - - /// Upload the values set with SetFields() or SetField() - /// On success: - /// 1. HTTPConnection::HasRead() will return true. - /// 2. Pass the value returned by HTTPConnection::Read() to PHPDirectoryServer2::ProcessHTTPRead(). - /// 3. The return value of PHPDirectoryServer2::ProcessHTTPRead() will be HTTP_RESULT_EMPTY - /// \param[in] uploadPassword The upload password set in the PHP page itself when you first uploaded and viewed it in the webpage. - /// \param[in] gameName Every entry must have a game name. Pass it here. - /// \param[in] gamePort Every entry must have a game port. Pass it here. The IP address will be stored automatically, or you can manually set it by passing a field named _System_Address - /// \param[in] autoRepost Tables must be uploaded every 60 seconds or they get dropped. Set autoRepost to true to automatically reupload the most recent table. - void UploadTable(RakNet::RakString uploadPassword, RakNet::RakString gameName, unsigned short gamePort, bool autoRepost); - - /// Send a download request to the PHP server. - /// On success: - /// 1. HTTPConnection::HasRead() will return true. - /// 2. Pass the value returned by HTTPConnection::Read() to PHPDirectoryServer2::ProcessHTTPRead(). - /// 3. The return value of PHPDirectoryServer2::ProcessHTTPRead() will be HTTP_RESULT_GOT_TABLE or HTTP_RESULT_EMPTY - /// 4. On HTTP_RESULT_GOT_TABLE, use GetLastDownloadedTable() to read the results. - /// \param[in] downloadPassword The download password set in the PHP page itself when you first uploaded and viewed it in the webpage. - void DownloadTable(RakNet::RakString downloadPassword); - - /// Same as calling DownloadTable immediately followed by UploadTable, except only the download result is returned - /// \param[in] uploadPassword The upload password set in the PHP page itself when you first uploaded and viewed it in the webpage. - /// \param[in] downloadPassword The download password set in the PHP page itself when you first uploaded and viewed it in the webpage. - /// \param[in] gameName Every entry must have a game name. Pass it here. - /// \param[in] gamePort Every entry must have a game port. Pass it here. The IP address will be stored automatically, or you can manually set it by passing a field named _System_Address - /// \param[in] autoRepost Tables must be uploaded every 60 seconds or they get dropped. Set autoRepost to true to automatically reupload the most recent table. - void UploadAndDownloadTable(RakNet::RakString uploadPassword, RakNet::RakString downloadPassword, RakNet::RakString gameName, unsigned short gamePort, bool autoRepost); - - /// When HTTPConnection::ProcessDataPacket() returns true, and not an error, pass HTTPConnection::Read() to this function - /// The message will be parsed into DataStructures::Table, and a copy stored internally which can be retrieved by GetLastDownloadedTable(); - /// \param[in] packetData Returned from HTTPInterface::Read() - /// \return One of the values for HTTPReadResult - HTTPReadResult ProcessHTTPRead(RakNet::RakString httpRead); - - /// Returns the last value returned from ProcessHTTPString - /// Default columns are "__GAME_NAME", "__GAME_PORT", "_System_Address" - /// \return The table created by parsing httpString - const DataStructures::Table *GetLastDownloadedTable(void) const; - - /// Call this periodically - it will handle connection states and refreshing updates to the server - void Update(void); - -private: - HTTPConnection *http; - RakNet::RakString pathToPHP; - - RakNet::RakString gameNameParam; - unsigned short gamePortParam; - - void SendOperation(void); - void PushColumnsAndValues(DataStructures::List &columns, DataStructures::List &values); - - DataStructures::Table lastDownloadedTable; - DataStructures::Map fields; - RakNet::RakString currentOperation; - RakNet::TimeMS nextRepost; - -}; - -} // namespace RakNet - -#endif - +/// \file +/// \brief Contains PHPDirectoryServer2, a client for communicating with a HTTP list of game servers +/// +/// This file is part of RakNet Copyright 2008 Kevin Jenkins. +/// +/// Usage of RakNet is subject to the appropriate license agreement. +/// Creative Commons Licensees are subject to the +/// license found at +/// http://creativecommons.org/licenses/by-nc/2.5/ +/// Single application licensees are subject to the license found at +/// http://www.jenkinssoftware.com/SingleApplicationLicense.html +/// Custom license users are subject to the terms therein. +/// GPL license users are subject to the GNU General Public +/// License as published by the Free +/// Software Foundation; either version 2 of the License, or (at your +/// option) any later version. + +#ifndef __PHP_DIRECTORY_SERVER_2 +#define __PHP_DIRECTORY_SERVER_2 + +#include "raknet/RakString.h" +#include "raknet/HTTPConnection.h" +#include "raknet/RakNetTypes.h" +#include "raknet/DS_Queue.h" +#include "raknet/DS_Table.h" +#include "raknet/DS_Map.h" + +namespace RakNet { + +struct SystemAddress; + +enum HTTPReadResult +{ + HTTP_RESULT_GOT_TABLE, + HTTP_RESULT_EMPTY +}; + +/// \brief Use PHPDirectoryServer2 as a C++ client to DirectoryServer.php +/// +/// PHPDirectoryServer2 works with the HTTPConnection class (which works with the TCPInterface class) in order to communiate with DirectoryServer.php found under Samples/PHPDirectoryServer2 +class PHPDirectoryServer2 +{ +public: + PHPDirectoryServer2(); + virtual ~PHPDirectoryServer2(); + + /// Associate PHPDirectoryServer2 with the HTTPConnection class it will communicate through + /// \param[in] _http The instance of HTTP connection we will communicate through + /// \param[in] _path The path to the PHP file on the remote server. For example, if the path is mysite.com/raknet/DirectoryServer.php then you would enter raknet/DirectoryServer.php + void Init(HTTPConnection *_http, const char *_path); + + /// Set a parameter (these are passed to the server) + /// To delete a column, just pass an empty string for value + /// Store the game name and port with UploadTable, rather than SetField, as these columns are required and use reserved column names + /// \param[in] columnName The name of the column to store + /// \param[in] value What value to hold for the uploaded row (only one row can be uploaded at a time) + void SetField(RakNet::RakString columnName, RakNet::RakString value); + + /// Returns the number of fields set with SetField() + unsigned int GetFieldCount(void) const; + + /// Returns a field set with SetField() + /// \param[in] index The 0 based index into the field list + /// \param[out] columnName The \a columnName parameter passed to SetField() + /// \param[out] value The \a value parameter passed to SetField() + void GetField(unsigned int index, RakNet::RakString &columnName, RakNet::RakString &value); + + /// Set all parameters at once from a table + /// \param[in] table A table containing the values you want to send. Note that all values are stored as strings in PHP + void SetFields(DataStructures::Table *table); + + /// Clear all fields + void ClearFields(void); + + /// Upload the values set with SetFields() or SetField() + /// On success: + /// 1. HTTPConnection::HasRead() will return true. + /// 2. Pass the value returned by HTTPConnection::Read() to PHPDirectoryServer2::ProcessHTTPRead(). + /// 3. The return value of PHPDirectoryServer2::ProcessHTTPRead() will be HTTP_RESULT_EMPTY + /// \param[in] uploadPassword The upload password set in the PHP page itself when you first uploaded and viewed it in the webpage. + /// \param[in] gameName Every entry must have a game name. Pass it here. + /// \param[in] gamePort Every entry must have a game port. Pass it here. The IP address will be stored automatically, or you can manually set it by passing a field named _System_Address + /// \param[in] autoRepost Tables must be uploaded every 60 seconds or they get dropped. Set autoRepost to true to automatically reupload the most recent table. + void UploadTable(RakNet::RakString uploadPassword, RakNet::RakString gameName, unsigned short gamePort, bool autoRepost); + + /// Send a download request to the PHP server. + /// On success: + /// 1. HTTPConnection::HasRead() will return true. + /// 2. Pass the value returned by HTTPConnection::Read() to PHPDirectoryServer2::ProcessHTTPRead(). + /// 3. The return value of PHPDirectoryServer2::ProcessHTTPRead() will be HTTP_RESULT_GOT_TABLE or HTTP_RESULT_EMPTY + /// 4. On HTTP_RESULT_GOT_TABLE, use GetLastDownloadedTable() to read the results. + /// \param[in] downloadPassword The download password set in the PHP page itself when you first uploaded and viewed it in the webpage. + void DownloadTable(RakNet::RakString downloadPassword); + + /// Same as calling DownloadTable immediately followed by UploadTable, except only the download result is returned + /// \param[in] uploadPassword The upload password set in the PHP page itself when you first uploaded and viewed it in the webpage. + /// \param[in] downloadPassword The download password set in the PHP page itself when you first uploaded and viewed it in the webpage. + /// \param[in] gameName Every entry must have a game name. Pass it here. + /// \param[in] gamePort Every entry must have a game port. Pass it here. The IP address will be stored automatically, or you can manually set it by passing a field named _System_Address + /// \param[in] autoRepost Tables must be uploaded every 60 seconds or they get dropped. Set autoRepost to true to automatically reupload the most recent table. + void UploadAndDownloadTable(RakNet::RakString uploadPassword, RakNet::RakString downloadPassword, RakNet::RakString gameName, unsigned short gamePort, bool autoRepost); + + /// When HTTPConnection::ProcessDataPacket() returns true, and not an error, pass HTTPConnection::Read() to this function + /// The message will be parsed into DataStructures::Table, and a copy stored internally which can be retrieved by GetLastDownloadedTable(); + /// \param[in] packetData Returned from HTTPInterface::Read() + /// \return One of the values for HTTPReadResult + HTTPReadResult ProcessHTTPRead(RakNet::RakString httpRead); + + /// Returns the last value returned from ProcessHTTPString + /// Default columns are "__GAME_NAME", "__GAME_PORT", "_System_Address" + /// \return The table created by parsing httpString + const DataStructures::Table *GetLastDownloadedTable(void) const; + + /// Call this periodically - it will handle connection states and refreshing updates to the server + void Update(void); + +private: + HTTPConnection *http; + RakNet::RakString pathToPHP; + + RakNet::RakString gameNameParam; + unsigned short gamePortParam; + + void SendOperation(void); + void PushColumnsAndValues(DataStructures::List &columns, DataStructures::List &values); + + DataStructures::Table lastDownloadedTable; + DataStructures::Map fields; + RakNet::RakString currentOperation; + RakNet::TimeMS nextRepost; + +}; + +} // namespace RakNet + +#endif + diff --git a/src/network/Packet.cpp b/src/network/Packet.cpp index ca1b328..7f9c7fe 100755 --- a/src/network/Packet.cpp +++ b/src/network/Packet.cpp @@ -1,212 +1,212 @@ - -#include "Packet.h" -#include "../world/level/chunk/LevelChunk.h" - -#include "packet/PacketInclude.h" - -Packet::Packet() -: priority(HIGH_PRIORITY), - reliability(RELIABLE) -{} - -Packet* MinecraftPackets::createPacket(int id) -{ - Packet* packet = NULL; - - switch (id - ID_USER_PACKET_ENUM) { - default: - break; - - case PACKET_LOGIN: - packet = new LoginPacket(); - break; - case PACKET_LOGINSTATUS: - packet = new LoginStatusPacket(); - break; - case PACKET_READY: - packet = new ReadyPacket(); - break; - case PACKET_SETTIME: - packet = new SetTimePacket(); - break; - case PACKET_MESSAGE: - packet = new MessagePacket(); - break; - case PACKET_STARTGAME: - packet = new StartGamePacket(); - break; - case PACKET_ADDENTITY: - packet = new AddEntityPacket(); - break; - case PACKET_ADDITEMENTITY: - packet = new AddItemEntityPacket(); - break; - case PACKET_TAKEITEMENTITY: - packet = new TakeItemEntityPacket(); - break; - case PACKET_ADDMOB: - packet = new AddMobPacket(); - break; - case PACKET_ADDPLAYER: - packet = new AddPlayerPacket(); - break; - case PACKET_REMOVEPLAYER: - packet = new RemovePlayerPacket(); - break; - case PACKET_MOVEENTITY: - packet = new MoveEntityPacket(); - break; - case PACKET_MOVEENTITY_POSROT: - packet = new MoveEntityPacket_PosRot(); - break; - //case PACKET_TELEPORTENTITY: - // packet = new TeleportEntityPacket(); - // break; - case PACKET_MOVEPLAYER: - packet = new MovePlayerPacket(); - break; - case PACKET_RESPAWN: - packet = new RespawnPacket(); - break; - case PACKET_REMOVEENTITY: - packet = new RemoveEntityPacket(); - break; - case PACKET_PLACEBLOCK: - packet = new PlaceBlockPacket(); - break; - case PACKET_REMOVEBLOCK: - packet = new RemoveBlockPacket(); - break; - case PACKET_UPDATEBLOCK: - packet = new UpdateBlockPacket(); - break; - case PACKET_EXPLODE: - packet = new ExplodePacket(); - break; - case PACKET_LEVELEVENT: - packet = new LevelEventPacket(); - break; - case PACKET_TILEEVENT: - packet = new TileEventPacket(); - break; - case PACKET_ENTITYEVENT: - packet = new EntityEventPacket(); - break; - case PACKET_REQUESTCHUNK: - packet = new RequestChunkPacket(); - break; - case PACKET_CHUNKDATA: - packet = new ChunkDataPacket(); - break; - case PACKET_PLAYEREQUIPMENT: - packet = new PlayerEquipmentPacket(); - break; - case PACKET_PLAYERARMOREQUIPMENT: - packet = new PlayerArmorEquipmentPacket(); - break; - case PACKET_INTERACT: - packet = new InteractPacket(); - break; - case PACKET_USEITEM: - packet = new UseItemPacket(); - break; - case PACKET_PLAYERACTION: - packet = new PlayerActionPacket(); - break; - case PACKET_HURTARMOR: - packet = new HurtArmorPacket(); - break; - case PACKET_SETENTITYDATA: - packet = new SetEntityDataPacket(); - break; - case PACKET_SETENTITYMOTION: - packet = new SetEntityMotionPacket(); - break; - case PACKET_SETHEALTH: - packet = new SetHealthPacket(); - break; - case PACKET_SETSPAWNPOSITION: - packet = new SetSpawnPositionPacket(); - break; - case PACKET_ANIMATE: - packet = new AnimatePacket(); - break; - case PACKET_SENDINVENTORY: - packet = new SendInventoryPacket(); - break; - case PACKET_DROPITEM: - packet = new DropItemPacket(); - break; - case PACKET_CONTAINERACK: - packet = new ContainerAckPacket(); - break; - case PACKET_CONTAINEROPEN: - packet = new ContainerOpenPacket(); - break; - case PACKET_CONTAINERCLOSE: - packet = new ContainerClosePacket(); - break; - case PACKET_CONTAINERSETDATA: - packet = new ContainerSetDataPacket(); - break; - case PACKET_CONTAINERSETSLOT: - packet = new ContainerSetSlotPacket(); - break; - case PACKET_CONTAINERSETCONTENT: - packet = new ContainerSetContentPacket(); - break; - case PACKET_CHAT: - packet = new ChatPacket(); - break; - case PACKET_SIGNUPDATE: - packet = new SignUpdatePacket(); - break; - case PACKET_ADDPAINTING: - packet = new AddPaintingPacket(); - break; - case PACKET_ADVENTURESETTINGS: - packet = new AdventureSettingsPacket(); - break; - } - - return packet; -} - - -namespace PacketUtil -{ - signed char Rot_degreesToChar(float rot) { - return (signed char)(rot / 360.0f * 256.0f); - } - float Rot_charToDegrees(signed char rot) { - return ((float)rot) / 256.0f * 360.0f; - } - - void Rot_entityToChar(const Entity* e, signed char& yRot, signed char& xRot) { - xRot = Rot_degreesToChar(e->xRot); - yRot = Rot_degreesToChar(e->yRot); - } - - void Rot_charToEntity(Entity* e, signed char yRot, signed char xRot) { - e->xRot = e->xRotO = Rot_charToDegrees(xRot); - e->yRot = e->yRotO = Rot_charToDegrees(yRot); - } - - void writeItemInstance(const ItemInstance& item, RakNet::BitStream* stream) { - short id = item.id; - unsigned char count = item.count; - short aux = item.getAuxValue(); - stream->Write(id); - stream->Write(count); - stream->Write(aux); - } - - ItemInstance readItemInstance(RakNet::BitStream* stream) { - short id, aux; - unsigned char count; - stream->Read(id); - stream->Read(count); - stream->Read(aux); - return ItemInstance(id, count, aux); - } -} + +#include "Packet.hpp" +#include "world/level/chunk/LevelChunk.hpp" + +#include "packet/PacketInclude.hpp" + +Packet::Packet() +: priority(HIGH_PRIORITY), + reliability(RELIABLE) +{} + +Packet* MinecraftPackets::createPacket(int id) +{ + Packet* packet = NULL; + + switch (id - ID_USER_PACKET_ENUM) { + default: + break; + + case PACKET_LOGIN: + packet = new LoginPacket(); + break; + case PACKET_LOGINSTATUS: + packet = new LoginStatusPacket(); + break; + case PACKET_READY: + packet = new ReadyPacket(); + break; + case PACKET_SETTIME: + packet = new SetTimePacket(); + break; + case PACKET_MESSAGE: + packet = new MessagePacket(); + break; + case PACKET_STARTGAME: + packet = new StartGamePacket(); + break; + case PACKET_ADDENTITY: + packet = new AddEntityPacket(); + break; + case PACKET_ADDITEMENTITY: + packet = new AddItemEntityPacket(); + break; + case PACKET_TAKEITEMENTITY: + packet = new TakeItemEntityPacket(); + break; + case PACKET_ADDMOB: + packet = new AddMobPacket(); + break; + case PACKET_ADDPLAYER: + packet = new AddPlayerPacket(); + break; + case PACKET_REMOVEPLAYER: + packet = new RemovePlayerPacket(); + break; + case PACKET_MOVEENTITY: + packet = new MoveEntityPacket(); + break; + case PACKET_MOVEENTITY_POSROT: + packet = new MoveEntityPacket_PosRot(); + break; + //case PACKET_TELEPORTENTITY: + // packet = new TeleportEntityPacket(); + // break; + case PACKET_MOVEPLAYER: + packet = new MovePlayerPacket(); + break; + case PACKET_RESPAWN: + packet = new RespawnPacket(); + break; + case PACKET_REMOVEENTITY: + packet = new RemoveEntityPacket(); + break; + case PACKET_PLACEBLOCK: + packet = new PlaceBlockPacket(); + break; + case PACKET_REMOVEBLOCK: + packet = new RemoveBlockPacket(); + break; + case PACKET_UPDATEBLOCK: + packet = new UpdateBlockPacket(); + break; + case PACKET_EXPLODE: + packet = new ExplodePacket(); + break; + case PACKET_LEVELEVENT: + packet = new LevelEventPacket(); + break; + case PACKET_TILEEVENT: + packet = new TileEventPacket(); + break; + case PACKET_ENTITYEVENT: + packet = new EntityEventPacket(); + break; + case PACKET_REQUESTCHUNK: + packet = new RequestChunkPacket(); + break; + case PACKET_CHUNKDATA: + packet = new ChunkDataPacket(); + break; + case PACKET_PLAYEREQUIPMENT: + packet = new PlayerEquipmentPacket(); + break; + case PACKET_PLAYERARMOREQUIPMENT: + packet = new PlayerArmorEquipmentPacket(); + break; + case PACKET_INTERACT: + packet = new InteractPacket(); + break; + case PACKET_USEITEM: + packet = new UseItemPacket(); + break; + case PACKET_PLAYERACTION: + packet = new PlayerActionPacket(); + break; + case PACKET_HURTARMOR: + packet = new HurtArmorPacket(); + break; + case PACKET_SETENTITYDATA: + packet = new SetEntityDataPacket(); + break; + case PACKET_SETENTITYMOTION: + packet = new SetEntityMotionPacket(); + break; + case PACKET_SETHEALTH: + packet = new SetHealthPacket(); + break; + case PACKET_SETSPAWNPOSITION: + packet = new SetSpawnPositionPacket(); + break; + case PACKET_ANIMATE: + packet = new AnimatePacket(); + break; + case PACKET_SENDINVENTORY: + packet = new SendInventoryPacket(); + break; + case PACKET_DROPITEM: + packet = new DropItemPacket(); + break; + case PACKET_CONTAINERACK: + packet = new ContainerAckPacket(); + break; + case PACKET_CONTAINEROPEN: + packet = new ContainerOpenPacket(); + break; + case PACKET_CONTAINERCLOSE: + packet = new ContainerClosePacket(); + break; + case PACKET_CONTAINERSETDATA: + packet = new ContainerSetDataPacket(); + break; + case PACKET_CONTAINERSETSLOT: + packet = new ContainerSetSlotPacket(); + break; + case PACKET_CONTAINERSETCONTENT: + packet = new ContainerSetContentPacket(); + break; + case PACKET_CHAT: + packet = new ChatPacket(); + break; + case PACKET_SIGNUPDATE: + packet = new SignUpdatePacket(); + break; + case PACKET_ADDPAINTING: + packet = new AddPaintingPacket(); + break; + case PACKET_ADVENTURESETTINGS: + packet = new AdventureSettingsPacket(); + break; + } + + return packet; +} + + +namespace PacketUtil +{ + signed char Rot_degreesToChar(float rot) { + return (signed char)(rot / 360.0f * 256.0f); + } + float Rot_charToDegrees(signed char rot) { + return ((float)rot) / 256.0f * 360.0f; + } + + void Rot_entityToChar(const Entity* e, signed char& yRot, signed char& xRot) { + xRot = Rot_degreesToChar(e->xRot); + yRot = Rot_degreesToChar(e->yRot); + } + + void Rot_charToEntity(Entity* e, signed char yRot, signed char xRot) { + e->xRot = e->xRotO = Rot_charToDegrees(xRot); + e->yRot = e->yRotO = Rot_charToDegrees(yRot); + } + + void writeItemInstance(const ItemInstance& item, RakNet::BitStream* stream) { + short id = item.id; + unsigned char count = item.count; + short aux = item.getAuxValue(); + stream->Write(id); + stream->Write(count); + stream->Write(aux); + } + + ItemInstance readItemInstance(RakNet::BitStream* stream) { + short id, aux; + unsigned char count; + stream->Read(id); + stream->Read(count); + stream->Read(aux); + return ItemInstance(id, count, aux); + } +} diff --git a/src/network/Packet.h b/src/network/Packet.hpp similarity index 94% rename from src/network/Packet.h rename to src/network/Packet.hpp index 5d417e2..95f357d 100755 --- a/src/network/Packet.h +++ b/src/network/Packet.hpp @@ -1,11 +1,11 @@ #pragma once -#include "NetEventCallback.h" +#include "NetEventCallback.hpp" -#include "../raknet/MessageIdentifiers.h" -#include "../raknet/RakNetTypes.h" -#include "../raknet/BitStream.h" -#include "../raknet/PacketPriority.h" +#include "raknet/MessageIdentifiers.h" +#include "raknet/RakNetTypes.h" +#include "raknet/BitStream.h" +#include "raknet/PacketPriority.h" class LevelChunk; diff --git a/src/network/RakNetInstance.cpp b/src/network/RakNetInstance.cpp index 3fae0b2..c107b83 100755 --- a/src/network/RakNetInstance.cpp +++ b/src/network/RakNetInstance.cpp @@ -1,739 +1,739 @@ -#include "RakNetInstance.h" -#include "Packet.h" -#include "NetEventCallback.h" -#include "../raknet/RakPeerInterface.h" -#include "../raknet/BitStream.h" -#include "../raknet/MessageIdentifiers.h" -#include "../raknet/GetTime.h" - -#include "../platform/log.h" - -#define APP_IDENTIFIER "MCCPP;Demo;" -#define APP_IDENTIFIER_MINECON "MCCPP;MINECON;" - -RakNetInstance::RakNetInstance() -: rakPeer(NULL), - _isServer(false), - _isLoggedIn(false) -{ - rakPeer = RakNet::RakPeerInterface::GetInstance(); - rakPeer->SetTimeoutTime(20000, RakNet::UNASSIGNED_SYSTEM_ADDRESS); - rakPeer->SetOccasionalPing(true); -} - -RakNetInstance::~RakNetInstance() -{ - if (rakPeer) - { - rakPeer->Shutdown(100, 0); - RakNet::RakPeerInterface::DestroyInstance(rakPeer); - rakPeer = NULL; - } -} - -bool RakNetInstance::host(const std::string& localName, int port, int maxConnections /* = 4 */) -{ - if (rakPeer->IsActive()) - { - rakPeer->Shutdown(500); - } - - RakNet::SocketDescriptor socket(port, 0); - socket.socketFamily = AF_INET; - - rakPeer->SetMaximumIncomingConnections(maxConnections); - RakNet::StartupResult result = rakPeer->Startup(maxConnections, &socket, 1); - - _isServer = true; - isPingingForServers = false; - - return (result == RakNet::RAKNET_STARTED); -} - -void RakNetInstance::announceServer(const std::string& localName) -{ - if (_isServer && rakPeer->IsActive()) - { - RakNet::RakString connectionData; - -#if defined(MINECON) - connectionData += APP_IDENTIFIER_MINECON; -#else - connectionData += APP_IDENTIFIER; -#endif - connectionData += localName.c_str(); - - RakNet::BitStream bitStream; - bitStream.Write(connectionData); - rakPeer->SetOfflinePingResponse((const char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); - } -} - -bool RakNetInstance::connect(const char* host, int port) -{ - _isLoggedIn = false; - RakNet::StartupResult result; - - RakNet::SocketDescriptor socket(0, 0); - socket.socketFamily = AF_INET; - - if (rakPeer->IsActive()) - { - rakPeer->Shutdown(500); - } - - result = rakPeer->Startup(4, &socket, 1); - - _isServer = false; - isPingingForServers = false; - - if (result == RakNet::RAKNET_STARTED) - { - RakNet::ConnectionAttemptResult connectResult = rakPeer->Connect(host, port, NULL, 0, NULL, 0, 12, 500, 0); - - return (connectResult == RakNet::CONNECTION_ATTEMPT_STARTED); - } - - return false; -} - -void RakNetInstance::disconnect() -{ - if (rakPeer->IsActive()) - { - rakPeer->Shutdown(500); - } - _isLoggedIn = false; - _isServer = false; - isPingingForServers = false; -} - -void RakNetInstance::pingForHosts(int basePort) -{ - if (!rakPeer->IsActive()) - { - RakNet::SocketDescriptor socket(0, 0); - rakPeer->Startup(4, &socket, 1); - } - - isPingingForServers = true; - pingPort = basePort; - lastPingTime = RakNet::GetTimeMS(); - - for (int i = 0; i < 4; ++i) - rakPeer->Ping("255.255.255.255", basePort + i, true); -} - -void RakNetInstance::stopPingForHosts() -{ - if (isPingingForServers) - { - rakPeer->Shutdown(0); - isPingingForServers = false; - } -} - -const ServerList& RakNetInstance::getServerList() -{ - return availableServers; -} - -void RakNetInstance::clearServerList() -{ - availableServers.clear(); - /* - for (int i = 0; i < 20; ++i) { - PingedCompatibleServer ps; - ps.isSpecial = false; - ps.name = "Fake-Real"; - ps.address.FromString("192.168.1.236|19132"); - availableServers.push_back(ps); - } - */ -} - -RakNet::RakPeerInterface* RakNetInstance::getPeer() -{ - return rakPeer; -} - -bool RakNetInstance::isProbablyBroken() { - return rakPeer->errorState < -100; -} -void RakNetInstance::resetIsBroken() { - rakPeer->errorState = 0; -} - -bool RakNetInstance::isMyLocalGuid(const RakNet::RakNetGUID& guid) -{ - return rakPeer->IsActive() && rakPeer->GetMyGUID() == guid; -} - -void RakNetInstance::runEvents(NetEventCallback* callback) -{ - RakNet::Packet* currentEvent; - - while ((currentEvent = rakPeer->Receive()) != NULL) - { - int packetId = currentEvent->data[0]; - int length = currentEvent->length; - - RakNet::BitStream activeBitStream(currentEvent->data + 1, length - 1, false); - - if (callback) { - if (packetId < ID_USER_PACKET_ENUM) - { - //LOGI("Received event: %s\n", getPacketName(packetId)); - switch (packetId) - { - case ID_NEW_INCOMING_CONNECTION: - callback->onNewClient(currentEvent->guid); - break; - case ID_CONNECTION_REQUEST_ACCEPTED: - serverGuid = currentEvent->guid; - callback->onConnect(currentEvent->guid); - break; - case ID_CONNECTION_ATTEMPT_FAILED: - callback->onUnableToConnect(); - break; - case ID_DISCONNECTION_NOTIFICATION: - case ID_CONNECTION_LOST: - callback->onDisconnect(currentEvent->guid); - break; - case ID_UNCONNECTED_PONG: - { - RakNet::TimeMS time; - RakNet::RakString data; - activeBitStream.Read(time); - activeBitStream.Read(data); - - int index = handleUnconnectedPong(data, currentEvent, APP_IDENTIFIER, false); - if (index < 0) { - // Check if it's an official Mojang MineCon server - index = handleUnconnectedPong(data, currentEvent, APP_IDENTIFIER_MINECON, true); - if (index >= 0) availableServers[index].isSpecial = true; - } - } - break; - } - } - else - { - int userPacketId = packetId - ID_USER_PACKET_ENUM; - bool isStatusPacket = userPacketId <= PACKET_READY; - - if (isStatusPacket || _isServer || _isLoggedIn) { - - if (Packet* packet = MinecraftPackets::createPacket(packetId)) { - packet->read(&activeBitStream); - packet->handle(currentEvent->guid, callback); - delete packet; - } - } - } - } - - rakPeer->DeallocatePacket(currentEvent); - //delete activeBitStream; - } - - if (isPingingForServers) - { - if (RakNet::GetTimeMS() - lastPingTime > 1000) - { - // remove servers that hasn't responded for a while - ServerList::iterator it = availableServers.begin(); - for (; it != availableServers.end(); ) - { - if (RakNet::GetTimeMS() - it->pingTime > 3000) - { - it = availableServers.erase(it); - } - else - { - ++it; - } - } - - pingForHosts(pingPort); - } - } - -} - -void RakNetInstance::send(Packet& packet) { - RakNet::BitStream bitStream; - packet.write(&bitStream); - if (_isServer) - { - // broadcast to all connected clients - rakPeer->Send(&bitStream, packet.priority, packet.reliability, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true); - } - else - { - // send to server - rakPeer->Send(&bitStream, packet.priority, packet.reliability, 0, serverGuid, false); - } -} - -void RakNetInstance::send(const RakNet::RakNetGUID& guid, Packet& packet) { - RakNet::BitStream bitStream; - packet.write(&bitStream); - rakPeer->Send(&bitStream, packet.priority, packet.reliability, 0, guid, false); -} - - -void RakNetInstance::send(Packet* packet) -{ - send(*packet); - delete packet; -} - -void RakNetInstance::send(const RakNet::RakNetGUID& guid, Packet* packet) -{ - send(guid, *packet); - delete packet; -} - -#ifdef _DEBUG -const char* RakNetInstance::getPacketName(int packetId) -{ - - switch (packetId) - { - case ID_CONNECTED_PING: - return "ID_CONNECTED_PING"; - - case ID_UNCONNECTED_PING: - return "ID_UNCONNECTED_PING"; - - case ID_UNCONNECTED_PING_OPEN_CONNECTIONS: - return "ID_UNCONNECTED_PING_OPEN_CONNECTIONS"; - - case ID_CONNECTED_PONG: - return "ID_CONNECTED_PONG"; - - case ID_DETECT_LOST_CONNECTIONS: - return "ID_DETECT_LOST_CONNECTIONS"; - - case ID_OPEN_CONNECTION_REQUEST_1: - return "ID_OPEN_CONNECTION_REQUEST_1"; - - case ID_OPEN_CONNECTION_REPLY_1: - return "ID_OPEN_CONNECTION_REPLY_1"; - - case ID_OPEN_CONNECTION_REQUEST_2: - return "ID_OPEN_CONNECTION_REQUEST_2"; - - case ID_OPEN_CONNECTION_REPLY_2: - return "ID_OPEN_CONNECTION_REPLY_2"; - - case ID_CONNECTION_REQUEST: - return "ID_CONNECTION_REQUEST"; - - case ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY: - return "ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY"; - - case ID_OUR_SYSTEM_REQUIRES_SECURITY: - return "ID_OUR_SYSTEM_REQUIRES_SECURITY"; - - case ID_PUBLIC_KEY_MISMATCH: - return "ID_PUBLIC_KEY_MISMATCH"; - - case ID_OUT_OF_BAND_INTERNAL: - return "ID_OUT_OF_BAND_INTERNAL"; - - case ID_SND_RECEIPT_ACKED: - return "ID_SND_RECEIPT_ACKED"; - - case ID_SND_RECEIPT_LOSS: - return "ID_SND_RECEIPT_LOSS"; - - case ID_CONNECTION_REQUEST_ACCEPTED: - return "ID_CONNECTION_REQUEST_ACCEPTED"; - - case ID_CONNECTION_ATTEMPT_FAILED: - return "ID_CONNECTION_ATTEMPT_FAILED"; - - case ID_ALREADY_CONNECTED: - return "ID_ALREADY_CONNECTED"; - - case ID_NEW_INCOMING_CONNECTION: - return "ID_NEW_INCOMING_CONNECTION"; - - case ID_NO_FREE_INCOMING_CONNECTIONS: - return "ID_NO_FREE_INCOMING_CONNECTIONS"; - - case ID_DISCONNECTION_NOTIFICATION: - return "ID_DISCONNECTION_NOTIFICATION"; - - case ID_CONNECTION_LOST: - return "ID_CONNECTION_LOST"; - - case ID_CONNECTION_BANNED: - return "ID_CONNECTION_BANNED"; - - case ID_INVALID_PASSWORD: - return "ID_INVALID_PASSWORD"; - - case ID_INCOMPATIBLE_PROTOCOL_VERSION: - return "ID_INCOMPATIBLE_PROTOCOL_VERSION"; - - case ID_IP_RECENTLY_CONNECTED: - return "ID_IP_RECENTLY_CONNECTED"; - - case ID_TIMESTAMP: - return "ID_TIMESTAMP"; - - case ID_UNCONNECTED_PONG: - return "ID_UNCONNECTED_PONG"; - - case ID_ADVERTISE_SYSTEM: - return "ID_ADVERTISE_SYSTEM"; - - case ID_DOWNLOAD_PROGRESS: - return "ID_DOWNLOAD_PROGRESS"; - - case ID_REMOTE_DISCONNECTION_NOTIFICATION: - return "ID_REMOTE_DISCONNECTION_NOTIFICATION"; - - case ID_REMOTE_CONNECTION_LOST: - return "ID_REMOTE_CONNECTION_LOST"; - - case ID_REMOTE_NEW_INCOMING_CONNECTION: - return "ID_REMOTE_NEW_INCOMING_CONNECTION"; - - case ID_FILE_LIST_TRANSFER_HEADER: - return "ID_FILE_LIST_TRANSFER_HEADER"; - - case ID_FILE_LIST_TRANSFER_FILE: - return "ID_FILE_LIST_TRANSFER_FILE"; - - case ID_FILE_LIST_REFERENCE_PUSH_ACK: - return "ID_FILE_LIST_REFERENCE_PUSH_ACK"; - - case ID_DDT_DOWNLOAD_REQUEST: - return "ID_DDT_DOWNLOAD_REQUEST"; - - case ID_TRANSPORT_STRING: - return "ID_TRANSPORT_STRING"; - - case ID_REPLICA_MANAGER_CONSTRUCTION: - return "ID_REPLICA_MANAGER_CONSTRUCTION"; - - case ID_REPLICA_MANAGER_SCOPE_CHANGE: - return "ID_REPLICA_MANAGER_SCOPE_CHANGE"; - - case ID_REPLICA_MANAGER_SERIALIZE: - return "ID_REPLICA_MANAGER_SERIALIZE"; - - case ID_REPLICA_MANAGER_DOWNLOAD_STARTED: - return "ID_REPLICA_MANAGER_DOWNLOAD_STARTED"; - - case ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE: - return "ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE"; - - case ID_RAKVOICE_OPEN_CHANNEL_REQUEST: - return "ID_RAKVOICE_OPEN_CHANNEL_REQUEST"; - - case ID_RAKVOICE_OPEN_CHANNEL_REPLY: - return "ID_RAKVOICE_OPEN_CHANNEL_REPLY"; - - case ID_RAKVOICE_CLOSE_CHANNEL: - return "ID_RAKVOICE_CLOSE_CHANNEL"; - - case ID_RAKVOICE_DATA: - return "ID_RAKVOICE_DATA"; - - case ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE: - return "ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE"; - - case ID_AUTOPATCHER_CREATION_LIST: - return "ID_AUTOPATCHER_CREATION_LIST"; - - case ID_AUTOPATCHER_DELETION_LIST: - return "ID_AUTOPATCHER_DELETION_LIST"; - - case ID_AUTOPATCHER_GET_PATCH: - return "ID_AUTOPATCHER_GET_PATCH"; - - case ID_AUTOPATCHER_PATCH_LIST: - return "ID_AUTOPATCHER_PATCH_LIST"; - - case ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR: - return "ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR"; - - case ID_AUTOPATCHER_FINISHED_INTERNAL: - return "ID_AUTOPATCHER_FINISHED_INTERNAL"; - - case ID_AUTOPATCHER_FINISHED: - return "ID_AUTOPATCHER_FINISHED"; - - case ID_AUTOPATCHER_RESTART_APPLICATION: - return "ID_AUTOPATCHER_RESTART_APPLICATION"; - - case ID_NAT_PUNCHTHROUGH_REQUEST: - return "ID_NAT_PUNCHTHROUGH_REQUEST"; - - case ID_NAT_GROUP_PUNCHTHROUGH_REQUEST: - return "ID_NAT_GROUP_PUNCHTHROUGH_REQUEST"; - - case ID_NAT_GROUP_PUNCHTHROUGH_REPLY: - return "ID_NAT_GROUP_PUNCHTHROUGH_REPLY"; - - case ID_NAT_CONNECT_AT_TIME: - return "ID_NAT_CONNECT_AT_TIME"; - - case ID_NAT_GET_MOST_RECENT_PORT: - return "ID_NAT_GET_MOST_RECENT_PORT"; - - case ID_NAT_CLIENT_READY: - return "ID_NAT_CLIENT_READY"; - - case ID_NAT_GROUP_PUNCHTHROUGH_FAILURE_NOTIFICATION: - return "ID_NAT_GROUP_PUNCHTHROUGH_FAILURE_NOTIFICATION"; - - case ID_NAT_TARGET_NOT_CONNECTED: - return "ID_NAT_TARGET_NOT_CONNECTED"; - - case ID_NAT_TARGET_UNRESPONSIVE: - return "ID_NAT_TARGET_UNRESPONSIVE"; - - case ID_NAT_CONNECTION_TO_TARGET_LOST: - return "ID_NAT_CONNECTION_TO_TARGET_LOST"; - - case ID_NAT_ALREADY_IN_PROGRESS: - return "ID_NAT_ALREADY_IN_PROGRESS"; - - case ID_NAT_PUNCHTHROUGH_FAILED: - return "ID_NAT_PUNCHTHROUGH_FAILED"; - - case ID_NAT_PUNCHTHROUGH_SUCCEEDED: - return "ID_NAT_PUNCHTHROUGH_SUCCEEDED"; - - case ID_NAT_GROUP_PUNCH_FAILED: - return "ID_NAT_GROUP_PUNCH_FAILED"; - - case ID_NAT_GROUP_PUNCH_SUCCEEDED: - return "ID_NAT_GROUP_PUNCH_SUCCEEDED"; - - case ID_READY_EVENT_SET: - return "ID_READY_EVENT_SET"; - - case ID_READY_EVENT_UNSET: - return "ID_READY_EVENT_UNSET"; - - case ID_READY_EVENT_ALL_SET: - return "ID_READY_EVENT_ALL_SET"; - - case ID_READY_EVENT_QUERY: - return "ID_READY_EVENT_QUERY"; - - case ID_LOBBY_GENERAL: - return "ID_LOBBY_GENERAL"; - - case ID_RPC_REMOTE_ERROR: - return "ID_RPC_REMOTE_ERROR"; - - case ID_RPC_PLUGIN: - return "ID_RPC_PLUGIN"; - - case ID_FILE_LIST_REFERENCE_PUSH: - return "ID_FILE_LIST_REFERENCE_PUSH"; - - case ID_READY_EVENT_FORCE_ALL_SET: - return "ID_READY_EVENT_FORCE_ALL_SET"; - - case ID_ROOMS_EXECUTE_FUNC: - return "ID_ROOMS_EXECUTE_FUNC"; - - case ID_ROOMS_LOGON_STATUS: - return "ID_ROOMS_LOGON_STATUS"; - - case ID_ROOMS_HANDLE_CHANGE: - return "ID_ROOMS_HANDLE_CHANGE"; - - case ID_LOBBY2_SEND_MESSAGE: - return "ID_LOBBY2_SEND_MESSAGE"; - - case ID_LOBBY2_SERVER_ERROR: - return "ID_LOBBY2_SERVER_ERROR"; - - case ID_FCM2_NEW_HOST: - return "ID_FCM2_NEW_HOST"; - - case ID_FCM2_REQUEST_FCMGUID: - return "ID_FCM2_REQUEST_FCMGUID"; - - case ID_FCM2_RESPOND_CONNECTION_COUNT: - return "ID_FCM2_RESPOND_CONNECTION_COUNT"; - - case ID_FCM2_INFORM_FCMGUID: - return "ID_FCM2_INFORM_FCMGUID"; - - case ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT: - return "ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT"; - - case ID_UDP_PROXY_GENERAL: - return "ID_UDP_PROXY_GENERAL"; - - case ID_SQLite3_EXEC: - return "ID_SQLite3_EXEC"; - - case ID_SQLite3_UNKNOWN_DB: - return "ID_SQLite3_UNKNOWN_DB"; - - case ID_SQLLITE_LOGGER: - return "ID_SQLLITE_LOGGER"; - - case ID_NAT_TYPE_DETECTION_REQUEST: - return "ID_NAT_TYPE_DETECTION_REQUEST"; - - case ID_NAT_TYPE_DETECTION_RESULT: - return "ID_NAT_TYPE_DETECTION_RESULT"; - - case ID_ROUTER_2_INTERNAL: - return "ID_ROUTER_2_INTERNAL"; - - case ID_ROUTER_2_FORWARDING_NO_PATH: - return "ID_ROUTER_2_FORWARDING_NO_PATH"; - - case ID_ROUTER_2_FORWARDING_ESTABLISHED: - return "ID_ROUTER_2_FORWARDING_ESTABLISHED"; - - case ID_ROUTER_2_REROUTED: - return "ID_ROUTER_2_REROUTED"; - - case ID_TEAM_BALANCER_INTERNAL: - return "ID_TEAM_BALANCER_INTERNAL"; - - case ID_TEAM_BALANCER_REQUESTED_TEAM_CHANGE_PENDING: - return "ID_TEAM_BALANCER_REQUESTED_TEAM_CHANGE_PENDING"; - - case ID_TEAM_BALANCER_TEAMS_LOCKED: - return "ID_TEAM_BALANCER_TEAMS_LOCKED"; - - case ID_TEAM_BALANCER_TEAM_ASSIGNED: - return "ID_TEAM_BALANCER_TEAM_ASSIGNED"; - - case ID_LIGHTSPEED_INTEGRATION: - return "ID_LIGHTSPEED_INTEGRATION"; - - case ID_XBOX_LOBBY: - return "ID_XBOX_LOBBY"; - - case ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS: - return "ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS"; - - case ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS: - return "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS"; - - case ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE: - return "ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE"; - - case ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE: - return "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE"; - - case ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT: - return "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT"; - - case ID_TWO_WAY_AUTHENTICATION_NEGOTIATION: - return "ID_TWO_WAY_AUTHENTICATION_NEGOTIATION"; - - case ID_CLOUD_POST_REQUEST: - return "ID_CLOUD_POST_REQUEST"; - - case ID_CLOUD_RELEASE_REQUEST: - return "ID_CLOUD_RELEASE_REQUEST"; - - case ID_CLOUD_GET_REQUEST: - return "ID_CLOUD_GET_REQUEST"; - - case ID_CLOUD_GET_RESPONSE: - return "ID_CLOUD_GET_RESPONSE"; - - case ID_CLOUD_UNSUBSCRIBE_REQUEST: - return "ID_CLOUD_UNSUBSCRIBE_REQUEST"; - - case ID_CLOUD_SERVER_TO_SERVER_COMMAND: - return "ID_CLOUD_SERVER_TO_SERVER_COMMAND"; - - case ID_CLOUD_SUBSCRIPTION_NOTIFICATION: - return "ID_CLOUD_SUBSCRIPTION_NOTIFICATION"; - - case ID_RESERVED_1: - return "ID_RESERVED_1"; - - case ID_RESERVED_2: - return "ID_RESERVED_2"; - - case ID_RESERVED_3: - return "ID_RESERVED_3"; - - case ID_RESERVED_4: - return "ID_RESERVED_4"; - - case ID_RESERVED_5: - return "ID_RESERVED_5"; - - case ID_RESERVED_6: - return "ID_RESERVED_6"; - - case ID_RESERVED_7: - return "ID_RESERVED_7"; - - case ID_RESERVED_8: - return "ID_RESERVED_8"; - - case ID_RESERVED_9: - return "ID_RESERVED_9"; - - default: - break; - } - return "Unknown or user-defined"; -} -#endif - -int RakNetInstance::handleUnconnectedPong(const RakNet::RakString& data, const RakNet::Packet* p, const char* appid, bool insertAtBeginning) -{ - RakNet::RakString appIdentifier(appid); - // This weird code is a result of RakString.Find being pretty useless - bool emptyNameOrLonger = data.GetLength() >= appIdentifier.GetLength(); - - if ( !emptyNameOrLonger || appIdentifier.StrCmp(data.SubStr(0, appIdentifier.GetLength())) != 0) - return -1; - - bool found = false; - for (unsigned int i = 0; i < availableServers.size(); i++) { - if (availableServers[i].address == p->systemAddress) { - availableServers[i].pingTime = RakNet::GetTimeMS(); - - bool emptyName = data.GetLength() == appIdentifier.GetLength(); - if (emptyName) - availableServers[i].name = ""; - else { - availableServers[i].name = data.SubStr(appIdentifier.GetLength(), data.GetLength() - appIdentifier.GetLength()); - } - //LOGI("Swapping name: %s\n", availableServers[i].name.C_String()); - return i; - } - } - PingedCompatibleServer server; - server.address = p->systemAddress; - server.pingTime = RakNet::GetTimeMS(); - server.isSpecial = false; - server.name = data.SubStr(appIdentifier.GetLength(), data.GetLength() - appIdentifier.GetLength()); - - if (insertAtBeginning) { - availableServers.insert(availableServers.begin(), server); - return 0; - } else { - availableServers.push_back(server); - return availableServers.size() - 1; - } -} - -void RakNetInstance::setIsLoggedIn( bool status ) { - _isLoggedIn = status; -} +#include "RakNetInstance.hpp" +#include "Packet.hpp" +#include "NetEventCallback.hpp" +#include "raknet/RakPeerInterface.h" +#include "raknet/BitStream.h" +#include "raknet/MessageIdentifiers.h" +#include "raknet/GetTime.h" + +#include "platform/log.hpp" + +#define APP_IDENTIFIER "MCCPP;Demo;" +#define APP_IDENTIFIER_MINECON "MCCPP;MINECON;" + +RakNetInstance::RakNetInstance() +: rakPeer(NULL), + _isServer(false), + _isLoggedIn(false) +{ + rakPeer = RakNet::RakPeerInterface::GetInstance(); + rakPeer->SetTimeoutTime(20000, RakNet::UNASSIGNED_SYSTEM_ADDRESS); + rakPeer->SetOccasionalPing(true); +} + +RakNetInstance::~RakNetInstance() +{ + if (rakPeer) + { + rakPeer->Shutdown(100, 0); + RakNet::RakPeerInterface::DestroyInstance(rakPeer); + rakPeer = NULL; + } +} + +bool RakNetInstance::host(const std::string& localName, int port, int maxConnections /* = 4 */) +{ + if (rakPeer->IsActive()) + { + rakPeer->Shutdown(500); + } + + RakNet::SocketDescriptor socket(port, 0); + socket.socketFamily = AF_INET; + + rakPeer->SetMaximumIncomingConnections(maxConnections); + RakNet::StartupResult result = rakPeer->Startup(maxConnections, &socket, 1); + + _isServer = true; + isPingingForServers = false; + + return (result == RakNet::RAKNET_STARTED); +} + +void RakNetInstance::announceServer(const std::string& localName) +{ + if (_isServer && rakPeer->IsActive()) + { + RakNet::RakString connectionData; + +#if defined(MINECON) + connectionData += APP_IDENTIFIER_MINECON; +#else + connectionData += APP_IDENTIFIER; +#endif + connectionData += localName.c_str(); + + RakNet::BitStream bitStream; + bitStream.Write(connectionData); + rakPeer->SetOfflinePingResponse((const char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed()); + } +} + +bool RakNetInstance::connect(const char* host, int port) +{ + _isLoggedIn = false; + RakNet::StartupResult result; + + RakNet::SocketDescriptor socket(0, 0); + socket.socketFamily = AF_INET; + + if (rakPeer->IsActive()) + { + rakPeer->Shutdown(500); + } + + result = rakPeer->Startup(4, &socket, 1); + + _isServer = false; + isPingingForServers = false; + + if (result == RakNet::RAKNET_STARTED) + { + RakNet::ConnectionAttemptResult connectResult = rakPeer->Connect(host, port, NULL, 0, NULL, 0, 12, 500, 0); + + return (connectResult == RakNet::CONNECTION_ATTEMPT_STARTED); + } + + return false; +} + +void RakNetInstance::disconnect() +{ + if (rakPeer->IsActive()) + { + rakPeer->Shutdown(500); + } + _isLoggedIn = false; + _isServer = false; + isPingingForServers = false; +} + +void RakNetInstance::pingForHosts(int basePort) +{ + if (!rakPeer->IsActive()) + { + RakNet::SocketDescriptor socket(0, 0); + rakPeer->Startup(4, &socket, 1); + } + + isPingingForServers = true; + pingPort = basePort; + lastPingTime = RakNet::GetTimeMS(); + + for (int i = 0; i < 4; ++i) + rakPeer->Ping("255.255.255.255", basePort + i, true); +} + +void RakNetInstance::stopPingForHosts() +{ + if (isPingingForServers) + { + rakPeer->Shutdown(0); + isPingingForServers = false; + } +} + +const ServerList& RakNetInstance::getServerList() +{ + return availableServers; +} + +void RakNetInstance::clearServerList() +{ + availableServers.clear(); + /* + for (int i = 0; i < 20; ++i) { + PingedCompatibleServer ps; + ps.isSpecial = false; + ps.name = "Fake-Real"; + ps.address.FromString("192.168.1.236|19132"); + availableServers.push_back(ps); + } + */ +} + +RakNet::RakPeerInterface* RakNetInstance::getPeer() +{ + return rakPeer; +} + +bool RakNetInstance::isProbablyBroken() { + return rakPeer->errorState < -100; +} +void RakNetInstance::resetIsBroken() { + rakPeer->errorState = 0; +} + +bool RakNetInstance::isMyLocalGuid(const RakNet::RakNetGUID& guid) +{ + return rakPeer->IsActive() && rakPeer->GetMyGUID() == guid; +} + +void RakNetInstance::runEvents(NetEventCallback* callback) +{ + RakNet::Packet* currentEvent; + + while ((currentEvent = rakPeer->Receive()) != NULL) + { + int packetId = currentEvent->data[0]; + int length = currentEvent->length; + + RakNet::BitStream activeBitStream(currentEvent->data + 1, length - 1, false); + + if (callback) { + if (packetId < ID_USER_PACKET_ENUM) + { + //LOGI("Received event: %s\n", getPacketName(packetId)); + switch (packetId) + { + case ID_NEW_INCOMING_CONNECTION: + callback->onNewClient(currentEvent->guid); + break; + case ID_CONNECTION_REQUEST_ACCEPTED: + serverGuid = currentEvent->guid; + callback->onConnect(currentEvent->guid); + break; + case ID_CONNECTION_ATTEMPT_FAILED: + callback->onUnableToConnect(); + break; + case ID_DISCONNECTION_NOTIFICATION: + case ID_CONNECTION_LOST: + callback->onDisconnect(currentEvent->guid); + break; + case ID_UNCONNECTED_PONG: + { + RakNet::TimeMS time; + RakNet::RakString data; + activeBitStream.Read(time); + activeBitStream.Read(data); + + int index = handleUnconnectedPong(data, currentEvent, APP_IDENTIFIER, false); + if (index < 0) { + // Check if it's an official Mojang MineCon server + index = handleUnconnectedPong(data, currentEvent, APP_IDENTIFIER_MINECON, true); + if (index >= 0) availableServers[index].isSpecial = true; + } + } + break; + } + } + else + { + int userPacketId = packetId - ID_USER_PACKET_ENUM; + bool isStatusPacket = userPacketId <= PACKET_READY; + + if (isStatusPacket || _isServer || _isLoggedIn) { + + if (Packet* packet = MinecraftPackets::createPacket(packetId)) { + packet->read(&activeBitStream); + packet->handle(currentEvent->guid, callback); + delete packet; + } + } + } + } + + rakPeer->DeallocatePacket(currentEvent); + //delete activeBitStream; + } + + if (isPingingForServers) + { + if (RakNet::GetTimeMS() - lastPingTime > 1000) + { + // remove servers that hasn't responded for a while + ServerList::iterator it = availableServers.begin(); + for (; it != availableServers.end(); ) + { + if (RakNet::GetTimeMS() - it->pingTime > 3000) + { + it = availableServers.erase(it); + } + else + { + ++it; + } + } + + pingForHosts(pingPort); + } + } + +} + +void RakNetInstance::send(Packet& packet) { + RakNet::BitStream bitStream; + packet.write(&bitStream); + if (_isServer) + { + // broadcast to all connected clients + rakPeer->Send(&bitStream, packet.priority, packet.reliability, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true); + } + else + { + // send to server + rakPeer->Send(&bitStream, packet.priority, packet.reliability, 0, serverGuid, false); + } +} + +void RakNetInstance::send(const RakNet::RakNetGUID& guid, Packet& packet) { + RakNet::BitStream bitStream; + packet.write(&bitStream); + rakPeer->Send(&bitStream, packet.priority, packet.reliability, 0, guid, false); +} + + +void RakNetInstance::send(Packet* packet) +{ + send(*packet); + delete packet; +} + +void RakNetInstance::send(const RakNet::RakNetGUID& guid, Packet* packet) +{ + send(guid, *packet); + delete packet; +} + +#ifdef _DEBUG +const char* RakNetInstance::getPacketName(int packetId) +{ + + switch (packetId) + { + case ID_CONNECTED_PING: + return "ID_CONNECTED_PING"; + + case ID_UNCONNECTED_PING: + return "ID_UNCONNECTED_PING"; + + case ID_UNCONNECTED_PING_OPEN_CONNECTIONS: + return "ID_UNCONNECTED_PING_OPEN_CONNECTIONS"; + + case ID_CONNECTED_PONG: + return "ID_CONNECTED_PONG"; + + case ID_DETECT_LOST_CONNECTIONS: + return "ID_DETECT_LOST_CONNECTIONS"; + + case ID_OPEN_CONNECTION_REQUEST_1: + return "ID_OPEN_CONNECTION_REQUEST_1"; + + case ID_OPEN_CONNECTION_REPLY_1: + return "ID_OPEN_CONNECTION_REPLY_1"; + + case ID_OPEN_CONNECTION_REQUEST_2: + return "ID_OPEN_CONNECTION_REQUEST_2"; + + case ID_OPEN_CONNECTION_REPLY_2: + return "ID_OPEN_CONNECTION_REPLY_2"; + + case ID_CONNECTION_REQUEST: + return "ID_CONNECTION_REQUEST"; + + case ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY: + return "ID_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY"; + + case ID_OUR_SYSTEM_REQUIRES_SECURITY: + return "ID_OUR_SYSTEM_REQUIRES_SECURITY"; + + case ID_PUBLIC_KEY_MISMATCH: + return "ID_PUBLIC_KEY_MISMATCH"; + + case ID_OUT_OF_BAND_INTERNAL: + return "ID_OUT_OF_BAND_INTERNAL"; + + case ID_SND_RECEIPT_ACKED: + return "ID_SND_RECEIPT_ACKED"; + + case ID_SND_RECEIPT_LOSS: + return "ID_SND_RECEIPT_LOSS"; + + case ID_CONNECTION_REQUEST_ACCEPTED: + return "ID_CONNECTION_REQUEST_ACCEPTED"; + + case ID_CONNECTION_ATTEMPT_FAILED: + return "ID_CONNECTION_ATTEMPT_FAILED"; + + case ID_ALREADY_CONNECTED: + return "ID_ALREADY_CONNECTED"; + + case ID_NEW_INCOMING_CONNECTION: + return "ID_NEW_INCOMING_CONNECTION"; + + case ID_NO_FREE_INCOMING_CONNECTIONS: + return "ID_NO_FREE_INCOMING_CONNECTIONS"; + + case ID_DISCONNECTION_NOTIFICATION: + return "ID_DISCONNECTION_NOTIFICATION"; + + case ID_CONNECTION_LOST: + return "ID_CONNECTION_LOST"; + + case ID_CONNECTION_BANNED: + return "ID_CONNECTION_BANNED"; + + case ID_INVALID_PASSWORD: + return "ID_INVALID_PASSWORD"; + + case ID_INCOMPATIBLE_PROTOCOL_VERSION: + return "ID_INCOMPATIBLE_PROTOCOL_VERSION"; + + case ID_IP_RECENTLY_CONNECTED: + return "ID_IP_RECENTLY_CONNECTED"; + + case ID_TIMESTAMP: + return "ID_TIMESTAMP"; + + case ID_UNCONNECTED_PONG: + return "ID_UNCONNECTED_PONG"; + + case ID_ADVERTISE_SYSTEM: + return "ID_ADVERTISE_SYSTEM"; + + case ID_DOWNLOAD_PROGRESS: + return "ID_DOWNLOAD_PROGRESS"; + + case ID_REMOTE_DISCONNECTION_NOTIFICATION: + return "ID_REMOTE_DISCONNECTION_NOTIFICATION"; + + case ID_REMOTE_CONNECTION_LOST: + return "ID_REMOTE_CONNECTION_LOST"; + + case ID_REMOTE_NEW_INCOMING_CONNECTION: + return "ID_REMOTE_NEW_INCOMING_CONNECTION"; + + case ID_FILE_LIST_TRANSFER_HEADER: + return "ID_FILE_LIST_TRANSFER_HEADER"; + + case ID_FILE_LIST_TRANSFER_FILE: + return "ID_FILE_LIST_TRANSFER_FILE"; + + case ID_FILE_LIST_REFERENCE_PUSH_ACK: + return "ID_FILE_LIST_REFERENCE_PUSH_ACK"; + + case ID_DDT_DOWNLOAD_REQUEST: + return "ID_DDT_DOWNLOAD_REQUEST"; + + case ID_TRANSPORT_STRING: + return "ID_TRANSPORT_STRING"; + + case ID_REPLICA_MANAGER_CONSTRUCTION: + return "ID_REPLICA_MANAGER_CONSTRUCTION"; + + case ID_REPLICA_MANAGER_SCOPE_CHANGE: + return "ID_REPLICA_MANAGER_SCOPE_CHANGE"; + + case ID_REPLICA_MANAGER_SERIALIZE: + return "ID_REPLICA_MANAGER_SERIALIZE"; + + case ID_REPLICA_MANAGER_DOWNLOAD_STARTED: + return "ID_REPLICA_MANAGER_DOWNLOAD_STARTED"; + + case ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE: + return "ID_REPLICA_MANAGER_DOWNLOAD_COMPLETE"; + + case ID_RAKVOICE_OPEN_CHANNEL_REQUEST: + return "ID_RAKVOICE_OPEN_CHANNEL_REQUEST"; + + case ID_RAKVOICE_OPEN_CHANNEL_REPLY: + return "ID_RAKVOICE_OPEN_CHANNEL_REPLY"; + + case ID_RAKVOICE_CLOSE_CHANNEL: + return "ID_RAKVOICE_CLOSE_CHANNEL"; + + case ID_RAKVOICE_DATA: + return "ID_RAKVOICE_DATA"; + + case ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE: + return "ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE"; + + case ID_AUTOPATCHER_CREATION_LIST: + return "ID_AUTOPATCHER_CREATION_LIST"; + + case ID_AUTOPATCHER_DELETION_LIST: + return "ID_AUTOPATCHER_DELETION_LIST"; + + case ID_AUTOPATCHER_GET_PATCH: + return "ID_AUTOPATCHER_GET_PATCH"; + + case ID_AUTOPATCHER_PATCH_LIST: + return "ID_AUTOPATCHER_PATCH_LIST"; + + case ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR: + return "ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR"; + + case ID_AUTOPATCHER_FINISHED_INTERNAL: + return "ID_AUTOPATCHER_FINISHED_INTERNAL"; + + case ID_AUTOPATCHER_FINISHED: + return "ID_AUTOPATCHER_FINISHED"; + + case ID_AUTOPATCHER_RESTART_APPLICATION: + return "ID_AUTOPATCHER_RESTART_APPLICATION"; + + case ID_NAT_PUNCHTHROUGH_REQUEST: + return "ID_NAT_PUNCHTHROUGH_REQUEST"; + + case ID_NAT_GROUP_PUNCHTHROUGH_REQUEST: + return "ID_NAT_GROUP_PUNCHTHROUGH_REQUEST"; + + case ID_NAT_GROUP_PUNCHTHROUGH_REPLY: + return "ID_NAT_GROUP_PUNCHTHROUGH_REPLY"; + + case ID_NAT_CONNECT_AT_TIME: + return "ID_NAT_CONNECT_AT_TIME"; + + case ID_NAT_GET_MOST_RECENT_PORT: + return "ID_NAT_GET_MOST_RECENT_PORT"; + + case ID_NAT_CLIENT_READY: + return "ID_NAT_CLIENT_READY"; + + case ID_NAT_GROUP_PUNCHTHROUGH_FAILURE_NOTIFICATION: + return "ID_NAT_GROUP_PUNCHTHROUGH_FAILURE_NOTIFICATION"; + + case ID_NAT_TARGET_NOT_CONNECTED: + return "ID_NAT_TARGET_NOT_CONNECTED"; + + case ID_NAT_TARGET_UNRESPONSIVE: + return "ID_NAT_TARGET_UNRESPONSIVE"; + + case ID_NAT_CONNECTION_TO_TARGET_LOST: + return "ID_NAT_CONNECTION_TO_TARGET_LOST"; + + case ID_NAT_ALREADY_IN_PROGRESS: + return "ID_NAT_ALREADY_IN_PROGRESS"; + + case ID_NAT_PUNCHTHROUGH_FAILED: + return "ID_NAT_PUNCHTHROUGH_FAILED"; + + case ID_NAT_PUNCHTHROUGH_SUCCEEDED: + return "ID_NAT_PUNCHTHROUGH_SUCCEEDED"; + + case ID_NAT_GROUP_PUNCH_FAILED: + return "ID_NAT_GROUP_PUNCH_FAILED"; + + case ID_NAT_GROUP_PUNCH_SUCCEEDED: + return "ID_NAT_GROUP_PUNCH_SUCCEEDED"; + + case ID_READY_EVENT_SET: + return "ID_READY_EVENT_SET"; + + case ID_READY_EVENT_UNSET: + return "ID_READY_EVENT_UNSET"; + + case ID_READY_EVENT_ALL_SET: + return "ID_READY_EVENT_ALL_SET"; + + case ID_READY_EVENT_QUERY: + return "ID_READY_EVENT_QUERY"; + + case ID_LOBBY_GENERAL: + return "ID_LOBBY_GENERAL"; + + case ID_RPC_REMOTE_ERROR: + return "ID_RPC_REMOTE_ERROR"; + + case ID_RPC_PLUGIN: + return "ID_RPC_PLUGIN"; + + case ID_FILE_LIST_REFERENCE_PUSH: + return "ID_FILE_LIST_REFERENCE_PUSH"; + + case ID_READY_EVENT_FORCE_ALL_SET: + return "ID_READY_EVENT_FORCE_ALL_SET"; + + case ID_ROOMS_EXECUTE_FUNC: + return "ID_ROOMS_EXECUTE_FUNC"; + + case ID_ROOMS_LOGON_STATUS: + return "ID_ROOMS_LOGON_STATUS"; + + case ID_ROOMS_HANDLE_CHANGE: + return "ID_ROOMS_HANDLE_CHANGE"; + + case ID_LOBBY2_SEND_MESSAGE: + return "ID_LOBBY2_SEND_MESSAGE"; + + case ID_LOBBY2_SERVER_ERROR: + return "ID_LOBBY2_SERVER_ERROR"; + + case ID_FCM2_NEW_HOST: + return "ID_FCM2_NEW_HOST"; + + case ID_FCM2_REQUEST_FCMGUID: + return "ID_FCM2_REQUEST_FCMGUID"; + + case ID_FCM2_RESPOND_CONNECTION_COUNT: + return "ID_FCM2_RESPOND_CONNECTION_COUNT"; + + case ID_FCM2_INFORM_FCMGUID: + return "ID_FCM2_INFORM_FCMGUID"; + + case ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT: + return "ID_FCM2_UPDATE_MIN_TOTAL_CONNECTION_COUNT"; + + case ID_UDP_PROXY_GENERAL: + return "ID_UDP_PROXY_GENERAL"; + + case ID_SQLite3_EXEC: + return "ID_SQLite3_EXEC"; + + case ID_SQLite3_UNKNOWN_DB: + return "ID_SQLite3_UNKNOWN_DB"; + + case ID_SQLLITE_LOGGER: + return "ID_SQLLITE_LOGGER"; + + case ID_NAT_TYPE_DETECTION_REQUEST: + return "ID_NAT_TYPE_DETECTION_REQUEST"; + + case ID_NAT_TYPE_DETECTION_RESULT: + return "ID_NAT_TYPE_DETECTION_RESULT"; + + case ID_ROUTER_2_INTERNAL: + return "ID_ROUTER_2_INTERNAL"; + + case ID_ROUTER_2_FORWARDING_NO_PATH: + return "ID_ROUTER_2_FORWARDING_NO_PATH"; + + case ID_ROUTER_2_FORWARDING_ESTABLISHED: + return "ID_ROUTER_2_FORWARDING_ESTABLISHED"; + + case ID_ROUTER_2_REROUTED: + return "ID_ROUTER_2_REROUTED"; + + case ID_TEAM_BALANCER_INTERNAL: + return "ID_TEAM_BALANCER_INTERNAL"; + + case ID_TEAM_BALANCER_REQUESTED_TEAM_CHANGE_PENDING: + return "ID_TEAM_BALANCER_REQUESTED_TEAM_CHANGE_PENDING"; + + case ID_TEAM_BALANCER_TEAMS_LOCKED: + return "ID_TEAM_BALANCER_TEAMS_LOCKED"; + + case ID_TEAM_BALANCER_TEAM_ASSIGNED: + return "ID_TEAM_BALANCER_TEAM_ASSIGNED"; + + case ID_LIGHTSPEED_INTEGRATION: + return "ID_LIGHTSPEED_INTEGRATION"; + + case ID_XBOX_LOBBY: + return "ID_XBOX_LOBBY"; + + case ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS: + return "ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS"; + + case ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS: + return "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS"; + + case ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE: + return "ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE"; + + case ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE: + return "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE"; + + case ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT: + return "ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_TIMEOUT"; + + case ID_TWO_WAY_AUTHENTICATION_NEGOTIATION: + return "ID_TWO_WAY_AUTHENTICATION_NEGOTIATION"; + + case ID_CLOUD_POST_REQUEST: + return "ID_CLOUD_POST_REQUEST"; + + case ID_CLOUD_RELEASE_REQUEST: + return "ID_CLOUD_RELEASE_REQUEST"; + + case ID_CLOUD_GET_REQUEST: + return "ID_CLOUD_GET_REQUEST"; + + case ID_CLOUD_GET_RESPONSE: + return "ID_CLOUD_GET_RESPONSE"; + + case ID_CLOUD_UNSUBSCRIBE_REQUEST: + return "ID_CLOUD_UNSUBSCRIBE_REQUEST"; + + case ID_CLOUD_SERVER_TO_SERVER_COMMAND: + return "ID_CLOUD_SERVER_TO_SERVER_COMMAND"; + + case ID_CLOUD_SUBSCRIPTION_NOTIFICATION: + return "ID_CLOUD_SUBSCRIPTION_NOTIFICATION"; + + case ID_RESERVED_1: + return "ID_RESERVED_1"; + + case ID_RESERVED_2: + return "ID_RESERVED_2"; + + case ID_RESERVED_3: + return "ID_RESERVED_3"; + + case ID_RESERVED_4: + return "ID_RESERVED_4"; + + case ID_RESERVED_5: + return "ID_RESERVED_5"; + + case ID_RESERVED_6: + return "ID_RESERVED_6"; + + case ID_RESERVED_7: + return "ID_RESERVED_7"; + + case ID_RESERVED_8: + return "ID_RESERVED_8"; + + case ID_RESERVED_9: + return "ID_RESERVED_9"; + + default: + break; + } + return "Unknown or user-defined"; +} +#endif + +int RakNetInstance::handleUnconnectedPong(const RakNet::RakString& data, const RakNet::Packet* p, const char* appid, bool insertAtBeginning) +{ + RakNet::RakString appIdentifier(appid); + // This weird code is a result of RakString.Find being pretty useless + bool emptyNameOrLonger = data.GetLength() >= appIdentifier.GetLength(); + + if ( !emptyNameOrLonger || appIdentifier.StrCmp(data.SubStr(0, appIdentifier.GetLength())) != 0) + return -1; + + bool found = false; + for (unsigned int i = 0; i < availableServers.size(); i++) { + if (availableServers[i].address == p->systemAddress) { + availableServers[i].pingTime = RakNet::GetTimeMS(); + + bool emptyName = data.GetLength() == appIdentifier.GetLength(); + if (emptyName) + availableServers[i].name = ""; + else { + availableServers[i].name = data.SubStr(appIdentifier.GetLength(), data.GetLength() - appIdentifier.GetLength()); + } + //LOGI("Swapping name: %s\n", availableServers[i].name.C_String()); + return i; + } + } + PingedCompatibleServer server; + server.address = p->systemAddress; + server.pingTime = RakNet::GetTimeMS(); + server.isSpecial = false; + server.name = data.SubStr(appIdentifier.GetLength(), data.GetLength() - appIdentifier.GetLength()); + + if (insertAtBeginning) { + availableServers.insert(availableServers.begin(), server); + return 0; + } else { + availableServers.push_back(server); + return availableServers.size() - 1; + } +} + +void RakNetInstance::setIsLoggedIn( bool status ) { + _isLoggedIn = status; +} diff --git a/src/network/RakNetInstance.h b/src/network/RakNetInstance.hpp similarity index 97% rename from src/network/RakNetInstance.h rename to src/network/RakNetInstance.hpp index bdacb3c..6f208bb 100755 --- a/src/network/RakNetInstance.h +++ b/src/network/RakNetInstance.hpp @@ -2,8 +2,8 @@ #include #include -#include "../raknet/RakNetTypes.h" -#include "../raknet/RakString.h" +#include "raknet/RakNetTypes.h" +#include "raknet/RakString.h" namespace RakNet { diff --git a/src/network/ServerSideNetworkHandler.cpp b/src/network/ServerSideNetworkHandler.cpp index 39fd077..4a189cb 100755 --- a/src/network/ServerSideNetworkHandler.cpp +++ b/src/network/ServerSideNetworkHandler.cpp @@ -1,759 +1,759 @@ - -#include "ServerSideNetworkHandler.h" -#include "../world/level/Level.h" -#include "../world/entity/player/Player.h" -#include "../world/entity/player/Inventory.h" -#include "../world/Container.h" -#include "../world/inventory/BaseContainerMenu.h" -#include "MinecraftClient.h" -#include "gamemode/GameMode.h" - -#include "RakNetInstance.h" -#include -#include "../client/player/LocalPlayer.h" -#include "../raknet/RakPeerInterface.h" -#include "../raknet/PacketPriority.h" -#include "../server/ServerPlayer.h" -#include "../world/entity/item/FallingTile.h" -#include "network/packet/AddEntityPacket.h" -#include "network/packet/AddItemEntityPacket.h" -#include "network/packet/AddMobPacket.h" -#include "network/packet/AddPaintingPacket.h" -#include "network/packet/AddPlayerPacket.h" -#include "network/packet/AdventureSettingsPacket.h" -#include "network/packet/AnimatePacket.h" -#include "network/packet/ChatPacket.h" -#include "network/packet/ChunkDataPacket.h" -#include "network/packet/ContainerSetSlotPacket.h" -#include "network/packet/DropItemPacket.h" -#include "network/packet/EntityEventPacket.h" -#include "network/packet/InteractPacket.h" -#include "network/packet/LevelEventPacket.h" -#include "network/packet/LoginPacket.h" -#include "network/packet/LoginStatusPacket.h" -#include "network/packet/MessagePacket.h" -#include "network/packet/MovePlayerPacket.h" -#include "network/packet/PlayerActionPacket.h" -#include "network/packet/PlayerArmorEquipmentPacket.h" -#include "network/packet/PlayerEquipmentPacket.h" -#include "network/packet/ReadyPacket.h" -#include "network/packet/RemoveBlockPacket.h" -#include "network/packet/RemoveEntityPacket.h" -#include "network/packet/RemovePlayerPacket.h" -#include "network/packet/RequestChunkPacket.h" -#include "network/packet/RespawnPacket.h" -#include "network/packet/SendInventoryPacket.h" -#include "network/packet/SetHealthPacket.h" -#include "network/packet/SetTimePacket.h" -#include "network/packet/SignUpdatePacket.h" -#include "network/packet/StartGamePacket.h" -#include "network/packet/TileEventPacket.h" -#include "network/packet/UpdateBlockPacket.h" -#include "network/packet/UseItemPacket.h" -#include "world/entity/Painting.h" -#include "world/level/tile/entity/TileEntity.h" - -#define TIMES(x) for(int itc ## __LINE__ = 0; itc ## __LINE__ < x; ++ itc ## __LINE__) - -ServerSideNetworkHandler::ServerSideNetworkHandler(Minecraft* minecraft, IRakNetInstance* raknetInstance) -: minecraft(minecraft), - raknetInstance(raknetInstance), - level(NULL) -{ - allowIncomingConnections(false); - rakPeer = raknetInstance->getPeer(); -} - -ServerSideNetworkHandler::~ServerSideNetworkHandler() -{ - if (level) { - level->removeListener(this); - } - - for (unsigned int i = 0; i < _pendingPlayers.size(); ++i) - delete _pendingPlayers[i]; -} - -void ServerSideNetworkHandler::tileChanged(int x, int y, int z) -{ - //LOGI("tileChanged(%d, %d, %d)\n", x, y, z); - - // broadcast change event - UpdateBlockPacket packet(x, y, z, level->getTile(x, y, z), level->getData(x, y, z)); - RakNet::BitStream bitStream; - packet.write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true); -} - -Packet* ServerSideNetworkHandler::getAddPacketFromEntity( Entity* entity ) { - // if (entity->isMob() && !entity->isPlayer()) { //@fix: This code is duplicated. See if it can be unified. - // auto client = dynamic_cast(minecraft); - - // if (client && client->getPlayer()) { - // // I guess this should always be true, but it crashed somewhere in this - // // function once and I only see this one as a potential problem - // return new AddMobPacket((Mob*)entity); - // } - // } - // else if (entity->isPlayer()) { - - // } else - if (entity->isItemEntity()) { - AddItemEntityPacket* packet = new AddItemEntityPacket((ItemEntity*)entity); - entity->xd = packet->xa(); - entity->yd = packet->ya(); - entity->zd = packet->za(); - //LOGI("item-entity @ server: %f, %f, %f\n", e->xd, e->yd, e->zd); - return packet; - } else if(entity->isHangingEntity()) { - return new AddPaintingPacket((Painting*) entity); - } else { - int type = entity->getEntityTypeId(); - int data = entity->getAuxData(); - - if (EntityTypes::IdFallingTile == type) { - FallingTile* ft = (FallingTile*) entity; - data = -(ft->tile | (ft->data << 16)); - } - - //LOGI("Server: adding entity with %f, %f, %f\n", e->xd, e->yd, e->zd); - AddEntityPacket* packet = new AddEntityPacket(entity, data); - /* - entity->xd = packet->xd; - entity->yd = packet->yd; - entity->zd = packet->zd; - */ - return packet; - } - return NULL; -} -void ServerSideNetworkHandler::entityAdded(Entity* e) { - Packet* packet = getAddPacketFromEntity(e); - if(packet != NULL) { - if (e->isMob() && !e->isPlayer()) { - redistributePacket(packet, rakPeer->GetMyGUID()); - delete packet; - } else { - raknetInstance->send(packet); - // raknetInstance->send always deletes package - } - - } -} - -void ServerSideNetworkHandler::entityRemoved(Entity* e) -{ - if (!e->isPlayer()) { //@fix: This code MIGHT be duplicated. See if it can be unified. - RemoveEntityPacket packet(e->entityId); - redistributePacket(&packet, rakPeer->GetMyGUID()); - } else { // Is a player - RemovePlayerPacket packet((Player*) e); - redistributePacket(&packet, rakPeer->GetMyGUID()); - } -} - -void ServerSideNetworkHandler::redistributePacket(Packet* packet, const RakNet::RakNetGUID& fromPlayer) -{ - // broadcast the new player to all other players - RakNet::BitStream bitStream; - packet->write(&bitStream); - rakPeer->Send(&bitStream, packet->priority, packet->reliability, 0, fromPlayer, true); -} - -void ServerSideNetworkHandler::displayGameMessage(const std::string& message) -{ -#ifndef STANDALONE_SERVER - minecraft->gui.addMessage(message); -#else - LOGI("%s\n", message.c_str()); -#endif - MessagePacket packet(message.c_str()); - raknetInstance->send(packet); -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChatPacket* packet) -{ - displayGameMessage(packet->message); -} - -void ServerSideNetworkHandler::onNewClient(const RakNet::RakNetGUID& clientGuid) -{ - LOGI("onNewClient, client guid: %s\n", clientGuid.ToString()); -} - -void ServerSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) -{ - if (!level) return; - LOGI("onDisconnect\n"); - - const PlayerList& players = level->players; - for (unsigned int i = 0; i < players.size(); i++) - { - Player* player = players[i]; - - if (player->owner == guid) - { - std::string message = player->name; - message += " disconnected from the game"; - displayGameMessage(message); - - //RemoveEntityPacket packet(player->entityId); - //raknetInstance->send(packet); - player->reallyRemoveIfPlayer = true; - level->removeEntity(player); - //level->removePlayer(player); - - LOGI("&e@disc: %p", player); - - break; - } - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPacket* packet) -{ - if (!level) return; - if (!_allowIncoming) return; - - LOGI("LoginPacket\n"); - - int loginStatus = LoginStatus::Success; - // - // Bad/incompatible client version - // - bool oldClient = packet->clientNetworkVersion < SharedConstants::NetworkProtocolLowestSupportedVersion; - bool oldServer = packet->clientNetworkLowestSupportedVersion > SharedConstants::NetworkProtocolVersion; - if (oldClient || oldServer) - loginStatus = oldClient? LoginStatus::Failed_ClientOld : LoginStatus::Failed_ServerOld; - - RakNet::BitStream bitStream; - LoginStatusPacket(loginStatus).write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - - if (LoginStatus::Success != loginStatus) - return; - - // - // Valid client version - // - Player* newPlayer = new ServerPlayer(minecraft, level); - - minecraft->gameMode->initAbilities(newPlayer->abilities); - newPlayer->owner = source; - newPlayer->name = packet->clientName.C_String(); - _pendingPlayers.push_back(newPlayer); - - // Reset the player so he doesn't spawn inside blocks - while (newPlayer->y > 0) { - newPlayer->setPos(newPlayer->x, newPlayer->y, newPlayer->z); - if (level->getCubes(newPlayer, newPlayer->bb).size() == 0) break; - newPlayer->y += 1; - } - newPlayer->moveTo(newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z, newPlayer->yRot, newPlayer->xRot); - - // send world seed - { - RakNet::BitStream bitStream; - - // @todo: Read from LevelData? - int gameType = minecraft->isCreativeMode() - ? GameType::Creative - : GameType::Survival; - - StartGamePacket( - level->getSeed(), - level->getLevelData()->getGeneratorVersion(), - gameType, - newPlayer->entityId, - newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z - ).write(&bitStream); - - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ReadyPacket* packet) -{ - if (!level) return; - - if (packet->type == ReadyPacket::READY_CLIENTGENERATION) - onReady_ClientGeneration(source); - - if (packet->type == ReadyPacket::READY_REQUESTEDCHUNKS) - onReady_RequestedChunks(source); -} - -void ServerSideNetworkHandler::onReady_ClientGeneration(const RakNet::RakNetGUID& source) -{ - Player* newPlayer = popPendingPlayer(source); - if (!newPlayer) { - for (int i = 0; i < 3; ++i) - LOGE("We don't have a user associated with this player!\n"); - return; - } - // Create a bitstream that can be used by everyone (after ::reset() ) - RakNet::BitStream bitStream; - - // send level info - SetTimePacket(level->getTime()).write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - - // send adventure settings (includes showNameTags, etc.) - bitStream.Reset(); - AdventureSettingsPacket(level->adventureSettings).write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - - // send all pre-existing players to the new player - const PlayerList& players = level->players; - for (unsigned int i = 0; i < players.size(); i++) { - Player* player = players[i]; - - bitStream.Reset(); - AddPlayerPacket(player).write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - - if (player->getArmorTypeHash()) { - bitStream.Reset(); - PlayerArmorEquipmentPacket(player).write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - } - } - - level->addEntity(newPlayer); -#ifndef STANDALONE_SERVER - minecraft->gui.addMessage(newPlayer->name + " joined the game"); -#else - LOGW("%s joined the game\n", newPlayer->name.c_str()); -#endif - - // Send all Entities to the new player - for (unsigned int i = 0; i < level->entities.size(); ++i) { - Entity* e = level->entities[i]; - Packet* packet = getAddPacketFromEntity(e); - if(packet != NULL) { - bitStream.Reset(); - packet->write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - delete packet; - } - } - - // Additional packets - // * set spawn - /* - bitStream.Reset(); - SetSpawnPositionPacket spawnPacket(level->getSharedSpawnPos()); - raknetInstance->send(source, spawnPacket); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - */ - - // broadcast the new player to all other players - bitStream.Reset(); - AddPlayerPacket(newPlayer).write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, true); -} - -// -// Messages to be sent after client has finished applying changes -// -void ServerSideNetworkHandler::onReady_RequestedChunks(const RakNet::RakNetGUID& source) -{ - RakNet::BitStream bitStream; - // Send all TileEntities to the new player - for (unsigned int i = 0; i < level->tileEntities.size(); ++i) { - TileEntity* e = level->tileEntities[i]; - Packet* packet = e->getUpdatePacket(); - if (packet != NULL) { - bitStream.Reset(); - packet->write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - delete packet; - } - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlayerPacket* packet) -{ - if (!level) return; - - //LOGI("MovePlayerPacket\n"); - if (Entity* entity = level->getEntity(packet->entityId)) - { - entity->xd = entity->yd = entity->zd = 0; - entity->lerpTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot, 3); - - // broadcast this packet to other clients - redistributePacket(packet, source); - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveBlockPacket* packet){ - if (!level) return; - - Player* player = getPlayer(source); - if (!player) return; - - player->swing(); - - int x = packet->x, y = packet->y, z = packet->z; - - // code copied from GameMode.cpp - int oldId = level->getTile(x, y, z); - int data = level->getData(x, y, z); - Tile* oldTile = Tile::tiles[oldId]; - bool changed = level->setTile(x, y, z, 0); - if (oldTile != NULL && changed) { - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, oldTile->soundType->getBreakSound(), (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f); - - if (minecraft->gameMode->isSurvivalType() && player->canDestroy(oldTile)) - //oldTile->spawnResources(level, x, y, z, data, 1); //@todo - oldTile->playerDestroy(level, player, x, y, z, data); - - oldTile->destroy(level, x, y, z, data); - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RequestChunkPacket* packet) -{ - if (!level) - return; - - LevelChunk* chunk = level->getChunk(packet->x, packet->z); - - if (!chunk) - return; - - ChunkDataPacket cpacket(chunk->x, chunk->z, chunk); - - RakNet::BitStream bitStream; - cpacket.write(&bitStream); - rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); - //LOGI("RequestChunkPacket @ (%d, %d). %d bytes\n", packet->x, packet->z, cpacket.chunkData.GetNumberOfBytesUsed()); - //LOGI("size: %d\n", bitStream.GetNumberOfBytesUsed()); - - const LevelChunk::TEMap& teMap = chunk->getTileEntityMap(); - for (LevelChunk::TEMapCIterator cit = teMap.begin(); cit != teMap.end(); ++cit) { - TileEntity* te = cit->second; - if (Packet* p = te->getUpdatePacket()) { - bitStream.Reset(); - p->write(&bitStream); - raknetInstance->send(source, p); - } - } -} - -void ServerSideNetworkHandler::levelGenerated( Level* level ) -{ - this->level = level; - - // auto client = dynamic_cast(minecraft); - - // if (client && client->getPlayer()) { - // client->getPlayer()->owner = rakPeer->GetMyGUID(); - // } - - level->addListener(this); -#ifndef STANDALONE_SERVER - allowIncomingConnections(minecraft->options.getBooleanValue(OPTIONS_SERVER_VISIBLE)); -#else - allowIncomingConnections(true); -#endif -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerEquipmentPacket* packet) -{ - if (!level) return; - - Player* player = getPlayer(source); - if (!player) return; - if (rakPeer->GetMyGUID() == player->owner) return; - - // override the player's inventory - //int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue); - int slot = Inventory::MAX_SELECTION_SIZE; - if (slot >= 0) { - if (packet->itemId == 0) { - player->inventory->clearSlot(slot); - } else { - // @note: 128 is an ugly hack for depletable items. - // @todo: fix - ItemInstance newItem(packet->itemId, 128, packet->itemAuxValue); - player->inventory->replaceSlot(slot, &newItem); - } - player->inventory->moveToSelectedSlot(slot, true); - redistributePacket(packet, source); - } else { - LOGW("Warning: Remote player doesn't have his thing, Odd!\n"); - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerArmorEquipmentPacket* packet) { - if (!level) return; - - Player* player = getPlayer(source); - if (!player) return; - if (rakPeer->GetMyGUID() == player->owner) return; - - packet->fillIn(player); - redistributePacket(packet, source); -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, InteractPacket* packet) { - if (!level) return; - - Entity* src = level->getEntity(packet->sourceId); - Entity* entity = level->getEntity(packet->targetId); - if (src && entity && src->isPlayer()) - { - Player* player = (Player*) src; - if (InteractPacket::Attack == packet->action) { - player->swing(); - minecraft->gameMode->attack(player, entity); - } - if (InteractPacket::Interact == packet->action) { - player->swing(); - minecraft->gameMode->interact(player, entity); - } - - redistributePacket(packet, source); - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimatePacket* packet) -{ - if (!level) - return; - - // auto client = dynamic_cast(minecraft); - - // // Own player -> invalid - // if (client && client->getPlayer() && client->getPlayer()->entityId == packet->entityId) { - // return; - // } - - Entity* entity = level->getEntity(packet->entityId); - if (!entity || !entity->isPlayer()) - return; - - Player* player = (Player*) entity; - - switch (packet->action) { - case AnimatePacket::Swing: - player->swing(); - break; - default: - LOGW("Unknown Animate action: %d\n", packet->action); - break; - } - redistributePacket(packet, source); -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) -{ - if (!level) return; - - LOGI("UseItemPacket\n"); - Entity* entity = level->getEntity(packet->entityId); - if (entity && entity->isPlayer()) { - Player* player = (Player*) entity; - int x = packet->x, y = packet->y, z = packet->z; - Tile* t = Tile::tiles[level->getTile(x, y, z)]; - - if (t == Tile::invisible_bedrock) return; - if (t && t->use(level, x, y, z, player)) return; - if (packet->item.isNull()) return; - - ItemInstance* item = &packet->item; - - if(packet->face == 255) { - // Special case: x,y,z means direction-of-action - player->aimDirection.set(packet->x / 32768.0f, packet->y / 32768.0f, packet->z / 32768.0f); - minecraft->gameMode->useItem(player, level, item); - } - else { - minecraft->gameMode->useItemOn(player, level, item, packet->x, packet->y, packet->z, packet->face, - Vec3(packet->clickX + packet->x, packet->clickY + packet->y, packet->clickZ + packet->z)); - } - - //LOGW("Use Item not working! Out of synch?\n"); - - // Don't have to redistribute (ugg.. this will mess up), cause tileUpdated is sent - //redistributePacket(packet, source); - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, EntityEventPacket* packet) { - if (!level) return; - - if (Entity* e = level->getEntity(packet->entityId)) - e->handleEntityEvent(packet->eventId); -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerActionPacket* packet) -{ - if (!level) return; - LOGI("PlayerActionPacket\n"); - Entity* entity = level->getEntity(packet->entityId); - if (entity && entity->isPlayer()) { - Player* player = (Player*) entity; - if(packet->action == PlayerActionPacket::RELEASE_USE_ITEM) { - minecraft->gameMode->releaseUsingItem(player); - return; - } - else if(packet->action == PlayerActionPacket::STOP_SLEEPING) { - player->stopSleepInBed(true, true, true); - } - } -} - -void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, RespawnPacket* packet ) -{ - if (!level) return; - - NetEventCallback::handle(level, source, packet ); - redistributePacket(packet, source); -} - -void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SendInventoryPacket* packet ) -{ - if (!level) return; - - Entity* entity = level->getEntity(packet->entityId); - if (entity && entity->isPlayer()) { - Player* p = (Player*)entity; - p->inventory->replace(packet->items, packet->numItems); - if ((packet->extra & SendInventoryPacket::ExtraDrop) != 0) { - p->inventory->dropAll(false); - //@todo @armor : Drop armor - } - } -} - -void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, DropItemPacket* packet ) -{ - if (!level) return; - - Entity* entity = level->getEntity(packet->entityId); - if (entity && entity->isPlayer()) { - Player* p = (Player*)entity; - p->drop(new ItemInstance(packet->item), packet->dropType != 0); - } -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet) { - if (!level) return; - - Player* p = findPlayer(level, &source); - if (!p) return; - - // // if (p != minecraft->player) - // static_cast(p)->doCloseContainer(); - - if (auto sp = dynamic_cast(p)) - sp->doCloseContainer(); -} - -void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetSlotPacket* packet) { - if (!level) return; - - Player* p = findPlayer(level, &source); - if (!p) return; - - if (p->containerMenu == NULL) { - LOGW("User has no container!\n"); - return; - } - if (p->containerMenu->containerId != packet->containerId) - { - LOGW("Wrong container id: %d vs %d\n", p->containerMenu->containerId, packet->containerId); - return; - } - - if (ContainerType::FURNACE == p->containerMenu->containerType) { - //LOGI("Server:Setting slot %d: %s\n", packet->slot, packet->item.toString().c_str()); - p->containerMenu->setSlot(packet->slot, &packet->item); - //p->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); - } - if (ContainerType::CONTAINER == p->containerMenu->containerType) { - //LOGI("Server:Setting slot %d: %s\n", packet->slot, packet->item.toString().c_str()); - p->containerMenu->setSlot(packet->slot, &packet->item); - //p->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); - } -} - -void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SetHealthPacket* packet ) -{ - for (unsigned int i = 0; i < level->players.size(); ++i) { - Player* p = level->players[i]; - if (p->owner == source) { - if (packet->health <= -32) { - int diff = packet->health - SetHealthPacket::HEALTH_MODIFY_OFFSET; - if (diff > 0) p->hurt(NULL, diff); - else if (diff < 0) p->heal(-diff); - } - break; - } - } -} - -void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SignUpdatePacket* packet ) { - redistributePacket(packet, source); - if (!level) - return; - - TileEntity* te = level->getTileEntity(packet->x, packet->y, packet->z); - if (TileEntity::isType(te, TileEntityType::Sign)) { - SignTileEntity* ste = (SignTileEntity*) te; - if (ste->isEditable()) { - for (int i = 0; i < SignTileEntity::NUM_LINES; i++) { - ste->messages[i] = packet->lines[i]; - } - //ste->setChanged(); - } - } -} - -void ServerSideNetworkHandler::allowIncomingConnections( bool doAllow ) -{ - if (doAllow) { - raknetInstance->announceServer(minecraft->getServerName()); - } else { - raknetInstance->announceServer(""); - } - _allowIncoming = doAllow; -} - -Player* ServerSideNetworkHandler::popPendingPlayer( const RakNet::RakNetGUID& source ) -{ - if (!level) { - LOGE("Could not add player since Level is NULL!\n"); - return NULL; - } - - for (unsigned int i = 0; i < _pendingPlayers.size(); ++i) { - Player* p = _pendingPlayers[i]; - if (p->owner == source) { - _pendingPlayers.erase(_pendingPlayers.begin() + i); - return p; - } - } - return NULL; -} - -void ServerSideNetworkHandler::levelEvent( Player* source, int type, int x, int y, int z, int data ) -{ - LevelEventPacket packet(type, x, y, z, data); - redistributePacket(&packet, source? source->owner : rakPeer->GetMyGUID()); -} - -void ServerSideNetworkHandler::tileEvent( int x, int y, int z, int b0, int b1 ) -{ - TileEventPacket packet(x, y, z, b0, b1); - raknetInstance->send(packet); -} - -Player* ServerSideNetworkHandler::getPlayer( const RakNet::RakNetGUID& source ) { - for (unsigned int i = 0; i < level->players.size(); ++i) - if (source == level->players[i]->owner) return level->players[i]; - return NULL; -} + +#include "ServerSideNetworkHandler.hpp" +#include "world/level/Level.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/Container.hpp" +#include "world/inventory/BaseContainerMenu.hpp" +#include "MinecraftClient.hpp" +#include "gamemode/GameMode.hpp" + +#include "RakNetInstance.hpp" +#include +#include "client/player/LocalPlayer.hpp" +#include "raknet/RakPeerInterface.h" +#include "raknet/PacketPriority.h" +#include "server/ServerPlayer.hpp" +#include "world/entity/item/FallingTile.hpp" +#include "network/packet/AddEntityPacket.hpp" +#include "network/packet/AddItemEntityPacket.hpp" +#include "network/packet/AddMobPacket.hpp" +#include "network/packet/AddPaintingPacket.hpp" +#include "network/packet/AddPlayerPacket.hpp" +#include "network/packet/AdventureSettingsPacket.hpp" +#include "network/packet/AnimatePacket.hpp" +#include "network/packet/ChatPacket.hpp" +#include "network/packet/ChunkDataPacket.hpp" +#include "network/packet/ContainerSetSlotPacket.hpp" +#include "network/packet/DropItemPacket.hpp" +#include "network/packet/EntityEventPacket.hpp" +#include "network/packet/InteractPacket.hpp" +#include "network/packet/LevelEventPacket.hpp" +#include "network/packet/LoginPacket.hpp" +#include "network/packet/LoginStatusPacket.hpp" +#include "network/packet/MessagePacket.hpp" +#include "network/packet/MovePlayerPacket.hpp" +#include "network/packet/PlayerActionPacket.hpp" +#include "network/packet/PlayerArmorEquipmentPacket.hpp" +#include "network/packet/PlayerEquipmentPacket.hpp" +#include "network/packet/ReadyPacket.hpp" +#include "network/packet/RemoveBlockPacket.hpp" +#include "network/packet/RemoveEntityPacket.hpp" +#include "network/packet/RemovePlayerPacket.hpp" +#include "network/packet/RequestChunkPacket.hpp" +#include "network/packet/RespawnPacket.hpp" +#include "network/packet/SendInventoryPacket.hpp" +#include "network/packet/SetHealthPacket.hpp" +#include "network/packet/SetTimePacket.hpp" +#include "network/packet/SignUpdatePacket.hpp" +#include "network/packet/StartGamePacket.hpp" +#include "network/packet/TileEventPacket.hpp" +#include "network/packet/UpdateBlockPacket.hpp" +#include "network/packet/UseItemPacket.hpp" +#include "world/entity/Painting.hpp" +#include "world/level/tile/entity/TileEntity.hpp" + +#define TIMES(x) for(int itc ## __LINE__ = 0; itc ## __LINE__ < x; ++ itc ## __LINE__) + +ServerSideNetworkHandler::ServerSideNetworkHandler(Minecraft* minecraft, IRakNetInstance* raknetInstance) +: minecraft(minecraft), + raknetInstance(raknetInstance), + level(NULL) +{ + allowIncomingConnections(false); + rakPeer = raknetInstance->getPeer(); +} + +ServerSideNetworkHandler::~ServerSideNetworkHandler() +{ + if (level) { + level->removeListener(this); + } + + for (unsigned int i = 0; i < _pendingPlayers.size(); ++i) + delete _pendingPlayers[i]; +} + +void ServerSideNetworkHandler::tileChanged(int x, int y, int z) +{ + //LOGI("tileChanged(%d, %d, %d)\n", x, y, z); + + // broadcast change event + UpdateBlockPacket packet(x, y, z, level->getTile(x, y, z), level->getData(x, y, z)); + RakNet::BitStream bitStream; + packet.write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true); +} + +Packet* ServerSideNetworkHandler::getAddPacketFromEntity( Entity* entity ) { + // if (entity->isMob() && !entity->isPlayer()) { //@fix: This code is duplicated. See if it can be unified. + // auto client = dynamic_cast(minecraft); + + // if (client && client->getPlayer()) { + // // I guess this should always be true, but it crashed somewhere in this + // // function once and I only see this one as a potential problem + // return new AddMobPacket((Mob*)entity); + // } + // } + // else if (entity->isPlayer()) { + + // } else + if (entity->isItemEntity()) { + AddItemEntityPacket* packet = new AddItemEntityPacket((ItemEntity*)entity); + entity->xd = packet->xa(); + entity->yd = packet->ya(); + entity->zd = packet->za(); + //LOGI("item-entity @ server: %f, %f, %f\n", e->xd, e->yd, e->zd); + return packet; + } else if(entity->isHangingEntity()) { + return new AddPaintingPacket((Painting*) entity); + } else { + int type = entity->getEntityTypeId(); + int data = entity->getAuxData(); + + if (EntityTypes::IdFallingTile == type) { + FallingTile* ft = (FallingTile*) entity; + data = -(ft->tile | (ft->data << 16)); + } + + //LOGI("Server: adding entity with %f, %f, %f\n", e->xd, e->yd, e->zd); + AddEntityPacket* packet = new AddEntityPacket(entity, data); + /* + entity->xd = packet->xd; + entity->yd = packet->yd; + entity->zd = packet->zd; + */ + return packet; + } + return NULL; +} +void ServerSideNetworkHandler::entityAdded(Entity* e) { + Packet* packet = getAddPacketFromEntity(e); + if(packet != NULL) { + if (e->isMob() && !e->isPlayer()) { + redistributePacket(packet, rakPeer->GetMyGUID()); + delete packet; + } else { + raknetInstance->send(packet); + // raknetInstance->send always deletes package + } + + } +} + +void ServerSideNetworkHandler::entityRemoved(Entity* e) +{ + if (!e->isPlayer()) { //@fix: This code MIGHT be duplicated. See if it can be unified. + RemoveEntityPacket packet(e->entityId); + redistributePacket(&packet, rakPeer->GetMyGUID()); + } else { // Is a player + RemovePlayerPacket packet((Player*) e); + redistributePacket(&packet, rakPeer->GetMyGUID()); + } +} + +void ServerSideNetworkHandler::redistributePacket(Packet* packet, const RakNet::RakNetGUID& fromPlayer) +{ + // broadcast the new player to all other players + RakNet::BitStream bitStream; + packet->write(&bitStream); + rakPeer->Send(&bitStream, packet->priority, packet->reliability, 0, fromPlayer, true); +} + +void ServerSideNetworkHandler::displayGameMessage(const std::string& message) +{ +#ifndef STANDALONE_SERVER + minecraft->gui.addMessage(message); +#else + LOGI("%s\n", message.c_str()); +#endif + MessagePacket packet(message.c_str()); + raknetInstance->send(packet); +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChatPacket* packet) +{ + displayGameMessage(packet->message); +} + +void ServerSideNetworkHandler::onNewClient(const RakNet::RakNetGUID& clientGuid) +{ + LOGI("onNewClient, client guid: %s\n", clientGuid.ToString()); +} + +void ServerSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) +{ + if (!level) return; + LOGI("onDisconnect\n"); + + const PlayerList& players = level->players; + for (unsigned int i = 0; i < players.size(); i++) + { + Player* player = players[i]; + + if (player->owner == guid) + { + std::string message = player->name; + message += " disconnected from the game"; + displayGameMessage(message); + + //RemoveEntityPacket packet(player->entityId); + //raknetInstance->send(packet); + player->reallyRemoveIfPlayer = true; + level->removeEntity(player); + //level->removePlayer(player); + + LOGI("&e@disc: %p", player); + + break; + } + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPacket* packet) +{ + if (!level) return; + if (!_allowIncoming) return; + + LOGI("LoginPacket\n"); + + int loginStatus = LoginStatus::Success; + // + // Bad/incompatible client version + // + bool oldClient = packet->clientNetworkVersion < SharedConstants::NetworkProtocolLowestSupportedVersion; + bool oldServer = packet->clientNetworkLowestSupportedVersion > SharedConstants::NetworkProtocolVersion; + if (oldClient || oldServer) + loginStatus = oldClient? LoginStatus::Failed_ClientOld : LoginStatus::Failed_ServerOld; + + RakNet::BitStream bitStream; + LoginStatusPacket(loginStatus).write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + + if (LoginStatus::Success != loginStatus) + return; + + // + // Valid client version + // + Player* newPlayer = new ServerPlayer(minecraft, level); + + minecraft->gameMode->initAbilities(newPlayer->abilities); + newPlayer->owner = source; + newPlayer->name = packet->clientName.C_String(); + _pendingPlayers.push_back(newPlayer); + + // Reset the player so he doesn't spawn inside blocks + while (newPlayer->y > 0) { + newPlayer->setPos(newPlayer->x, newPlayer->y, newPlayer->z); + if (level->getCubes(newPlayer, newPlayer->bb).size() == 0) break; + newPlayer->y += 1; + } + newPlayer->moveTo(newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z, newPlayer->yRot, newPlayer->xRot); + + // send world seed + { + RakNet::BitStream bitStream; + + // @todo: Read from LevelData? + int gameType = minecraft->isCreativeMode() + ? GameType::Creative + : GameType::Survival; + + StartGamePacket( + level->getSeed(), + level->getLevelData()->getGeneratorVersion(), + gameType, + newPlayer->entityId, + newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z + ).write(&bitStream); + + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ReadyPacket* packet) +{ + if (!level) return; + + if (packet->type == ReadyPacket::READY_CLIENTGENERATION) + onReady_ClientGeneration(source); + + if (packet->type == ReadyPacket::READY_REQUESTEDCHUNKS) + onReady_RequestedChunks(source); +} + +void ServerSideNetworkHandler::onReady_ClientGeneration(const RakNet::RakNetGUID& source) +{ + Player* newPlayer = popPendingPlayer(source); + if (!newPlayer) { + for (int i = 0; i < 3; ++i) + LOGE("We don't have a user associated with this player!\n"); + return; + } + // Create a bitstream that can be used by everyone (after ::reset() ) + RakNet::BitStream bitStream; + + // send level info + SetTimePacket(level->getTime()).write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + + // send adventure settings (includes showNameTags, etc.) + bitStream.Reset(); + AdventureSettingsPacket(level->adventureSettings).write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + + // send all pre-existing players to the new player + const PlayerList& players = level->players; + for (unsigned int i = 0; i < players.size(); i++) { + Player* player = players[i]; + + bitStream.Reset(); + AddPlayerPacket(player).write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + + if (player->getArmorTypeHash()) { + bitStream.Reset(); + PlayerArmorEquipmentPacket(player).write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + } + } + + level->addEntity(newPlayer); +#ifndef STANDALONE_SERVER + minecraft->gui.addMessage(newPlayer->name + " joined the game"); +#else + LOGW("%s joined the game\n", newPlayer->name.c_str()); +#endif + + // Send all Entities to the new player + for (unsigned int i = 0; i < level->entities.size(); ++i) { + Entity* e = level->entities[i]; + Packet* packet = getAddPacketFromEntity(e); + if(packet != NULL) { + bitStream.Reset(); + packet->write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + delete packet; + } + } + + // Additional packets + // * set spawn + /* + bitStream.Reset(); + SetSpawnPositionPacket spawnPacket(level->getSharedSpawnPos()); + raknetInstance->send(source, spawnPacket); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + */ + + // broadcast the new player to all other players + bitStream.Reset(); + AddPlayerPacket(newPlayer).write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, true); +} + +// +// Messages to be sent after client has finished applying changes +// +void ServerSideNetworkHandler::onReady_RequestedChunks(const RakNet::RakNetGUID& source) +{ + RakNet::BitStream bitStream; + // Send all TileEntities to the new player + for (unsigned int i = 0; i < level->tileEntities.size(); ++i) { + TileEntity* e = level->tileEntities[i]; + Packet* packet = e->getUpdatePacket(); + if (packet != NULL) { + bitStream.Reset(); + packet->write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + delete packet; + } + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlayerPacket* packet) +{ + if (!level) return; + + //LOGI("MovePlayerPacket\n"); + if (Entity* entity = level->getEntity(packet->entityId)) + { + entity->xd = entity->yd = entity->zd = 0; + entity->lerpTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot, 3); + + // broadcast this packet to other clients + redistributePacket(packet, source); + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveBlockPacket* packet){ + if (!level) return; + + Player* player = getPlayer(source); + if (!player) return; + + player->swing(); + + int x = packet->x, y = packet->y, z = packet->z; + + // code copied from GameMode.cpp + int oldId = level->getTile(x, y, z); + int data = level->getData(x, y, z); + Tile* oldTile = Tile::tiles[oldId]; + bool changed = level->setTile(x, y, z, 0); + if (oldTile != NULL && changed) { + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, oldTile->soundType->getBreakSound(), (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f); + + if (minecraft->gameMode->isSurvivalType() && player->canDestroy(oldTile)) + //oldTile->spawnResources(level, x, y, z, data, 1); //@todo + oldTile->playerDestroy(level, player, x, y, z, data); + + oldTile->destroy(level, x, y, z, data); + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RequestChunkPacket* packet) +{ + if (!level) + return; + + LevelChunk* chunk = level->getChunk(packet->x, packet->z); + + if (!chunk) + return; + + ChunkDataPacket cpacket(chunk->x, chunk->z, chunk); + + RakNet::BitStream bitStream; + cpacket.write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + //LOGI("RequestChunkPacket @ (%d, %d). %d bytes\n", packet->x, packet->z, cpacket.chunkData.GetNumberOfBytesUsed()); + //LOGI("size: %d\n", bitStream.GetNumberOfBytesUsed()); + + const LevelChunk::TEMap& teMap = chunk->getTileEntityMap(); + for (LevelChunk::TEMapCIterator cit = teMap.begin(); cit != teMap.end(); ++cit) { + TileEntity* te = cit->second; + if (Packet* p = te->getUpdatePacket()) { + bitStream.Reset(); + p->write(&bitStream); + raknetInstance->send(source, p); + } + } +} + +void ServerSideNetworkHandler::levelGenerated( Level* level ) +{ + this->level = level; + + // auto client = dynamic_cast(minecraft); + + // if (client && client->getPlayer()) { + // client->getPlayer()->owner = rakPeer->GetMyGUID(); + // } + + level->addListener(this); +#ifndef STANDALONE_SERVER + allowIncomingConnections(minecraft->options.getBooleanValue(OPTIONS_SERVER_VISIBLE)); +#else + allowIncomingConnections(true); +#endif +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerEquipmentPacket* packet) +{ + if (!level) return; + + Player* player = getPlayer(source); + if (!player) return; + if (rakPeer->GetMyGUID() == player->owner) return; + + // override the player's inventory + //int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue); + int slot = Inventory::MAX_SELECTION_SIZE; + if (slot >= 0) { + if (packet->itemId == 0) { + player->inventory->clearSlot(slot); + } else { + // @note: 128 is an ugly hack for depletable items. + // @todo: fix + ItemInstance newItem(packet->itemId, 128, packet->itemAuxValue); + player->inventory->replaceSlot(slot, &newItem); + } + player->inventory->moveToSelectedSlot(slot, true); + redistributePacket(packet, source); + } else { + LOGW("Warning: Remote player doesn't have his thing, Odd!\n"); + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerArmorEquipmentPacket* packet) { + if (!level) return; + + Player* player = getPlayer(source); + if (!player) return; + if (rakPeer->GetMyGUID() == player->owner) return; + + packet->fillIn(player); + redistributePacket(packet, source); +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, InteractPacket* packet) { + if (!level) return; + + Entity* src = level->getEntity(packet->sourceId); + Entity* entity = level->getEntity(packet->targetId); + if (src && entity && src->isPlayer()) + { + Player* player = (Player*) src; + if (InteractPacket::Attack == packet->action) { + player->swing(); + minecraft->gameMode->attack(player, entity); + } + if (InteractPacket::Interact == packet->action) { + player->swing(); + minecraft->gameMode->interact(player, entity); + } + + redistributePacket(packet, source); + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimatePacket* packet) +{ + if (!level) + return; + + // auto client = dynamic_cast(minecraft); + + // // Own player -> invalid + // if (client && client->getPlayer() && client->getPlayer()->entityId == packet->entityId) { + // return; + // } + + Entity* entity = level->getEntity(packet->entityId); + if (!entity || !entity->isPlayer()) + return; + + Player* player = (Player*) entity; + + switch (packet->action) { + case AnimatePacket::Swing: + player->swing(); + break; + default: + LOGW("Unknown Animate action: %d\n", packet->action); + break; + } + redistributePacket(packet, source); +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) +{ + if (!level) return; + + LOGI("UseItemPacket\n"); + Entity* entity = level->getEntity(packet->entityId); + if (entity && entity->isPlayer()) { + Player* player = (Player*) entity; + int x = packet->x, y = packet->y, z = packet->z; + Tile* t = Tile::tiles[level->getTile(x, y, z)]; + + if (t == Tile::invisible_bedrock) return; + if (t && t->use(level, x, y, z, player)) return; + if (packet->item.isNull()) return; + + ItemInstance* item = &packet->item; + + if(packet->face == 255) { + // Special case: x,y,z means direction-of-action + player->aimDirection.set(packet->x / 32768.0f, packet->y / 32768.0f, packet->z / 32768.0f); + minecraft->gameMode->useItem(player, level, item); + } + else { + minecraft->gameMode->useItemOn(player, level, item, packet->x, packet->y, packet->z, packet->face, + Vec3(packet->clickX + packet->x, packet->clickY + packet->y, packet->clickZ + packet->z)); + } + + //LOGW("Use Item not working! Out of synch?\n"); + + // Don't have to redistribute (ugg.. this will mess up), cause tileUpdated is sent + //redistributePacket(packet, source); + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, EntityEventPacket* packet) { + if (!level) return; + + if (Entity* e = level->getEntity(packet->entityId)) + e->handleEntityEvent(packet->eventId); +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerActionPacket* packet) +{ + if (!level) return; + LOGI("PlayerActionPacket\n"); + Entity* entity = level->getEntity(packet->entityId); + if (entity && entity->isPlayer()) { + Player* player = (Player*) entity; + if(packet->action == PlayerActionPacket::RELEASE_USE_ITEM) { + minecraft->gameMode->releaseUsingItem(player); + return; + } + else if(packet->action == PlayerActionPacket::STOP_SLEEPING) { + player->stopSleepInBed(true, true, true); + } + } +} + +void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, RespawnPacket* packet ) +{ + if (!level) return; + + NetEventCallback::handle(level, source, packet ); + redistributePacket(packet, source); +} + +void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SendInventoryPacket* packet ) +{ + if (!level) return; + + Entity* entity = level->getEntity(packet->entityId); + if (entity && entity->isPlayer()) { + Player* p = (Player*)entity; + p->inventory->replace(packet->items, packet->numItems); + if ((packet->extra & SendInventoryPacket::ExtraDrop) != 0) { + p->inventory->dropAll(false); + //@todo @armor : Drop armor + } + } +} + +void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, DropItemPacket* packet ) +{ + if (!level) return; + + Entity* entity = level->getEntity(packet->entityId); + if (entity && entity->isPlayer()) { + Player* p = (Player*)entity; + p->drop(new ItemInstance(packet->item), packet->dropType != 0); + } +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet) { + if (!level) return; + + Player* p = findPlayer(level, &source); + if (!p) return; + + // // if (p != minecraft->player) + // static_cast(p)->doCloseContainer(); + + if (auto sp = dynamic_cast(p)) + sp->doCloseContainer(); +} + +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetSlotPacket* packet) { + if (!level) return; + + Player* p = findPlayer(level, &source); + if (!p) return; + + if (p->containerMenu == NULL) { + LOGW("User has no container!\n"); + return; + } + if (p->containerMenu->containerId != packet->containerId) + { + LOGW("Wrong container id: %d vs %d\n", p->containerMenu->containerId, packet->containerId); + return; + } + + if (ContainerType::FURNACE == p->containerMenu->containerType) { + //LOGI("Server:Setting slot %d: %s\n", packet->slot, packet->item.toString().c_str()); + p->containerMenu->setSlot(packet->slot, &packet->item); + //p->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); + } + if (ContainerType::CONTAINER == p->containerMenu->containerType) { + //LOGI("Server:Setting slot %d: %s\n", packet->slot, packet->item.toString().c_str()); + p->containerMenu->setSlot(packet->slot, &packet->item); + //p->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); + } +} + +void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SetHealthPacket* packet ) +{ + for (unsigned int i = 0; i < level->players.size(); ++i) { + Player* p = level->players[i]; + if (p->owner == source) { + if (packet->health <= -32) { + int diff = packet->health - SetHealthPacket::HEALTH_MODIFY_OFFSET; + if (diff > 0) p->hurt(NULL, diff); + else if (diff < 0) p->heal(-diff); + } + break; + } + } +} + +void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SignUpdatePacket* packet ) { + redistributePacket(packet, source); + if (!level) + return; + + TileEntity* te = level->getTileEntity(packet->x, packet->y, packet->z); + if (TileEntity::isType(te, TileEntityType::Sign)) { + SignTileEntity* ste = (SignTileEntity*) te; + if (ste->isEditable()) { + for (int i = 0; i < SignTileEntity::NUM_LINES; i++) { + ste->messages[i] = packet->lines[i]; + } + //ste->setChanged(); + } + } +} + +void ServerSideNetworkHandler::allowIncomingConnections( bool doAllow ) +{ + if (doAllow) { + raknetInstance->announceServer(minecraft->getServerName()); + } else { + raknetInstance->announceServer(""); + } + _allowIncoming = doAllow; +} + +Player* ServerSideNetworkHandler::popPendingPlayer( const RakNet::RakNetGUID& source ) +{ + if (!level) { + LOGE("Could not add player since Level is NULL!\n"); + return NULL; + } + + for (unsigned int i = 0; i < _pendingPlayers.size(); ++i) { + Player* p = _pendingPlayers[i]; + if (p->owner == source) { + _pendingPlayers.erase(_pendingPlayers.begin() + i); + return p; + } + } + return NULL; +} + +void ServerSideNetworkHandler::levelEvent( Player* source, int type, int x, int y, int z, int data ) +{ + LevelEventPacket packet(type, x, y, z, data); + redistributePacket(&packet, source? source->owner : rakPeer->GetMyGUID()); +} + +void ServerSideNetworkHandler::tileEvent( int x, int y, int z, int b0, int b1 ) +{ + TileEventPacket packet(x, y, z, b0, b1); + raknetInstance->send(packet); +} + +Player* ServerSideNetworkHandler::getPlayer( const RakNet::RakNetGUID& source ) { + for (unsigned int i = 0; i < level->players.size(); ++i) + if (source == level->players[i]->owner) return level->players[i]; + return NULL; +} diff --git a/src/network/ServerSideNetworkHandler.h b/src/network/ServerSideNetworkHandler.hpp similarity index 97% rename from src/network/ServerSideNetworkHandler.h rename to src/network/ServerSideNetworkHandler.hpp index c098e2f..c2f42ce 100755 --- a/src/network/ServerSideNetworkHandler.h +++ b/src/network/ServerSideNetworkHandler.hpp @@ -1,9 +1,9 @@ #pragma once -#include "NetEventCallback.h" -#include "../raknet/RakNetTypes.h" -#include "../world/level/LevelListener.h" +#include "NetEventCallback.hpp" +#include "raknet/RakNetTypes.h" +#include "world/level/LevelListener.hpp" #include class Minecraft; diff --git a/src/network/command/CommandServer.cpp b/src/network/command/CommandServer.cpp index baaf2a5..b741e69 100755 --- a/src/network/command/CommandServer.cpp +++ b/src/network/command/CommandServer.cpp @@ -1,8 +1,8 @@ -#include "CommandServer.h" -#include -#include "../../world/level/Level.h" -#include "../../world/entity/Entity.h" -#include "gamemode/CreatorMode.h" +#include "CommandServer.hpp" +#include +#include "world/level/Level.hpp" +#include "world/entity/Entity.hpp" +#include "gamemode/CreatorMode.hpp" #ifdef WIN32 #define SERR(x) (WSA ## x) @@ -12,12 +12,12 @@ #include #endif -#include "../RakNetInstance.h" -#include "../packet/ChatPacket.h" -#include "../packet/AdventureSettingsPacket.h" -#include -#include -#include "../RakNetInstance.h" +#include "network/RakNetInstance.hpp" +#include "network/packet/ChatPacket.hpp" +#include "network/packet/AdventureSettingsPacket.hpp" +#include +#include +#include "network/RakNetInstance.hpp" const std::string NullString; const std::string CommandServer::Ok("\n"); diff --git a/src/network/command/CommandServer.h b/src/network/command/CommandServer.hpp similarity index 95% rename from src/network/command/CommandServer.h rename to src/network/command/CommandServer.hpp index 78e0517..a5c6365 100755 --- a/src/network/command/CommandServer.h +++ b/src/network/command/CommandServer.hpp @@ -10,8 +10,8 @@ #include #endif -#include "../../world/PosTranslator.h" -#include "../../world/Pos.h" +#include "world/PosTranslator.hpp" +#include "world/Pos.hpp" class Minecraft; class Packet; diff --git a/src/network/packet/AddEntityPacket.h b/src/network/packet/AddEntityPacket.hpp similarity index 96% rename from src/network/packet/AddEntityPacket.h rename to src/network/packet/AddEntityPacket.hpp index 6ce436f..2cdf029 100755 --- a/src/network/packet/AddEntityPacket.h +++ b/src/network/packet/AddEntityPacket.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../Packet.h" -#include "../../world/entity/Entity.h" +#include "network/Packet.hpp" +#include "world/entity/Entity.hpp" class AddEntityPacket : public Packet { diff --git a/src/network/packet/AddItemEntityPacket.h b/src/network/packet/AddItemEntityPacket.hpp similarity index 92% rename from src/network/packet/AddItemEntityPacket.h rename to src/network/packet/AddItemEntityPacket.hpp index eb2a0b9..89bc4f7 100755 --- a/src/network/packet/AddItemEntityPacket.h +++ b/src/network/packet/AddItemEntityPacket.hpp @@ -2,10 +2,10 @@ //package net.minecraft.network.packet; -#include "../Packet.h" -#include "../../world/entity/item/ItemEntity.h" -#include "../../world/item/ItemInstance.h" -#include "../../util/Mth.h" +#include "network/Packet.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/item/ItemInstance.hpp" +#include "util/Mth.hpp" class AddItemEntityPacket: public Packet { public: diff --git a/src/network/packet/AddMobPacket.h b/src/network/packet/AddMobPacket.hpp similarity index 94% rename from src/network/packet/AddMobPacket.h rename to src/network/packet/AddMobPacket.hpp index ceb3157..d723702 100755 --- a/src/network/packet/AddMobPacket.h +++ b/src/network/packet/AddMobPacket.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../Packet.h" -#include "../../world/entity/Mob.h" -#include "../../util/RakDataIO.h" +#include "network/Packet.hpp" +#include "world/entity/Mob.hpp" +#include "util/RakDataIO.hpp" class AddMobPacket : public Packet { diff --git a/src/network/packet/AddPaintingPacket.h b/src/network/packet/AddPaintingPacket.hpp similarity index 94% rename from src/network/packet/AddPaintingPacket.h rename to src/network/packet/AddPaintingPacket.hpp index aaf9c9f..75ff0c0 100755 --- a/src/network/packet/AddPaintingPacket.h +++ b/src/network/packet/AddPaintingPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" -#include "../../world/entity/Painting.h" +#include "network/Packet.hpp" +#include "world/entity/Painting.hpp" class AddPaintingPacket : public Packet { public: AddPaintingPacket() : entityId(0), xTile(0), yTile(0), zTile(0), dir(-1) { diff --git a/src/network/packet/AddPlayerPacket.h b/src/network/packet/AddPlayerPacket.hpp similarity index 94% rename from src/network/packet/AddPlayerPacket.h rename to src/network/packet/AddPlayerPacket.hpp index 5d432ec..f23cf9e 100755 --- a/src/network/packet/AddPlayerPacket.h +++ b/src/network/packet/AddPlayerPacket.hpp @@ -1,8 +1,8 @@ #pragma once -#include "../Packet.h" -#include "../../world/entity/player/Player.h" -#include "../../world/entity/player/Inventory.h" +#include "network/Packet.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/player/Inventory.hpp" class AddPlayerPacket : public Packet { diff --git a/src/network/packet/AdventureSettingsPacket.h b/src/network/packet/AdventureSettingsPacket.hpp similarity index 96% rename from src/network/packet/AdventureSettingsPacket.h rename to src/network/packet/AdventureSettingsPacket.hpp index bf78b11..9ad909f 100755 --- a/src/network/packet/AdventureSettingsPacket.h +++ b/src/network/packet/AdventureSettingsPacket.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../Packet.h" -#include "../../world/level/Level.h" +#include "network/Packet.hpp" +#include "world/level/Level.hpp" class AdventureSettingsPacket: public Packet { diff --git a/src/network/packet/AnimatePacket.h b/src/network/packet/AnimatePacket.hpp similarity index 96% rename from src/network/packet/AnimatePacket.h rename to src/network/packet/AnimatePacket.hpp index 61f974f..b3537dc 100755 --- a/src/network/packet/AnimatePacket.h +++ b/src/network/packet/AnimatePacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class AnimatePacket: public Packet { diff --git a/src/network/packet/ChatPacket.h b/src/network/packet/ChatPacket.hpp similarity index 92% rename from src/network/packet/ChatPacket.h rename to src/network/packet/ChatPacket.hpp index 0e4b2a7..69c4a50 100755 --- a/src/network/packet/ChatPacket.h +++ b/src/network/packet/ChatPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" -#include "../..//world/entity/player/Player.h" +#include "network/Packet.hpp" +#include "world/entity/player/Player.hpp" class ChatPacket: public Packet { diff --git a/src/network/packet/ChunkDataPacket.h b/src/network/packet/ChunkDataPacket.hpp similarity index 95% rename from src/network/packet/ChunkDataPacket.h rename to src/network/packet/ChunkDataPacket.hpp index af4cdef..4751404 100755 --- a/src/network/packet/ChunkDataPacket.h +++ b/src/network/packet/ChunkDataPacket.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../Packet.h" -#include "../../world/level/chunk/LevelChunk.h" +#include "network/Packet.hpp" +#include "world/level/chunk/LevelChunk.hpp" class ChunkDataPacket : public Packet { diff --git a/src/network/packet/ContainerAckPacket.h b/src/network/packet/ContainerAckPacket.hpp similarity index 96% rename from src/network/packet/ContainerAckPacket.h rename to src/network/packet/ContainerAckPacket.hpp index 317ac8f..b1ca9b9 100755 --- a/src/network/packet/ContainerAckPacket.h +++ b/src/network/packet/ContainerAckPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class ContainerAckPacket: public Packet { diff --git a/src/network/packet/ContainerClosePacket.h b/src/network/packet/ContainerClosePacket.hpp similarity index 95% rename from src/network/packet/ContainerClosePacket.h rename to src/network/packet/ContainerClosePacket.hpp index 3a77f88..38c6f23 100755 --- a/src/network/packet/ContainerClosePacket.h +++ b/src/network/packet/ContainerClosePacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class ContainerClosePacket: public Packet { diff --git a/src/network/packet/ContainerOpenPacket.h b/src/network/packet/ContainerOpenPacket.hpp similarity index 97% rename from src/network/packet/ContainerOpenPacket.h rename to src/network/packet/ContainerOpenPacket.hpp index de1dc26..3729fe3 100755 --- a/src/network/packet/ContainerOpenPacket.h +++ b/src/network/packet/ContainerOpenPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class ContainerOpenPacket: public Packet { diff --git a/src/network/packet/ContainerSetContentPacket.h b/src/network/packet/ContainerSetContentPacket.hpp similarity index 97% rename from src/network/packet/ContainerSetContentPacket.h rename to src/network/packet/ContainerSetContentPacket.hpp index a5b3c78..123dbbf 100755 --- a/src/network/packet/ContainerSetContentPacket.h +++ b/src/network/packet/ContainerSetContentPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class ContainerSetContentPacket: public Packet { diff --git a/src/network/packet/ContainerSetDataPacket.h b/src/network/packet/ContainerSetDataPacket.hpp similarity index 96% rename from src/network/packet/ContainerSetDataPacket.h rename to src/network/packet/ContainerSetDataPacket.hpp index 1f7803a..238e929 100755 --- a/src/network/packet/ContainerSetDataPacket.h +++ b/src/network/packet/ContainerSetDataPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class ContainerSetDataPacket: public Packet { diff --git a/src/network/packet/ContainerSetSlotPacket.h b/src/network/packet/ContainerSetSlotPacket.hpp similarity index 96% rename from src/network/packet/ContainerSetSlotPacket.h rename to src/network/packet/ContainerSetSlotPacket.hpp index 419eccb..6125e96 100755 --- a/src/network/packet/ContainerSetSlotPacket.h +++ b/src/network/packet/ContainerSetSlotPacket.hpp @@ -2,8 +2,8 @@ //package net.minecraft.network.packet; -#include "../Packet.h" -#include "../../world/item/ItemInstance.h" +#include "network/Packet.hpp" +#include "world/item/ItemInstance.hpp" // Note: This can be seen as "ContainerWantSetSlotPacket" when sent from // client to server. Currently, the client handles side-effects relating diff --git a/src/network/packet/DropItemPacket.h b/src/network/packet/DropItemPacket.hpp similarity index 96% rename from src/network/packet/DropItemPacket.h rename to src/network/packet/DropItemPacket.hpp index 893c938..3a58a8f 100755 --- a/src/network/packet/DropItemPacket.h +++ b/src/network/packet/DropItemPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class DropItemPacket: public Packet { diff --git a/src/network/packet/EntityEventPacket.h b/src/network/packet/EntityEventPacket.hpp similarity index 96% rename from src/network/packet/EntityEventPacket.h rename to src/network/packet/EntityEventPacket.hpp index 97a9042..45a3763 100755 --- a/src/network/packet/EntityEventPacket.h +++ b/src/network/packet/EntityEventPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class EntityEventPacket: public Packet { public: diff --git a/src/network/packet/ExplodePacket.h b/src/network/packet/ExplodePacket.hpp similarity index 95% rename from src/network/packet/ExplodePacket.h rename to src/network/packet/ExplodePacket.hpp index 94c9427..683edb6 100755 --- a/src/network/packet/ExplodePacket.h +++ b/src/network/packet/ExplodePacket.hpp @@ -2,8 +2,8 @@ //package net.minecraft.network.packet; -#include "../Packet.h" -#include "../../world/level/Explosion.h" +#include "network/Packet.hpp" +#include "world/level/Explosion.hpp" class ExplodePacket: public Packet { diff --git a/src/network/packet/HurtArmorPacket.h b/src/network/packet/HurtArmorPacket.hpp similarity index 94% rename from src/network/packet/HurtArmorPacket.h rename to src/network/packet/HurtArmorPacket.hpp index 3ae1c67..5eb25d9 100755 --- a/src/network/packet/HurtArmorPacket.h +++ b/src/network/packet/HurtArmorPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class HurtArmorPacket: public Packet { diff --git a/src/network/packet/InteractPacket.h b/src/network/packet/InteractPacket.hpp similarity index 96% rename from src/network/packet/InteractPacket.h rename to src/network/packet/InteractPacket.hpp index bd73959..faa9ac2 100755 --- a/src/network/packet/InteractPacket.h +++ b/src/network/packet/InteractPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class InteractPacket : public Packet { diff --git a/src/network/packet/LevelEventPacket.h b/src/network/packet/LevelEventPacket.hpp similarity index 96% rename from src/network/packet/LevelEventPacket.h rename to src/network/packet/LevelEventPacket.hpp index e9516f7..5b8be31 100755 --- a/src/network/packet/LevelEventPacket.h +++ b/src/network/packet/LevelEventPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class LevelEventPacket: public Packet { public: diff --git a/src/network/packet/LoginPacket.h b/src/network/packet/LoginPacket.hpp similarity index 97% rename from src/network/packet/LoginPacket.h rename to src/network/packet/LoginPacket.hpp index 0f25bc5..500f5d7 100755 --- a/src/network/packet/LoginPacket.h +++ b/src/network/packet/LoginPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class LoginPacket : public Packet { diff --git a/src/network/packet/LoginStatusPacket.h b/src/network/packet/LoginStatusPacket.hpp similarity index 95% rename from src/network/packet/LoginStatusPacket.h rename to src/network/packet/LoginStatusPacket.hpp index 070b38c..fec5434 100755 --- a/src/network/packet/LoginStatusPacket.h +++ b/src/network/packet/LoginStatusPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" namespace LoginStatus { const int Success = 0; diff --git a/src/network/packet/MessagePacket.h b/src/network/packet/MessagePacket.hpp similarity index 94% rename from src/network/packet/MessagePacket.h rename to src/network/packet/MessagePacket.hpp index 7a4eeb4..36ce199 100755 --- a/src/network/packet/MessagePacket.h +++ b/src/network/packet/MessagePacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class MessagePacket : public Packet { diff --git a/src/network/packet/MoveEntityPacket.h b/src/network/packet/MoveEntityPacket.hpp similarity index 98% rename from src/network/packet/MoveEntityPacket.h rename to src/network/packet/MoveEntityPacket.hpp index 11cf706..cdd3af4 100755 --- a/src/network/packet/MoveEntityPacket.h +++ b/src/network/packet/MoveEntityPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class MoveEntityPacket: public Packet { diff --git a/src/network/packet/MovePlayerPacket.h b/src/network/packet/MovePlayerPacket.hpp similarity index 96% rename from src/network/packet/MovePlayerPacket.h rename to src/network/packet/MovePlayerPacket.hpp index 0252cbc..9b2597e 100755 --- a/src/network/packet/MovePlayerPacket.h +++ b/src/network/packet/MovePlayerPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class MovePlayerPacket : public Packet { diff --git a/src/network/packet/PacketInclude.h b/src/network/packet/PacketInclude.h deleted file mode 100755 index 0d67d42..0000000 --- a/src/network/packet/PacketInclude.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include "AddEntityPacket.h" -#include "AddItemEntityPacket.h" -#include "AddMobPacket.h" -#include "AddPaintingPacket.h" -#include "AddPlayerPacket.h" -#include "AnimatePacket.h" -#include "AdventureSettingsPacket.h" -#include "ChatPacket.h" -#include "ContainerAckPacket.h" -#include "ContainerOpenPacket.h" -#include "ContainerClosePacket.h" -#include "ContainerSetDataPacket.h" -#include "ContainerSetSlotPacket.h" -#include "ContainerSetContentPacket.h" -#include "ChunkDataPacket.h" -#include "DropItemPacket.h" -#include "EntityEventPacket.h" -#include "ExplodePacket.h" -#include "HurtArmorPacket.h" -#include "InteractPacket.h" -#include "LevelEventPacket.h" -#include "LoginPacket.h" -#include "LoginStatusPacket.h" -#include "MessagePacket.h" -#include "MoveEntityPacket.h" -#include "MovePlayerPacket.h" -#include "PlaceBlockPacket.h" -#include "PlayerActionPacket.h" -#include "PlayerEquipmentPacket.h" -#include "PlayerArmorEquipmentPacket.h" -#include "ReadyPacket.h" -#include "RemoveBlockPacket.h" -#include "RemoveEntityPacket.h" -#include "RemovePlayerPacket.h" -#include "RespawnPacket.h" -#include "RequestChunkPacket.h" -#include "SendInventoryPacket.h" -#include "SetEntityDataPacket.h" -#include "SetEntityMotionPacket.h" -#include "SetHealthPacket.h" -#include "SetSpawnPositionPacket.h" -#include "SetTimePacket.h" -#include "SignUpdatePacket.h" -#include "StartGamePacket.h" -#include "TakeItemEntityPacket.h" -//#include "TeleportEntityPacket.h" -#include "TileEventPacket.h" -#include "UpdateBlockPacket.h" -#include "UseItemPacket.h" - diff --git a/src/network/packet/PacketInclude.hpp b/src/network/packet/PacketInclude.hpp new file mode 100755 index 0000000..88957a1 --- /dev/null +++ b/src/network/packet/PacketInclude.hpp @@ -0,0 +1,52 @@ +#pragma once + +#include "AddEntityPacket.hpp" +#include "AddItemEntityPacket.hpp" +#include "AddMobPacket.hpp" +#include "AddPaintingPacket.hpp" +#include "AddPlayerPacket.hpp" +#include "AnimatePacket.hpp" +#include "AdventureSettingsPacket.hpp" +#include "ChatPacket.hpp" +#include "ContainerAckPacket.hpp" +#include "ContainerOpenPacket.hpp" +#include "ContainerClosePacket.hpp" +#include "ContainerSetDataPacket.hpp" +#include "ContainerSetSlotPacket.hpp" +#include "ContainerSetContentPacket.hpp" +#include "ChunkDataPacket.hpp" +#include "DropItemPacket.hpp" +#include "EntityEventPacket.hpp" +#include "ExplodePacket.hpp" +#include "HurtArmorPacket.hpp" +#include "InteractPacket.hpp" +#include "LevelEventPacket.hpp" +#include "LoginPacket.hpp" +#include "LoginStatusPacket.hpp" +#include "MessagePacket.hpp" +#include "MoveEntityPacket.hpp" +#include "MovePlayerPacket.hpp" +#include "PlaceBlockPacket.hpp" +#include "PlayerActionPacket.hpp" +#include "PlayerEquipmentPacket.hpp" +#include "PlayerArmorEquipmentPacket.hpp" +#include "ReadyPacket.hpp" +#include "RemoveBlockPacket.hpp" +#include "RemoveEntityPacket.hpp" +#include "RemovePlayerPacket.hpp" +#include "RespawnPacket.hpp" +#include "RequestChunkPacket.hpp" +#include "SendInventoryPacket.hpp" +#include "SetEntityDataPacket.hpp" +#include "SetEntityMotionPacket.hpp" +#include "SetHealthPacket.hpp" +#include "SetSpawnPositionPacket.hpp" +#include "SetTimePacket.hpp" +#include "SignUpdatePacket.hpp" +#include "StartGamePacket.hpp" +#include "TakeItemEntityPacket.hpp" +//#include "TeleportEntityPacket.hpp" +#include "TileEventPacket.hpp" +#include "UpdateBlockPacket.hpp" +#include "UseItemPacket.hpp" + diff --git a/src/network/packet/PlaceBlockPacket.h b/src/network/packet/PlaceBlockPacket.hpp similarity index 97% rename from src/network/packet/PlaceBlockPacket.h rename to src/network/packet/PlaceBlockPacket.hpp index 12da5d1..67d45cc 100755 --- a/src/network/packet/PlaceBlockPacket.h +++ b/src/network/packet/PlaceBlockPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class PlaceBlockPacket : public Packet { diff --git a/src/network/packet/PlayerActionPacket.h b/src/network/packet/PlayerActionPacket.hpp similarity index 97% rename from src/network/packet/PlayerActionPacket.h rename to src/network/packet/PlayerActionPacket.hpp index 6a78465..d4787a9 100755 --- a/src/network/packet/PlayerActionPacket.h +++ b/src/network/packet/PlayerActionPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class PlayerActionPacket : public Packet { diff --git a/src/network/packet/PlayerArmorEquipmentPacket.h b/src/network/packet/PlayerArmorEquipmentPacket.hpp similarity index 91% rename from src/network/packet/PlayerArmorEquipmentPacket.h rename to src/network/packet/PlayerArmorEquipmentPacket.hpp index bf1da27..af875b8 100755 --- a/src/network/packet/PlayerArmorEquipmentPacket.h +++ b/src/network/packet/PlayerArmorEquipmentPacket.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../Packet.h" -#include "../../world/entity/player/Player.h" -#include "../../world/item/ArmorItem.h" -#include "../../world/item/ItemInstance.h" +#include "network/Packet.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/ArmorItem.hpp" +#include "world/item/ItemInstance.hpp" // @note: A visual update only class PlayerArmorEquipmentPacket : public Packet diff --git a/src/network/packet/PlayerEquipmentPacket.h b/src/network/packet/PlayerEquipmentPacket.hpp similarity index 96% rename from src/network/packet/PlayerEquipmentPacket.h rename to src/network/packet/PlayerEquipmentPacket.hpp index 63cec5c..9d0db53 100755 --- a/src/network/packet/PlayerEquipmentPacket.h +++ b/src/network/packet/PlayerEquipmentPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class PlayerEquipmentPacket : public Packet { diff --git a/src/network/packet/ReadyPacket.h b/src/network/packet/ReadyPacket.hpp similarity index 95% rename from src/network/packet/ReadyPacket.h rename to src/network/packet/ReadyPacket.hpp index 4ae95c1..e17104f 100755 --- a/src/network/packet/ReadyPacket.h +++ b/src/network/packet/ReadyPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class ReadyPacket: public Packet { diff --git a/src/network/packet/RemoveBlockPacket.h b/src/network/packet/RemoveBlockPacket.hpp similarity index 92% rename from src/network/packet/RemoveBlockPacket.h rename to src/network/packet/RemoveBlockPacket.hpp index 8e24ef9..61476ed 100755 --- a/src/network/packet/RemoveBlockPacket.h +++ b/src/network/packet/RemoveBlockPacket.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../Packet.h" -#include "../../world/entity/player/Player.h" +#include "network/Packet.hpp" +#include "world/entity/player/Player.hpp" class RemoveBlockPacket : public Packet { diff --git a/src/network/packet/RemoveEntityPacket.h b/src/network/packet/RemoveEntityPacket.hpp similarity index 94% rename from src/network/packet/RemoveEntityPacket.h rename to src/network/packet/RemoveEntityPacket.hpp index 8ef072f..59d7272 100755 --- a/src/network/packet/RemoveEntityPacket.h +++ b/src/network/packet/RemoveEntityPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class RemoveEntityPacket : public Packet { diff --git a/src/network/packet/RemovePlayerPacket.h b/src/network/packet/RemovePlayerPacket.hpp similarity index 90% rename from src/network/packet/RemovePlayerPacket.h rename to src/network/packet/RemovePlayerPacket.hpp index 2bbe6d4..c8927d0 100755 --- a/src/network/packet/RemovePlayerPacket.h +++ b/src/network/packet/RemovePlayerPacket.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../Packet.h" -#include "../../world/entity/player/Player.h" +#include "network/Packet.hpp" +#include "world/entity/player/Player.hpp" class RemovePlayerPacket : public Packet { diff --git a/src/network/packet/RequestChunkPacket.h b/src/network/packet/RequestChunkPacket.hpp similarity index 95% rename from src/network/packet/RequestChunkPacket.h rename to src/network/packet/RequestChunkPacket.hpp index a8b63cf..f5ae6f3 100755 --- a/src/network/packet/RequestChunkPacket.h +++ b/src/network/packet/RequestChunkPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class RequestChunkPacket : public Packet { diff --git a/src/network/packet/RespawnPacket.h b/src/network/packet/RespawnPacket.hpp similarity index 96% rename from src/network/packet/RespawnPacket.h rename to src/network/packet/RespawnPacket.hpp index b5fa761..a93e066 100755 --- a/src/network/packet/RespawnPacket.h +++ b/src/network/packet/RespawnPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class RespawnPacket: public Packet { diff --git a/src/network/packet/SendInventoryPacket.h b/src/network/packet/SendInventoryPacket.hpp similarity index 98% rename from src/network/packet/SendInventoryPacket.h rename to src/network/packet/SendInventoryPacket.hpp index c56a3bb..5f15531 100755 --- a/src/network/packet/SendInventoryPacket.h +++ b/src/network/packet/SendInventoryPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class SendInventoryPacket: public Packet { diff --git a/src/network/packet/SetEntityDataPacket.h b/src/network/packet/SetEntityDataPacket.hpp similarity index 91% rename from src/network/packet/SetEntityDataPacket.h rename to src/network/packet/SetEntityDataPacket.hpp index 5e81c26..a32eb99 100755 --- a/src/network/packet/SetEntityDataPacket.h +++ b/src/network/packet/SetEntityDataPacket.hpp @@ -2,10 +2,10 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" -#include "../../world/entity/SynchedEntityData.h" -#include "../../util/RakDataIO.h" +#include "world/entity/SynchedEntityData.hpp" +#include "util/RakDataIO.hpp" class SetEntityDataPacket: public Packet { diff --git a/src/network/packet/SetEntityMotionPacket.h b/src/network/packet/SetEntityMotionPacket.hpp similarity index 95% rename from src/network/packet/SetEntityMotionPacket.h rename to src/network/packet/SetEntityMotionPacket.hpp index b93fbc1..39a927e 100755 --- a/src/network/packet/SetEntityMotionPacket.h +++ b/src/network/packet/SetEntityMotionPacket.hpp @@ -2,8 +2,8 @@ //package net.minecraft.network.packet; -#include "../Packet.h" -#include "../../world/entity/Entity.h" +#include "network/Packet.hpp" +#include "world/entity/Entity.hpp" class SetEntityMotionPacket: public Packet { diff --git a/src/network/packet/SetHealthPacket.h b/src/network/packet/SetHealthPacket.hpp similarity index 95% rename from src/network/packet/SetHealthPacket.h rename to src/network/packet/SetHealthPacket.hpp index 0912ed6..9491121 100755 --- a/src/network/packet/SetHealthPacket.h +++ b/src/network/packet/SetHealthPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" //package net.minecraft.network.packet; diff --git a/src/network/packet/SetSpawnPositionPacket.h b/src/network/packet/SetSpawnPositionPacket.hpp similarity index 96% rename from src/network/packet/SetSpawnPositionPacket.h rename to src/network/packet/SetSpawnPositionPacket.hpp index e38a17b..a796ba9 100755 --- a/src/network/packet/SetSpawnPositionPacket.h +++ b/src/network/packet/SetSpawnPositionPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class SetSpawnPositionPacket : public Packet { diff --git a/src/network/packet/SetTimePacket.h b/src/network/packet/SetTimePacket.hpp similarity index 95% rename from src/network/packet/SetTimePacket.h rename to src/network/packet/SetTimePacket.hpp index 600fe8d..77261fc 100755 --- a/src/network/packet/SetTimePacket.h +++ b/src/network/packet/SetTimePacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" #include class SetTimePacket: public Packet { diff --git a/src/network/packet/SignUpdatePacket.h b/src/network/packet/SignUpdatePacket.hpp similarity index 92% rename from src/network/packet/SignUpdatePacket.h rename to src/network/packet/SignUpdatePacket.hpp index 17b595b..805cde8 100755 --- a/src/network/packet/SignUpdatePacket.h +++ b/src/network/packet/SignUpdatePacket.hpp @@ -2,9 +2,9 @@ //package net.minecraft.network.packet; -#include "../Packet.h" -#include "../../util/RakDataIO.h" -#include "../../world/level/tile/entity/SignTileEntity.h" +#include "network/Packet.hpp" +#include "util/RakDataIO.hpp" +#include "world/level/tile/entity/SignTileEntity.hpp" class SignUpdatePacket: public Packet { diff --git a/src/network/packet/StartGamePacket.h b/src/network/packet/StartGamePacket.hpp similarity index 97% rename from src/network/packet/StartGamePacket.h rename to src/network/packet/StartGamePacket.hpp index 9e289a4..4384e72 100755 --- a/src/network/packet/StartGamePacket.h +++ b/src/network/packet/StartGamePacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" #include class StartGamePacket : public Packet diff --git a/src/network/packet/TakeItemEntityPacket.h b/src/network/packet/TakeItemEntityPacket.hpp similarity index 95% rename from src/network/packet/TakeItemEntityPacket.h rename to src/network/packet/TakeItemEntityPacket.hpp index 6ce128d..1194bb9 100755 --- a/src/network/packet/TakeItemEntityPacket.h +++ b/src/network/packet/TakeItemEntityPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class TakeItemEntityPacket: public Packet { diff --git a/src/network/packet/TeleportEntityPacket.h b/src/network/packet/TeleportEntityPacket.hpp similarity index 94% rename from src/network/packet/TeleportEntityPacket.h rename to src/network/packet/TeleportEntityPacket.hpp index ed127fc..0a45338 100755 --- a/src/network/packet/TeleportEntityPacket.h +++ b/src/network/packet/TeleportEntityPacket.hpp @@ -2,10 +2,10 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" -#include "../../world/entity/Entity.h" -#include "../../util/Mth.h" +#include "world/entity/Entity.hpp" +#include "util/Mth.hpp" class TeleportEntityPacket: public Packet { diff --git a/src/network/packet/TileEventPacket.h b/src/network/packet/TileEventPacket.hpp similarity index 96% rename from src/network/packet/TileEventPacket.h rename to src/network/packet/TileEventPacket.hpp index 9048ae4..a23dc3c 100755 --- a/src/network/packet/TileEventPacket.h +++ b/src/network/packet/TileEventPacket.hpp @@ -2,7 +2,7 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" class TileEventPacket: public Packet { public: diff --git a/src/network/packet/UpdateArmorPacket.h b/src/network/packet/UpdateArmorPacket.hpp similarity index 93% rename from src/network/packet/UpdateArmorPacket.h rename to src/network/packet/UpdateArmorPacket.hpp index 4276355..ef243af 100755 --- a/src/network/packet/UpdateArmorPacket.h +++ b/src/network/packet/UpdateArmorPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class UpdateArmorPacket: public Packet { diff --git a/src/network/packet/UpdateBlockPacket.h b/src/network/packet/UpdateBlockPacket.hpp similarity index 97% rename from src/network/packet/UpdateBlockPacket.h rename to src/network/packet/UpdateBlockPacket.hpp index 78e97f2..e4948c4 100755 --- a/src/network/packet/UpdateBlockPacket.h +++ b/src/network/packet/UpdateBlockPacket.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Packet.h" +#include "network/Packet.hpp" class UpdateBlockPacket : public Packet { diff --git a/src/network/packet/UseItemPacket.h b/src/network/packet/UseItemPacket.hpp similarity index 96% rename from src/network/packet/UseItemPacket.h rename to src/network/packet/UseItemPacket.hpp index e4f58a3..ee580f0 100755 --- a/src/network/packet/UseItemPacket.h +++ b/src/network/packet/UseItemPacket.hpp @@ -2,9 +2,9 @@ //package net.minecraft.network.packet; -#include "../Packet.h" +#include "network/Packet.hpp" -#include "../../world/item/ItemInstance.h" +#include "world/item/ItemInstance.hpp" class UseItemPacket: public Packet { diff --git a/src/platform/CThread.cpp b/src/platform/CThread.cpp index e136198..465327f 100755 --- a/src/platform/CThread.cpp +++ b/src/platform/CThread.cpp @@ -1,73 +1,73 @@ -/* - * CThread.cpp - * oxeye - * - * Created by aegzorz on 2007-02-09. - * Copyright 2007 Mojang AB. All rights reserved. - * - */ - -#include "CThread.h" - - - - CThread::CThread( pthread_fn threadFunc, void* threadParam ) - { - #ifdef WIN32 - mp_threadFunc = (LPTHREAD_START_ROUTINE) threadFunc; - - m_threadHandle = CreateThread( - NULL, // pointer to security attributes - NULL, // initial thread stack size - mp_threadFunc, // pointer to thread function - threadParam, // argument for new thread - NULL, // creation flags - &m_threadID // pointer to receive thread ID - ); - #endif - #if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__) - mp_threadFunc = (pthread_fn)threadFunc; - - pthread_attr_init(&m_attributes); - pthread_attr_setdetachstate( &m_attributes, PTHREAD_CREATE_DETACHED ); - /*int error =*/ pthread_create(&m_thread, &m_attributes, mp_threadFunc, threadParam); - #endif - #ifdef MACOSX - mp_threadFunc = (TaskProc) threadFunc; - - MPCreateTask( - mp_threadFunc, // pointer to thread function - threadParam, // argument for new thread - 0, // initial thread stack size - NULL, // queue id - NULL, // termination param 1 - NULL, // termination param 2 - 0, // task options - &m_threadID // pointer to receive task ID - ); - #endif - } - - void CThread::sleep( const unsigned int millis ) - { - #ifdef WIN32 - Sleep( millis ); - #endif - #if defined(LINUX) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) - usleep(millis * 1000); - #endif - } - - CThread::~CThread() - { - #ifdef WIN32 - TerminateThread(m_threadHandle, 0); - #endif - #if defined(LINUX) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) - // Thread was created detached; pthread_join on a detached thread is undefined - // and causes SIGABRT when the pthread_t is no longer valid. - pthread_attr_destroy(&m_attributes); - #endif - } - - +/* + * CThread.cpp + * oxeye + * + * Created by aegzorz on 2007-02-09. + * Copyright 2007 Mojang AB. All rights reserved. + * + */ + +#include "CThread.hpp" + + + + CThread::CThread( pthread_fn threadFunc, void* threadParam ) + { + #ifdef WIN32 + mp_threadFunc = (LPTHREAD_START_ROUTINE) threadFunc; + + m_threadHandle = CreateThread( + NULL, // pointer to security attributes + NULL, // initial thread stack size + mp_threadFunc, // pointer to thread function + threadParam, // argument for new thread + NULL, // creation flags + &m_threadID // pointer to receive thread ID + ); + #endif + #if defined(__linux__) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) || defined(__EMSCRIPTEN__) + mp_threadFunc = (pthread_fn)threadFunc; + + pthread_attr_init(&m_attributes); + pthread_attr_setdetachstate( &m_attributes, PTHREAD_CREATE_DETACHED ); + /*int error =*/ pthread_create(&m_thread, &m_attributes, mp_threadFunc, threadParam); + #endif + #ifdef MACOSX + mp_threadFunc = (TaskProc) threadFunc; + + MPCreateTask( + mp_threadFunc, // pointer to thread function + threadParam, // argument for new thread + 0, // initial thread stack size + NULL, // queue id + NULL, // termination param 1 + NULL, // termination param 2 + 0, // task options + &m_threadID // pointer to receive task ID + ); + #endif + } + + void CThread::sleep( const unsigned int millis ) + { + #ifdef WIN32 + Sleep( millis ); + #endif + #if defined(LINUX) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) + usleep(millis * 1000); + #endif + } + + CThread::~CThread() + { + #ifdef WIN32 + TerminateThread(m_threadHandle, 0); + #endif + #if defined(LINUX) || defined(ANDROID) || defined(__APPLE__) || defined(POSIX) + // Thread was created detached; pthread_join on a detached thread is undefined + // and causes SIGABRT when the pthread_t is no longer valid. + pthread_attr_destroy(&m_attributes); + #endif + } + + diff --git a/src/platform/CThread.h b/src/platform/CThread.hpp similarity index 100% rename from src/platform/CThread.h rename to src/platform/CThread.hpp diff --git a/src/platform/HttpClient.cpp b/src/platform/HttpClient.cpp index 9f58a41..4c28c28 100644 --- a/src/platform/HttpClient.cpp +++ b/src/platform/HttpClient.cpp @@ -1,5 +1,5 @@ -#include "HttpClient.h" -#include "log.h" +#include "HttpClient.hpp" +#include "log.hpp" #include #include diff --git a/src/platform/HttpClient.h b/src/platform/HttpClient.hpp similarity index 100% rename from src/platform/HttpClient.h rename to src/platform/HttpClient.hpp diff --git a/src/platform/PngLoader.cpp b/src/platform/PngLoader.cpp index bbe7bb3..2243a32 100644 --- a/src/platform/PngLoader.cpp +++ b/src/platform/PngLoader.cpp @@ -1,4 +1,4 @@ -#include "PngLoader.h" +#include "PngLoader.hpp" #include #include diff --git a/src/platform/PngLoader.h b/src/platform/PngLoader.hpp similarity index 82% rename from src/platform/PngLoader.h rename to src/platform/PngLoader.hpp index 8dd62c4..4a4ec03 100644 --- a/src/platform/PngLoader.h +++ b/src/platform/PngLoader.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../client/renderer/TextureData.h" +#include "client/renderer/TextureData.hpp" #include diff --git a/src/platform/android/AppPlatform_android.h b/src/platform/android/AppPlatform_android.hpp similarity index 99% rename from src/platform/android/AppPlatform_android.h rename to src/platform/android/AppPlatform_android.hpp index fd68f99..a840798 100755 --- a/src/platform/android/AppPlatform_android.h +++ b/src/platform/android/AppPlatform_android.hpp @@ -1,9 +1,9 @@ #pragma once -#include -#include "client/renderer/gles.h" -#include "platform/log.h" -#include "platform/time.h" +#include +#include "client/renderer/gles.hpp" +#include "platform/log.hpp" +#include "platform/time.hpp" #include #include #include diff --git a/src/platform/android/AppPlatform_android23.h b/src/platform/android/AppPlatform_android23.hpp similarity index 94% rename from src/platform/android/AppPlatform_android23.h rename to src/platform/android/AppPlatform_android23.hpp index 1e69bc7..55e885c 100755 --- a/src/platform/android/AppPlatform_android23.h +++ b/src/platform/android/AppPlatform_android23.hpp @@ -1,49 +1,49 @@ -#include "AppPlatform_android.h" -#include -#include - -class AppPlatform_android23 : public AppPlatform_android -{ - typedef AppPlatform_android super; -public: - AppPlatform_android23() - : _assetManager(NULL) - { - } - - // If we're using Android 2.3+, try reading assets from NDK at first. - // If that doesn't work, read through java/JNI as usual. - BinaryBlob readAssetFile(const std::string& filename) { - if (!_isInited) - return BinaryBlob(); - - if (_assetManager != NULL) { - AAsset* asset = AAssetManager_open(_assetManager, filename.c_str(), AASSET_MODE_BUFFER); - if (asset != NULL) { - const int len = AAsset_getLength(asset); - const void* buf = len > 0? AAsset_getBuffer(asset) : NULL; - - BinaryBlob blob; - if (buf != NULL) { - blob = BinaryBlob(new unsigned char[len], len); - memcpy(blob.data, buf, len); - } - AAsset_close(asset); - if (blob.data) - return blob; - } - } - return super::readAssetFile(filename); - } - - - // Another init method... added to read data from the activity, and setup constants - // @note: This is called after instance is set from the outside, BUT this - // will be rewritten later on anyway - void initWithActivity(struct ANativeActivity* activity) { - _assetManager = activity->assetManager; - } - -private: - AAssetManager* _assetManager; -}; +#include "AppPlatform_android.hpp" +#include +#include + +class AppPlatform_android23 : public AppPlatform_android +{ + typedef AppPlatform_android super; +public: + AppPlatform_android23() + : _assetManager(NULL) + { + } + + // If we're using Android 2.3+, try reading assets from NDK at first. + // If that doesn't work, read through java/JNI as usual. + BinaryBlob readAssetFile(const std::string& filename) { + if (!_isInited) + return BinaryBlob(); + + if (_assetManager != NULL) { + AAsset* asset = AAssetManager_open(_assetManager, filename.c_str(), AASSET_MODE_BUFFER); + if (asset != NULL) { + const int len = AAsset_getLength(asset); + const void* buf = len > 0? AAsset_getBuffer(asset) : NULL; + + BinaryBlob blob; + if (buf != NULL) { + blob = BinaryBlob(new unsigned char[len], len); + memcpy(blob.data, buf, len); + } + AAsset_close(asset); + if (blob.data) + return blob; + } + } + return super::readAssetFile(filename); + } + + + // Another init method... added to read data from the activity, and setup constants + // @note: This is called after instance is set from the outside, BUT this + // will be rewritten later on anyway + void initWithActivity(struct ANativeActivity* activity) { + _assetManager = activity->assetManager; + } + +private: + AAssetManager* _assetManager; +}; diff --git a/src/platform/audio/SoundSystem.h b/src/platform/audio/SoundSystem.hpp similarity index 93% rename from src/platform/audio/SoundSystem.h rename to src/platform/audio/SoundSystem.hpp index 845e299..c5afd29 100755 --- a/src/platform/audio/SoundSystem.h +++ b/src/platform/audio/SoundSystem.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../world/level/tile/Tile.h" +#include "world/level/tile/Tile.hpp" #include class SoundDesc; diff --git a/src/platform/audio/SoundSystemAL.cpp b/src/platform/audio/SoundSystemAL.cpp index 7ea7289..4bb71aa 100755 --- a/src/platform/audio/SoundSystemAL.cpp +++ b/src/platform/audio/SoundSystemAL.cpp @@ -1,257 +1,257 @@ -//#include "ios/OpenALSupport.h" -#include "SoundSystemAL.h" -#include "../../util/Mth.h" -#include "../../world/level/tile/Tile.h" -#include "../../world/phys/Vec3.h" -#include "../../client/sound/Sound.h" - -#include "../log.h" - -static const char* errIdString = 0; - -void checkError() { - - while (1) { - ALenum err = alGetError(); - if(err == AL_NO_ERROR) return; - - LOGI("### SoundSystemAL error: %d ####: %s\n", err, errIdString==0?"(none)":errIdString); - } -} - -//typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid *data, ALsizei size, ALsizei freq); -//ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) -//{ -// static alBufferDataStaticProcPtr proc = NULL; -// -// if (proc == NULL) { -// proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic"); -// } -// -// if (proc) -// proc(bid, format, data, size, freq); -// -// return; -//} -// -SoundSystemAL::SoundSystemAL() -: available(true), - context(0), - device(0), - _rotation(-9999.9f) -{ - _buffers.reserve(64); - init(); -} - -SoundSystemAL::~SoundSystemAL() -{ - alDeleteSources(MaxNumSources, _sources); - - for (int i = 0; i < (int)_buffers.size(); ++i) - if (_buffers[i].inited) alDeleteBuffers(1, &_buffers[i].bufferID); - - alcMakeContextCurrent(NULL); - alcDestroyContext(context); - - // Close the device - alcCloseDevice(device); -} - -void SoundSystemAL::init() -{ - device = alcOpenDevice(NULL); - if(device) { - context = alcCreateContext(device, NULL); - alcMakeContextCurrent(context); - - alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); - - alGenSources(MaxNumSources, _sources); - for(int index = 0; index < MaxNumSources; index++) { - ALuint sourceID = _sources[index]; - - alSourcef(sourceID, AL_REFERENCE_DISTANCE, 5.0f); - alSourcef(sourceID, AL_MAX_DISTANCE, 16.0f); - alSourcef(sourceID, AL_ROLLOFF_FACTOR, 6.0f); - } - - float listenerPos[] = {0, 0, 0}; - float listenerOri[] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; - float listenerVel[] = {0, 0, 0}; - alListenerfv(AL_POSITION, listenerPos); - alListenerfv(AL_ORIENTATION, listenerOri); - alListenerfv(AL_VELOCITY, listenerVel); - - errIdString = "Init audio"; - checkError(); - } -} - -void SoundSystemAL::enable(bool status) { - LOGI("Enabling? audio: %d (context %p)\n", status, context); - if (status) { - alcMakeContextCurrent(context); - errIdString = "Enable audio"; - } - else { - alcMakeContextCurrent(NULL); - errIdString = "Disable audio"; - } - - checkError(); -} - -void SoundSystemAL::destroy() {} - -void SoundSystemAL::setListenerPos( float x, float y, float z ) -{ - // Note: listener position is thought to be 0,0,0 now - - /* - if (_listenerPos.x != x || _listenerPos.y != y || _listenerPos.z != z) { - _listenerPos.set(x, y, z); - alListener3f(AL_POSITION, x, y, z); - - static int _n = 0; - if (++_n == 20) { - _n = 0; - LOGI("Setting position for listener: %f, %f, %f\n", _listenerPos.x, _listenerPos.y, _listenerPos.z); - } - } - */ -} - -void SoundSystemAL::setListenerAngle( float deg ) -{ - if (_rotation != deg) { - _rotation = deg; - - float rad = deg * Mth::DEGRAD; - - static ALfloat orientation[] = {0, 0, 0, 0, 1, 0}; - orientation[0] = -Mth::sin( rad ); - orientation[2] = Mth::cos( rad ); - alListenerfv(AL_ORIENTATION, orientation); - } -} - -void SoundSystemAL::playAt( const SoundDesc& sound, float x, float y, float z, float volume, float pitch ) -{ - if (pitch < 0.01f) pitch = 1; - - //LOGI("playing sound '%s' with volume/pitch: %f, %f @ %f, %f, %f\n", sound.name.c_str(), volume, pitch, x, y, z); - - ALuint bufferID; - if (!getBufferId(sound, &bufferID)) { - errIdString = "Get buffer (failed)"; - checkError(); - LOGE("getBufferId returned false!\n"); - return; - } - errIdString = "Get buffer"; - checkError(); - //LOGI("playing sound %d - '%s' with volume/pitch: %f, %f @ %f, %f, %f\n", bufferID, sound.name.c_str(), volume, pitch, x, y, z); - - int sourceIndex; - errIdString = "Get free index"; - if (!getFreeSourceIndex(&sourceIndex)) { - LOGI("No free sound sources left @ SoundSystemAL::playAt\n"); - return; - } - - ALuint sourceID = _sources[sourceIndex]; - checkError(); - - alSourcei(sourceID, AL_BUFFER, 0); - errIdString = "unbind"; - checkError(); - alSourcei(sourceID, AL_BUFFER, bufferID); - errIdString = "bind"; - checkError(); - - alSourcef(sourceID, AL_PITCH, pitch); - errIdString = "pitch"; - checkError(); - alSourcef(sourceID, AL_GAIN, volume); - errIdString = "gain"; - checkError(); - - alSourcei(sourceID, AL_LOOPING, AL_FALSE); - errIdString = "looping"; - checkError(); - alSource3f(sourceID, AL_POSITION, x, y, z); - errIdString = "position"; - checkError(); - - alSourcePlay(sourceID); - errIdString = "source play"; - - checkError(); -} - -/*static*/ -void SoundSystemAL::removeStoppedSounds() -{ -} - -bool SoundSystemAL::getFreeSourceIndex(int* sourceIndex) { - for (int i = 0; i < MaxNumSources; ++i) { - ALint state; - alGetSourcei(_sources[i], AL_SOURCE_STATE, &state); - if(state != AL_PLAYING) { - *sourceIndex = i; - return true; - } - } - return false; -} - -bool SoundSystemAL::getBufferId(const SoundDesc& sound, ALuint* buf) { - for (int i = 0; i < (int)_buffers.size(); ++i) { - // Points to the same data buffer -> sounds equal - if (_buffers[i].framePtr == sound.frames) { - //LOGI("Found %p for %s!\n", sound.frames, sound.name.c_str()); - *buf = _buffers[i].bufferID; - return true; - } - } - - if (!sound.isValid()) { - LOGE("Err: sound is invalid @ getBufferId! %s\n", sound.name.c_str()); - return false; - } - - ALuint bufferID; - alGenBuffers(1, &bufferID); - errIdString = "Gen buffer"; - checkError(); - - ALenum format = (sound.byteWidth==2) ? - (sound.channels==2? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16) - : (sound.channels==2? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8); - - alBufferData(bufferID, format, sound.frames, sound.size, sound.frameRate); - //LOGI("Creating %d (%p) from sound: '%s'\n", bufferID, sound.frames, sound.name.c_str()); - errIdString = "Buffer data"; - //LOGI("Creating buffer with data: %d (%d), %p, %d, %d\n", format, sound.byteWidth, sound.frames, sound.size, sound.frameRate); - checkError(); - - //LOGI("Sound ch: %d, fmt: %d, frames: %p, len: %f, fr: %d, sz: %d, numfr: %d\n", sound.channels, format, sound.frames, sound.length(), sound.frameRate, sound.size, sound.numFrames); - - - Buffer buffer; - buffer.inited = true; - buffer.framePtr = sound.frames; - buffer.bufferID = bufferID; - *buf = bufferID; - _buffers.push_back(buffer); - - // @huge @attn @note @fix: The original data is free'd - // On PLATFORM_DESKTOP the PCM data lives in static arrays (not heap), - // so calling delete[] on them causes a debug-heap __debugbreak crash. -#if !defined(PLATFORM_DESKTOP) - sound.destroy(); -#endif - return true; -} +//#include "ios/OpenALSupport.hpp" +#include "SoundSystemAL.hpp" +#include "util/Mth.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/phys/Vec3.hpp" +#include "client/sound/Sound.hpp" + +#include "platform/log.hpp" + +static const char* errIdString = 0; + +void checkError() { + + while (1) { + ALenum err = alGetError(); + if(err == AL_NO_ERROR) return; + + LOGI("### SoundSystemAL error: %d ####: %s\n", err, errIdString==0?"(none)":errIdString); + } +} + +//typedef ALvoid AL_APIENTRY (*alBufferDataStaticProcPtr) (const ALint bid, ALenum format, ALvoid *data, ALsizei size, ALsizei freq); +//ALvoid alBufferDataStaticProc(const ALint bid, ALenum format, ALvoid* data, ALsizei size, ALsizei freq) +//{ +// static alBufferDataStaticProcPtr proc = NULL; +// +// if (proc == NULL) { +// proc = (alBufferDataStaticProcPtr) alcGetProcAddress(NULL, (const ALCchar*) "alBufferDataStatic"); +// } +// +// if (proc) +// proc(bid, format, data, size, freq); +// +// return; +//} +// +SoundSystemAL::SoundSystemAL() +: available(true), + context(0), + device(0), + _rotation(-9999.9f) +{ + _buffers.reserve(64); + init(); +} + +SoundSystemAL::~SoundSystemAL() +{ + alDeleteSources(MaxNumSources, _sources); + + for (int i = 0; i < (int)_buffers.size(); ++i) + if (_buffers[i].inited) alDeleteBuffers(1, &_buffers[i].bufferID); + + alcMakeContextCurrent(NULL); + alcDestroyContext(context); + + // Close the device + alcCloseDevice(device); +} + +void SoundSystemAL::init() +{ + device = alcOpenDevice(NULL); + if(device) { + context = alcCreateContext(device, NULL); + alcMakeContextCurrent(context); + + alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED); + + alGenSources(MaxNumSources, _sources); + for(int index = 0; index < MaxNumSources; index++) { + ALuint sourceID = _sources[index]; + + alSourcef(sourceID, AL_REFERENCE_DISTANCE, 5.0f); + alSourcef(sourceID, AL_MAX_DISTANCE, 16.0f); + alSourcef(sourceID, AL_ROLLOFF_FACTOR, 6.0f); + } + + float listenerPos[] = {0, 0, 0}; + float listenerOri[] = {0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; + float listenerVel[] = {0, 0, 0}; + alListenerfv(AL_POSITION, listenerPos); + alListenerfv(AL_ORIENTATION, listenerOri); + alListenerfv(AL_VELOCITY, listenerVel); + + errIdString = "Init audio"; + checkError(); + } +} + +void SoundSystemAL::enable(bool status) { + LOGI("Enabling? audio: %d (context %p)\n", status, context); + if (status) { + alcMakeContextCurrent(context); + errIdString = "Enable audio"; + } + else { + alcMakeContextCurrent(NULL); + errIdString = "Disable audio"; + } + + checkError(); +} + +void SoundSystemAL::destroy() {} + +void SoundSystemAL::setListenerPos( float x, float y, float z ) +{ + // Note: listener position is thought to be 0,0,0 now + + /* + if (_listenerPos.x != x || _listenerPos.y != y || _listenerPos.z != z) { + _listenerPos.set(x, y, z); + alListener3f(AL_POSITION, x, y, z); + + static int _n = 0; + if (++_n == 20) { + _n = 0; + LOGI("Setting position for listener: %f, %f, %f\n", _listenerPos.x, _listenerPos.y, _listenerPos.z); + } + } + */ +} + +void SoundSystemAL::setListenerAngle( float deg ) +{ + if (_rotation != deg) { + _rotation = deg; + + float rad = deg * Mth::DEGRAD; + + static ALfloat orientation[] = {0, 0, 0, 0, 1, 0}; + orientation[0] = -Mth::sin( rad ); + orientation[2] = Mth::cos( rad ); + alListenerfv(AL_ORIENTATION, orientation); + } +} + +void SoundSystemAL::playAt( const SoundDesc& sound, float x, float y, float z, float volume, float pitch ) +{ + if (pitch < 0.01f) pitch = 1; + + //LOGI("playing sound '%s' with volume/pitch: %f, %f @ %f, %f, %f\n", sound.name.c_str(), volume, pitch, x, y, z); + + ALuint bufferID; + if (!getBufferId(sound, &bufferID)) { + errIdString = "Get buffer (failed)"; + checkError(); + LOGE("getBufferId returned false!\n"); + return; + } + errIdString = "Get buffer"; + checkError(); + //LOGI("playing sound %d - '%s' with volume/pitch: %f, %f @ %f, %f, %f\n", bufferID, sound.name.c_str(), volume, pitch, x, y, z); + + int sourceIndex; + errIdString = "Get free index"; + if (!getFreeSourceIndex(&sourceIndex)) { + LOGI("No free sound sources left @ SoundSystemAL::playAt\n"); + return; + } + + ALuint sourceID = _sources[sourceIndex]; + checkError(); + + alSourcei(sourceID, AL_BUFFER, 0); + errIdString = "unbind"; + checkError(); + alSourcei(sourceID, AL_BUFFER, bufferID); + errIdString = "bind"; + checkError(); + + alSourcef(sourceID, AL_PITCH, pitch); + errIdString = "pitch"; + checkError(); + alSourcef(sourceID, AL_GAIN, volume); + errIdString = "gain"; + checkError(); + + alSourcei(sourceID, AL_LOOPING, AL_FALSE); + errIdString = "looping"; + checkError(); + alSource3f(sourceID, AL_POSITION, x, y, z); + errIdString = "position"; + checkError(); + + alSourcePlay(sourceID); + errIdString = "source play"; + + checkError(); +} + +/*static*/ +void SoundSystemAL::removeStoppedSounds() +{ +} + +bool SoundSystemAL::getFreeSourceIndex(int* sourceIndex) { + for (int i = 0; i < MaxNumSources; ++i) { + ALint state; + alGetSourcei(_sources[i], AL_SOURCE_STATE, &state); + if(state != AL_PLAYING) { + *sourceIndex = i; + return true; + } + } + return false; +} + +bool SoundSystemAL::getBufferId(const SoundDesc& sound, ALuint* buf) { + for (int i = 0; i < (int)_buffers.size(); ++i) { + // Points to the same data buffer -> sounds equal + if (_buffers[i].framePtr == sound.frames) { + //LOGI("Found %p for %s!\n", sound.frames, sound.name.c_str()); + *buf = _buffers[i].bufferID; + return true; + } + } + + if (!sound.isValid()) { + LOGE("Err: sound is invalid @ getBufferId! %s\n", sound.name.c_str()); + return false; + } + + ALuint bufferID; + alGenBuffers(1, &bufferID); + errIdString = "Gen buffer"; + checkError(); + + ALenum format = (sound.byteWidth==2) ? + (sound.channels==2? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16) + : (sound.channels==2? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8); + + alBufferData(bufferID, format, sound.frames, sound.size, sound.frameRate); + //LOGI("Creating %d (%p) from sound: '%s'\n", bufferID, sound.frames, sound.name.c_str()); + errIdString = "Buffer data"; + //LOGI("Creating buffer with data: %d (%d), %p, %d, %d\n", format, sound.byteWidth, sound.frames, sound.size, sound.frameRate); + checkError(); + + //LOGI("Sound ch: %d, fmt: %d, frames: %p, len: %f, fr: %d, sz: %d, numfr: %d\n", sound.channels, format, sound.frames, sound.length(), sound.frameRate, sound.size, sound.numFrames); + + + Buffer buffer; + buffer.inited = true; + buffer.framePtr = sound.frames; + buffer.bufferID = bufferID; + *buf = bufferID; + _buffers.push_back(buffer); + + // @huge @attn @note @fix: The original data is free'd + // On PLATFORM_DESKTOP the PCM data lives in static arrays (not heap), + // so calling delete[] on them causes a debug-heap __debugbreak crash. +#if !defined(PLATFORM_DESKTOP) + sound.destroy(); +#endif + return true; +} diff --git a/src/platform/audio/SoundSystemAL.h b/src/platform/audio/SoundSystemAL.hpp similarity index 98% rename from src/platform/audio/SoundSystemAL.h rename to src/platform/audio/SoundSystemAL.hpp index 48d78f6..22f1695 100755 --- a/src/platform/audio/SoundSystemAL.h +++ b/src/platform/audio/SoundSystemAL.hpp @@ -1,6 +1,6 @@ #pragma once -#include "SoundSystem.h" +#include "SoundSystem.hpp" #include #include diff --git a/src/platform/audio/SoundSystemSL.cpp b/src/platform/audio/SoundSystemSL.cpp index 15b4d7c..ae52332 100755 --- a/src/platform/audio/SoundSystemSL.cpp +++ b/src/platform/audio/SoundSystemSL.cpp @@ -1,243 +1,243 @@ -#include "SoundSystemSL.h" -#include -#include -#include "../../util/Mth.h" -#include "../../world/level/tile/Tile.h" -#include "../../world/phys/Vec3.h" -#include "../../client/sound/Sound.h" - -#include "../log.h" - -// Only one engine can be created at once. You CAN (if you really want) -// start two games at once, then it will crash without objEngine being static. -/*static*/ SLObjectItf SoundSystemSL::objEngine = 0; - -typedef struct t_context { - SLObjectItf obj; - Mutex* mutex; -} t_context; - -Mutex SoundSystemSL::toRemoveMutex; -std::vector SoundSystemSL::toRemove; - -SoundSystemSL::SoundSystemSL() -: available(true), - listener(NULL), - numBuffersPlaying(0) -{ - init(); -} - -SoundSystemSL::~SoundSystemSL() -{ - toRemoveMutex.unlock(); - for (SoundList::iterator it = playingBuffers.begin(); it != playingBuffers.end(); ++it) - (**it)->Destroy(*it); - (*objOutput)->Destroy(objOutput); - - if (SoundSystemSL::objEngine != 0) { - (*SoundSystemSL::objEngine)->Destroy(SoundSystemSL::objEngine); - SoundSystemSL::objEngine = 0; - } -} - -void SoundSystemSL::init() -{ - SoundSystemSL::toRemove.clear(); - SoundSystemSL::toRemove.reserve(MAX_BUFFERS_PLAYING); - toRemoveCopy.resize(MAX_BUFFERS_PLAYING); - - SLresult res; - const int MAX_NUMBER_INTERFACES = 2; - SLboolean required[MAX_NUMBER_INTERFACES]; - SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; - - SLEngineOption EngineOption[] = {(SLuint32) - SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}; - - /* Create OpenSL ES (destroy first if needed)*/ - if (SoundSystemSL::objEngine != 0) - (*SoundSystemSL::objEngine)->Destroy(SoundSystemSL::objEngine); - - res = slCreateEngine( &SoundSystemSL::objEngine, 1, EngineOption, 0, NULL, NULL); - checkErr(res); - - /* Realizing the SL Engine in synchronous mode. */ - res = (*SoundSystemSL::objEngine)->Realize(SoundSystemSL::objEngine, SL_BOOLEAN_FALSE); - if (checkErr(res)) { - available = false; - return; - } - - (*SoundSystemSL::objEngine)->GetInterface(SoundSystemSL::objEngine, SL_IID_ENGINE, (void*)&engEngine); - checkErr(res); - - /* Create Output Mix object to be used by player - no interfaces - required */ - res = (*engEngine)->CreateOutputMix(engEngine, &objOutput, 0, iidArray, required); - checkErr(res); - - /* Realizing the Output Mix object in synchronous mode. */ - res = (*objOutput)->Realize(objOutput, SL_BOOLEAN_FALSE); - checkErr(res); -} - -void SoundSystemSL::destroy() {} - -void SoundSystemSL::setListenerPos( float x, float y, float z ) -{ - if (!listener) { - listenerPos = Vec3(x, y, z); - return; - } - - SLVec3D pos = {(SLint32)(1000.0f * x), (SLint32)(1000.0f * y), (SLint32)(1000.0f * z)}; - SLresult res = (*listener)->SetLocationCartesian(listener, &pos); - checkErr(res); -} - -void SoundSystemSL::setListenerAngle( float deg ) -{ - if (!listener) return; - - SLresult res = (*listener)->SetOrientationAngles(listener, deg*1000.0f, 0, 0); - checkErr(res); -} - -void SoundSystemSL::playAt( const SoundDesc& sound, float x, float y, float z, float volume, float pitch ) -{ - removeStoppedSounds(); - - if (numBuffersPlaying >= MAX_BUFFERS_PLAYING) - return; - - /* Setup the data source structure for the player */ - SLDataLocator_AndroidSimpleBufferQueue uri = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; - SLDataFormat_PCM mime = { - SL_DATAFORMAT_PCM, - (SLuint32)sound.channels, - (SLuint32)(sound.frameRate * 1000), - (SLuint32)(sound.byteWidth << 3), - (SLuint32)(sound.byteWidth << 3), - sound.channels==1? SL_SPEAKER_FRONT_CENTER : - SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, - SL_BYTEORDER_LITTLEENDIAN - }; - SLDataSource audioSource = {&uri, &mime}; - SLDataLocator_OutputMix locator_outputmix; - SLDataSink audioSink; - SLObjectItf player; - SLPlayItf playItf; - //SL3DLocationItf locationItf; - SLVolumeItf volumeItf; - - /* Setup the data sink structure */ - locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - locator_outputmix.outputMix = objOutput; - audioSink.pLocator = (void *)&locator_outputmix; - audioSink.pFormat = NULL; - - /* Buffer queue-able */ - static SLboolean required[2]; - static SLInterfaceID iidArray[2]; - required[0] = SL_BOOLEAN_TRUE; - iidArray[0] = SL_IID_BUFFERQUEUE; - required[1] = SL_BOOLEAN_TRUE; - iidArray[1] = SL_IID_VOLUME; - - /* Create the 3D player */ - SLresult res = (*engEngine)->CreateAudioPlayer(engEngine, &player, - &audioSource, &audioSink, 2, iidArray, required); - //printf("SL: Created audio player\n"); - checkErr(res); - - /* Realizing the player in synchronous mode. */ - res = (*player)->Realize(player, SL_BOOLEAN_FALSE); - //LOGI("SL: Realize audio player\n"); - checkErr(res); - - /* Get the play and volume interfaces */ - res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); - //LOGI("SL: Get Player interface\n"); - checkErr(res); - - res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volumeItf); - //LOGI("SL: Get Player interface\n"); - checkErr(res); - - SLmillibel maxVolume; - res = (*volumeItf)->GetMaxVolumeLevel(volumeItf, &maxVolume); - SLmillibel mbelVolume = maxVolume - 2000 * (1-volume);//Mth::lerp(SL_MILLIBEL_MIN, maxVolume, 0.95f + 0.05f*volume); - LOGI("min: %d, max: %d, current: %d (%f)\n", SL_MILLIBEL_MIN, maxVolume, mbelVolume, volume); - res = (*volumeItf)->SetVolumeLevel(volumeItf, mbelVolume); - checkErr(res); - - SLAndroidSimpleBufferQueueItf buffer1; - res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, &buffer1); - checkErr(res); - - //t_context* context = new t_context(); //{ player, &toRemoveMutex }; - //context->obj = player; - //context->mutex = &toRemoveMutex; - res = (*buffer1)->RegisterCallback(buffer1, SoundSystemSL::removePlayer, (void*)player); - checkErr(res); - - res = (*buffer1)->Enqueue(buffer1, sound.frames, sound.size); - checkErr(res); - - /* Start playing the 3D source */ - res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); - //LOGI("SL: Set play state\n"); - checkErr(res); - - playingBuffers.push_back(player); - ++numBuffersPlaying; -} - -bool SoundSystemSL::checkErr( SLresult res ) -{ - if ( res != SL_RESULT_SUCCESS ) { - LOGI("OpenSL error: %d\n", res); - return true; - } - return false; -} - -/*static*/ -void SoundSystemSL::removeStoppedSounds() -{ - toRemoveMutex.lock(); - const int numBuffersToRemove = toRemove.size(); - for (int i = 0; i < numBuffersToRemove; ++i) - toRemoveCopy[i] = toRemove[i]; - SoundSystemSL::toRemove.clear(); - toRemoveMutex.unlock(); - - for (int i = 0; i < numBuffersToRemove; ++i) { - SLObjectItf obj = toRemoveCopy[i]; - - SoundList::iterator it = playingBuffers.begin(); - while (it != playingBuffers.end()) { - if (*it == obj) { - playingBuffers.erase(it); - break; - } - ++it; - } - (*obj)->Destroy(obj); - --numBuffersPlaying; - } -} - -void SoundSystemSL::removePlayer( SLAndroidSimpleBufferQueueItf bq, void *context_ ) -{ - //t_context* context = (t_context*) context_; - //context->mutex->lock(); - //SoundSystemSL::toRemove.push_back( context->obj ); - //context->mutex->unlock(); - //delete context; - - SoundSystemSL::toRemoveMutex.lock(); - SoundSystemSL::toRemove.push_back( (SLObjectItf) context_ ); - SoundSystemSL::toRemoveMutex.unlock(); -} +#include "SoundSystemSL.hpp" +#include +#include +#include "util/Mth.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/phys/Vec3.hpp" +#include "client/sound/Sound.hpp" + +#include "platform/log.hpp" + +// Only one engine can be created at once. You CAN (if you really want) +// start two games at once, then it will crash without objEngine being static. +/*static*/ SLObjectItf SoundSystemSL::objEngine = 0; + +typedef struct t_context { + SLObjectItf obj; + Mutex* mutex; +} t_context; + +Mutex SoundSystemSL::toRemoveMutex; +std::vector SoundSystemSL::toRemove; + +SoundSystemSL::SoundSystemSL() +: available(true), + listener(NULL), + numBuffersPlaying(0) +{ + init(); +} + +SoundSystemSL::~SoundSystemSL() +{ + toRemoveMutex.unlock(); + for (SoundList::iterator it = playingBuffers.begin(); it != playingBuffers.end(); ++it) + (**it)->Destroy(*it); + (*objOutput)->Destroy(objOutput); + + if (SoundSystemSL::objEngine != 0) { + (*SoundSystemSL::objEngine)->Destroy(SoundSystemSL::objEngine); + SoundSystemSL::objEngine = 0; + } +} + +void SoundSystemSL::init() +{ + SoundSystemSL::toRemove.clear(); + SoundSystemSL::toRemove.reserve(MAX_BUFFERS_PLAYING); + toRemoveCopy.resize(MAX_BUFFERS_PLAYING); + + SLresult res; + const int MAX_NUMBER_INTERFACES = 2; + SLboolean required[MAX_NUMBER_INTERFACES]; + SLInterfaceID iidArray[MAX_NUMBER_INTERFACES]; + + SLEngineOption EngineOption[] = {(SLuint32) + SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE}; + + /* Create OpenSL ES (destroy first if needed)*/ + if (SoundSystemSL::objEngine != 0) + (*SoundSystemSL::objEngine)->Destroy(SoundSystemSL::objEngine); + + res = slCreateEngine( &SoundSystemSL::objEngine, 1, EngineOption, 0, NULL, NULL); + checkErr(res); + + /* Realizing the SL Engine in synchronous mode. */ + res = (*SoundSystemSL::objEngine)->Realize(SoundSystemSL::objEngine, SL_BOOLEAN_FALSE); + if (checkErr(res)) { + available = false; + return; + } + + (*SoundSystemSL::objEngine)->GetInterface(SoundSystemSL::objEngine, SL_IID_ENGINE, (void*)&engEngine); + checkErr(res); + + /* Create Output Mix object to be used by player - no interfaces + required */ + res = (*engEngine)->CreateOutputMix(engEngine, &objOutput, 0, iidArray, required); + checkErr(res); + + /* Realizing the Output Mix object in synchronous mode. */ + res = (*objOutput)->Realize(objOutput, SL_BOOLEAN_FALSE); + checkErr(res); +} + +void SoundSystemSL::destroy() {} + +void SoundSystemSL::setListenerPos( float x, float y, float z ) +{ + if (!listener) { + listenerPos = Vec3(x, y, z); + return; + } + + SLVec3D pos = {(SLint32)(1000.0f * x), (SLint32)(1000.0f * y), (SLint32)(1000.0f * z)}; + SLresult res = (*listener)->SetLocationCartesian(listener, &pos); + checkErr(res); +} + +void SoundSystemSL::setListenerAngle( float deg ) +{ + if (!listener) return; + + SLresult res = (*listener)->SetOrientationAngles(listener, deg*1000.0f, 0, 0); + checkErr(res); +} + +void SoundSystemSL::playAt( const SoundDesc& sound, float x, float y, float z, float volume, float pitch ) +{ + removeStoppedSounds(); + + if (numBuffersPlaying >= MAX_BUFFERS_PLAYING) + return; + + /* Setup the data source structure for the player */ + SLDataLocator_AndroidSimpleBufferQueue uri = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; + SLDataFormat_PCM mime = { + SL_DATAFORMAT_PCM, + (SLuint32)sound.channels, + (SLuint32)(sound.frameRate * 1000), + (SLuint32)(sound.byteWidth << 3), + (SLuint32)(sound.byteWidth << 3), + sound.channels==1? SL_SPEAKER_FRONT_CENTER : + SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT, + SL_BYTEORDER_LITTLEENDIAN + }; + SLDataSource audioSource = {&uri, &mime}; + SLDataLocator_OutputMix locator_outputmix; + SLDataSink audioSink; + SLObjectItf player; + SLPlayItf playItf; + //SL3DLocationItf locationItf; + SLVolumeItf volumeItf; + + /* Setup the data sink structure */ + locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; + locator_outputmix.outputMix = objOutput; + audioSink.pLocator = (void *)&locator_outputmix; + audioSink.pFormat = NULL; + + /* Buffer queue-able */ + static SLboolean required[2]; + static SLInterfaceID iidArray[2]; + required[0] = SL_BOOLEAN_TRUE; + iidArray[0] = SL_IID_BUFFERQUEUE; + required[1] = SL_BOOLEAN_TRUE; + iidArray[1] = SL_IID_VOLUME; + + /* Create the 3D player */ + SLresult res = (*engEngine)->CreateAudioPlayer(engEngine, &player, + &audioSource, &audioSink, 2, iidArray, required); + //printf("SL: Created audio player\n"); + checkErr(res); + + /* Realizing the player in synchronous mode. */ + res = (*player)->Realize(player, SL_BOOLEAN_FALSE); + //LOGI("SL: Realize audio player\n"); + checkErr(res); + + /* Get the play and volume interfaces */ + res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf); + //LOGI("SL: Get Player interface\n"); + checkErr(res); + + res = (*player)->GetInterface(player, SL_IID_VOLUME, (void*)&volumeItf); + //LOGI("SL: Get Player interface\n"); + checkErr(res); + + SLmillibel maxVolume; + res = (*volumeItf)->GetMaxVolumeLevel(volumeItf, &maxVolume); + SLmillibel mbelVolume = maxVolume - 2000 * (1-volume);//Mth::lerp(SL_MILLIBEL_MIN, maxVolume, 0.95f + 0.05f*volume); + LOGI("min: %d, max: %d, current: %d (%f)\n", SL_MILLIBEL_MIN, maxVolume, mbelVolume, volume); + res = (*volumeItf)->SetVolumeLevel(volumeItf, mbelVolume); + checkErr(res); + + SLAndroidSimpleBufferQueueItf buffer1; + res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE, &buffer1); + checkErr(res); + + //t_context* context = new t_context(); //{ player, &toRemoveMutex }; + //context->obj = player; + //context->mutex = &toRemoveMutex; + res = (*buffer1)->RegisterCallback(buffer1, SoundSystemSL::removePlayer, (void*)player); + checkErr(res); + + res = (*buffer1)->Enqueue(buffer1, sound.frames, sound.size); + checkErr(res); + + /* Start playing the 3D source */ + res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING ); + //LOGI("SL: Set play state\n"); + checkErr(res); + + playingBuffers.push_back(player); + ++numBuffersPlaying; +} + +bool SoundSystemSL::checkErr( SLresult res ) +{ + if ( res != SL_RESULT_SUCCESS ) { + LOGI("OpenSL error: %d\n", res); + return true; + } + return false; +} + +/*static*/ +void SoundSystemSL::removeStoppedSounds() +{ + toRemoveMutex.lock(); + const int numBuffersToRemove = toRemove.size(); + for (int i = 0; i < numBuffersToRemove; ++i) + toRemoveCopy[i] = toRemove[i]; + SoundSystemSL::toRemove.clear(); + toRemoveMutex.unlock(); + + for (int i = 0; i < numBuffersToRemove; ++i) { + SLObjectItf obj = toRemoveCopy[i]; + + SoundList::iterator it = playingBuffers.begin(); + while (it != playingBuffers.end()) { + if (*it == obj) { + playingBuffers.erase(it); + break; + } + ++it; + } + (*obj)->Destroy(obj); + --numBuffersPlaying; + } +} + +void SoundSystemSL::removePlayer( SLAndroidSimpleBufferQueueItf bq, void *context_ ) +{ + //t_context* context = (t_context*) context_; + //context->mutex->lock(); + //SoundSystemSL::toRemove.push_back( context->obj ); + //context->mutex->unlock(); + //delete context; + + SoundSystemSL::toRemoveMutex.lock(); + SoundSystemSL::toRemove.push_back( (SLObjectItf) context_ ); + SoundSystemSL::toRemoveMutex.unlock(); +} diff --git a/src/platform/audio/SoundSystemSL.h b/src/platform/audio/SoundSystemSL.hpp similarity index 98% rename from src/platform/audio/SoundSystemSL.h rename to src/platform/audio/SoundSystemSL.hpp index b7afacb..ec02cac 100755 --- a/src/platform/audio/SoundSystemSL.h +++ b/src/platform/audio/SoundSystemSL.hpp @@ -1,6 +1,6 @@ #pragma once -#include "SoundSystem.h" +#include "SoundSystem.hpp" #include #include diff --git a/src/platform/file.h b/src/platform/file.hpp similarity index 100% rename from src/platform/file.h rename to src/platform/file.hpp diff --git a/src/platform/glfw/PlatformGlfw.cpp b/src/platform/glfw/PlatformGlfw.cpp index 36a4f73..cc0b5be 100644 --- a/src/platform/glfw/PlatformGlfw.cpp +++ b/src/platform/glfw/PlatformGlfw.cpp @@ -1,235 +1,235 @@ -#include "PlatformGlfw.h" -#include -#include "platform/input/Keyboard.h" -#include "platform/input/Mouse.h" - -#include "platform/log.h" -#include -#include - -#include "platform/HttpClient.h" -#include "util/StringUtils.h" -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#endif - -#include "App.h" - - -bool PlatformGlfw::init() { - glfwSetErrorCallback(PlatformGlfw::error_callback); - - if (!glfwInit()) { - return false; - } - - glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); -#ifndef __EMSCRIPTEN__ - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); -#else - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); -#endif - - m_window = glfwCreateWindow(getScreenWidth(), getScreenHeight(), "Minecraft PE 0.6.1", NULL, NULL); - - if (m_window == nullptr) { - return false; - } - - glfwSetKeyCallback(m_window, key_callback); - glfwSetCharCallback(m_window, character_callback); - glfwSetCursorPosCallback(m_window, cursor_position_callback); - glfwSetMouseButtonCallback(m_window, mouse_button_callback); - glfwSetScrollCallback(m_window, scroll_callback); - glfwSetWindowSizeCallback(m_window, window_size_callback); - - glfwSetWindowUserPointer(m_window, this); - - glfwMakeContextCurrent(m_window); - -#ifndef __EMSCRIPTEN__ - gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); - glfwSwapInterval(0); -#endif -} - -void PlatformGlfw::finish() { - glfwDestroyWindow(m_window); - glfwTerminate(); -} - -int PlatformGlfw::transformKey(int glfwkey) { - if (glfwkey >= GLFW_KEY_F1 && glfwkey <= GLFW_KEY_F12) { - return glfwkey - 178; - } - - switch (glfwkey) { - case GLFW_KEY_ESCAPE: return Keyboard::KEY_ESCAPE; - case GLFW_KEY_TAB: return Keyboard::KEY_TAB; - case GLFW_KEY_BACKSPACE: return Keyboard::KEY_BACKSPACE; - case GLFW_KEY_LEFT_SHIFT: return Keyboard::KEY_LSHIFT; - case GLFW_KEY_ENTER: return Keyboard::KEY_RETURN; - case GLFW_KEY_LEFT_CONTROL: return Keyboard::KEY_LEFT_CTRL; - default: return glfwkey; - } -} - -void PlatformGlfw::cursor_position_callback(GLFWwindow* window, double xpos, double ypos) { - static double lastX = 0.0, lastY = 0.0; - static bool firstMouse = true; - - if (firstMouse) { - lastX = xpos; - lastY = ypos; - firstMouse = false; - } - - double deltaX = xpos - lastX; - double deltaY = ypos - lastY; - - lastX = xpos; - lastY = ypos; - - if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { - Mouse::feed(0, 0, xpos, ypos, deltaX, deltaY); - } else { - Mouse::feed( MouseAction::ACTION_MOVE, 0, xpos, ypos); - } - - // Multitouch::feed(0, 0, xpos, ypos, 0); -} - -void PlatformGlfw::mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { - if(action == GLFW_REPEAT) return; - - double xpos, ypos; - glfwGetCursorPos(window, &xpos, &ypos); - - if (button == GLFW_MOUSE_BUTTON_LEFT) { - Mouse::feed( MouseAction::ACTION_LEFT, action, xpos, ypos); - // Multitouch::feed(1, action, xpos, ypos, 0); - } - - if (button == GLFW_MOUSE_BUTTON_RIGHT) { - Mouse::feed( MouseAction::ACTION_RIGHT, action, xpos, ypos); - } -} - -void PlatformGlfw::character_callback(GLFWwindow* window, unsigned int codepoint) { - Keyboard::feedText(codepoint); -} - -void PlatformGlfw::scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { - double xpos, ypos; - glfwGetCursorPos(window, &xpos, &ypos); - - Mouse::feed(3, 0, xpos, ypos, 0, yoffset); -} - -void PlatformGlfw::error_callback(int error, const char* desc) { - LOGE("GLFW Error (%d): %s", error, desc); -} - -void PlatformGlfw::window_size_callback(GLFWwindow* window, int width, int height) { - PlatformGlfw* app = (PlatformGlfw*)glfwGetWindowUserPointer(window); - - app->windowSizeChanged = true; -} - - -float PlatformGlfw::getPixelsPerMillimeter() { - GLFWmonitor* monitor = glfwGetPrimaryMonitor(); - - int width_mm, height_mm; - glfwGetMonitorPhysicalSize(monitor, &width_mm, &height_mm); - - const GLFWvidmode* mode = glfwGetVideoMode(monitor); - - return (float)mode->width / (float)width_mm; -} - -TextureData PlatformGlfw::loadTexture(const std::string& filename_, bool textureFolder) { - // Support fetching PNG textures via HTTP/HTTPS (for skins, etc) - if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) { - std::vector body; - if (HttpClient::download(filename_, body) && !body.empty()) { - return loadTextureFromMemory(body.data(), body.size()); - } - return TextureData(); - } - - TextureData out; - - std::string filename = textureFolder? "data/images/" + filename_ - : filename_; - std::ifstream source(filename.c_str(), std::ios::binary); - - if (!source) { - LOGI("Couldn't find file: %s\n", filename.c_str()); - return out; - } - - std::vector fileData((std::istreambuf_iterator(source)), std::istreambuf_iterator()); - source.close(); - - if (fileData.empty()) { - LOGI("Couldn't read file: %s\n", filename.c_str()); - return out; - } - - return loadTextureFromMemory(fileData.data(), fileData.size()); -} - -std::string PlatformGlfw::getDateString(int s) { - time_t tm = s; - - char mbstr[100]; - std::strftime(mbstr, sizeof(mbstr), "%F %T", std::localtime(&tm)); - - return std::string(mbstr); -} - -void PlatformGlfw::hideCursor(bool hide) { - int isHide = hide ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN; - glfwSetInputMode(m_window, GLFW_CURSOR, isHide); -} - -void PlatformGlfw::openURL(const std::string& url) { -#ifdef _WIN32 - ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL); -#elif __linux__ - std::string command = "xdg-open " + url; - system(command.c_str()); -#elif __EMSCRIPTEN__ - emscripten_run_script(std::string("window.open('" + url + "', '_blank')").c_str()); -#endif -} - -void PlatformGlfw::swapBuffers() { - glfwSwapBuffers(m_window); - glfwPollEvents(); - - // @todo - // if(((MAIN_CLASS*)g_app)->options.getBooleanValue(OPTIONS_LIMIT_FRAMERATE)) { - // auto frameEnd = clock::now(); - // auto elapsed = std::chrono::duration_cast(frameEnd - frameStart); - // auto target = std::chrono::microseconds(33333); // ~30 fps - // if(elapsed < target) - // std::this_thread::sleep_for(target - elapsed); - // } -} - -void PlatformGlfw::setVSync(bool on) { - IPlatform::setVSync(on); - - glfwSwapInterval(on); +#include "PlatformGlfw.hpp" +#include +#include "platform/input/Keyboard.hpp" +#include "platform/input/Mouse.hpp" + +#include "platform/log.hpp" +#include +#include + +#include "platform/HttpClient.hpp" +#include "util/StringUtils.hpp" +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#include "App.hpp" + + +bool PlatformGlfw::init() { + glfwSetErrorCallback(PlatformGlfw::error_callback); + + if (!glfwInit()) { + return false; + } + + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_NATIVE_CONTEXT_API); +#ifndef __EMSCRIPTEN__ + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); +#else + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 1); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); +#endif + + m_window = glfwCreateWindow(getScreenWidth(), getScreenHeight(), "Minecraft PE 0.6.1", NULL, NULL); + + if (m_window == nullptr) { + return false; + } + + glfwSetKeyCallback(m_window, key_callback); + glfwSetCharCallback(m_window, character_callback); + glfwSetCursorPosCallback(m_window, cursor_position_callback); + glfwSetMouseButtonCallback(m_window, mouse_button_callback); + glfwSetScrollCallback(m_window, scroll_callback); + glfwSetWindowSizeCallback(m_window, window_size_callback); + + glfwSetWindowUserPointer(m_window, this); + + glfwMakeContextCurrent(m_window); + +#ifndef __EMSCRIPTEN__ + gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); + glfwSwapInterval(0); +#endif +} + +void PlatformGlfw::finish() { + glfwDestroyWindow(m_window); + glfwTerminate(); +} + +int PlatformGlfw::transformKey(int glfwkey) { + if (glfwkey >= GLFW_KEY_F1 && glfwkey <= GLFW_KEY_F12) { + return glfwkey - 178; + } + + switch (glfwkey) { + case GLFW_KEY_ESCAPE: return Keyboard::KEY_ESCAPE; + case GLFW_KEY_TAB: return Keyboard::KEY_TAB; + case GLFW_KEY_BACKSPACE: return Keyboard::KEY_BACKSPACE; + case GLFW_KEY_LEFT_SHIFT: return Keyboard::KEY_LSHIFT; + case GLFW_KEY_ENTER: return Keyboard::KEY_RETURN; + case GLFW_KEY_LEFT_CONTROL: return Keyboard::KEY_LEFT_CTRL; + default: return glfwkey; + } +} + +void PlatformGlfw::cursor_position_callback(GLFWwindow* window, double xpos, double ypos) { + static double lastX = 0.0, lastY = 0.0; + static bool firstMouse = true; + + if (firstMouse) { + lastX = xpos; + lastY = ypos; + firstMouse = false; + } + + double deltaX = xpos - lastX; + double deltaY = ypos - lastY; + + lastX = xpos; + lastY = ypos; + + if (glfwGetInputMode(window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) { + Mouse::feed(0, 0, xpos, ypos, deltaX, deltaY); + } else { + Mouse::feed( MouseAction::ACTION_MOVE, 0, xpos, ypos); + } + + // Multitouch::feed(0, 0, xpos, ypos, 0); +} + +void PlatformGlfw::mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { + if(action == GLFW_REPEAT) return; + + double xpos, ypos; + glfwGetCursorPos(window, &xpos, &ypos); + + if (button == GLFW_MOUSE_BUTTON_LEFT) { + Mouse::feed( MouseAction::ACTION_LEFT, action, xpos, ypos); + // Multitouch::feed(1, action, xpos, ypos, 0); + } + + if (button == GLFW_MOUSE_BUTTON_RIGHT) { + Mouse::feed( MouseAction::ACTION_RIGHT, action, xpos, ypos); + } +} + +void PlatformGlfw::character_callback(GLFWwindow* window, unsigned int codepoint) { + Keyboard::feedText(codepoint); +} + +void PlatformGlfw::scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { + double xpos, ypos; + glfwGetCursorPos(window, &xpos, &ypos); + + Mouse::feed(3, 0, xpos, ypos, 0, yoffset); +} + +void PlatformGlfw::error_callback(int error, const char* desc) { + LOGE("GLFW Error (%d): %s", error, desc); +} + +void PlatformGlfw::window_size_callback(GLFWwindow* window, int width, int height) { + PlatformGlfw* app = (PlatformGlfw*)glfwGetWindowUserPointer(window); + + app->windowSizeChanged = true; +} + + +float PlatformGlfw::getPixelsPerMillimeter() { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + + int width_mm, height_mm; + glfwGetMonitorPhysicalSize(monitor, &width_mm, &height_mm); + + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + + return (float)mode->width / (float)width_mm; +} + +TextureData PlatformGlfw::loadTexture(const std::string& filename_, bool textureFolder) { + // Support fetching PNG textures via HTTP/HTTPS (for skins, etc) + if (Util::startsWith(filename_, "http://") || Util::startsWith(filename_, "https://")) { + std::vector body; + if (HttpClient::download(filename_, body) && !body.empty()) { + return loadTextureFromMemory(body.data(), body.size()); + } + return TextureData(); + } + + TextureData out; + + std::string filename = textureFolder? "data/images/" + filename_ + : filename_; + std::ifstream source(filename.c_str(), std::ios::binary); + + if (!source) { + LOGI("Couldn't find file: %s\n", filename.c_str()); + return out; + } + + std::vector fileData((std::istreambuf_iterator(source)), std::istreambuf_iterator()); + source.close(); + + if (fileData.empty()) { + LOGI("Couldn't read file: %s\n", filename.c_str()); + return out; + } + + return loadTextureFromMemory(fileData.data(), fileData.size()); +} + +std::string PlatformGlfw::getDateString(int s) { + time_t tm = s; + + char mbstr[100]; + std::strftime(mbstr, sizeof(mbstr), "%F %T", std::localtime(&tm)); + + return std::string(mbstr); +} + +void PlatformGlfw::hideCursor(bool hide) { + int isHide = hide ? GLFW_CURSOR_NORMAL : GLFW_CURSOR_HIDDEN; + glfwSetInputMode(m_window, GLFW_CURSOR, isHide); +} + +void PlatformGlfw::openURL(const std::string& url) { +#ifdef _WIN32 + ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL); +#elif __linux__ + std::string command = "xdg-open " + url; + system(command.c_str()); +#elif __EMSCRIPTEN__ + emscripten_run_script(std::string("window.open('" + url + "', '_blank')").c_str()); +#endif +} + +void PlatformGlfw::swapBuffers() { + glfwSwapBuffers(m_window); + glfwPollEvents(); + + // @todo + // if(((MAIN_CLASS*)g_app)->options.getBooleanValue(OPTIONS_LIMIT_FRAMERATE)) { + // auto frameEnd = clock::now(); + // auto elapsed = std::chrono::duration_cast(frameEnd - frameStart); + // auto target = std::chrono::microseconds(33333); // ~30 fps + // if(elapsed < target) + // std::this_thread::sleep_for(target - elapsed); + // } +} + +void PlatformGlfw::setVSync(bool on) { + IPlatform::setVSync(on); + + glfwSwapInterval(on); } \ No newline at end of file diff --git a/src/platform/glfw/PlatformGlfw.h b/src/platform/glfw/PlatformGlfw.hpp similarity index 89% rename from src/platform/glfw/PlatformGlfw.h rename to src/platform/glfw/PlatformGlfw.hpp index 349a39b..ec94305 100755 --- a/src/platform/glfw/PlatformGlfw.h +++ b/src/platform/glfw/PlatformGlfw.hpp @@ -1,11 +1,11 @@ #pragma once -#include -#include "platform/log.h" -#include "platform/HttpClient.h" -#include "platform/PngLoader.h" -#include "client/renderer/gles.h" -#include "world/level/storage/FolderMethods.h" +#include +#include "platform/log.hpp" +#include "platform/HttpClient.hpp" +#include "platform/PngLoader.hpp" +#include "client/renderer/gles.hpp" +#include "world/level/storage/FolderMethods.hpp" #include #include diff --git a/src/platform/input/Controller.cpp b/src/platform/input/Controller.cpp index 71ccabb..21efdaa 100755 --- a/src/platform/input/Controller.cpp +++ b/src/platform/input/Controller.cpp @@ -1,75 +1,75 @@ -#include "Controller.h" - -static int _abs(int x) { return x>=0? x:-x; } -static float _abs(float x) { return x>=0? x:-x; } - -/*static*/ float Controller::stickValuesX[NUM_STICKS] = {0}; -/*static*/ float Controller::stickValuesY[NUM_STICKS] = {0}; -/*static*/ bool Controller::isTouchedValues[NUM_STICKS] = {0}; - -bool Controller::isTouched( int stickIndex ) -{ - if (!isValidStick(stickIndex)) return false; - - return isTouchedValues[stickIndex-1]; -} - -void Controller::feed( int stickIndex, int state, float dx, float dy ) -{ - if (!isValidStick(stickIndex)) return; - - if (NUM_STICKS == 2) - stickIndex = dx<0? 1 : 2; - - isTouchedValues[stickIndex-1] = (state != STATE_RELEASE); - - // @note: Since I don't know where to put the Xperia Play specific - // calculations, I put them here! (normally I would probably have - // some kind of (XperiaPlay)ControllerReader but it doesn't make much - // more sense as long as we cant figure out (in code) whether or not - // we actually use an Xperia -> hardcode it here (Note#2, we CAN figure - // figure this out, at least by JNI/java-call but we arent doing it) - static float offsets[3] = {0, 0.64f, -0.64f}; - dx = linearTransform(dx + offsets[stickIndex], 0, 2.78f, true); - - stickValuesX[stickIndex-1] = dx; - stickValuesY[stickIndex-1] = dy; -} - -float Controller::getX( int stickIndex ) -{ - if (!isValidStick(stickIndex)) return 0; - return stickValuesX[stickIndex-1]; -} - -float Controller::getY( int stickIndex ) -{ - if (!isValidStick(stickIndex)) return 0; - return stickValuesY[stickIndex-1]; -} - -float Controller::getTransformedX( int stickIndex, float deadZone, float scale/*=1.0f*/, bool limit1/*=false*/ ) -{ - if (!isValidStick(stickIndex)) return 0; - return linearTransform(stickValuesX[stickIndex-1], deadZone, scale, limit1); -} - -float Controller::getTransformedY( int stickIndex, float deadZone, float scale/*=1.0f*/, bool limit1/*=false*/ ) -{ - if (!isValidStick(stickIndex)) return 0; - return linearTransform(stickValuesY[stickIndex-1], deadZone, scale, limit1); -} - -float Controller::linearTransform( float value, float deadZone, float scale/*=1.0f*/, bool limit1/*=false*/ ) -{ - float deadSigned = value >= 0? deadZone : -deadZone; - if (_abs(deadSigned) >= _abs(value)) return 0; - float ret = (value - deadSigned) * scale; - if (limit1 && _abs(ret) > 1) ret = ret>0.0f? 1.0f : -1.0f; - return ret; -} - -/*static*/ -bool Controller::isValidStick(int stick) { - return stick > 0 && stick <= NUM_STICKS; -} +#include "Controller.hpp" + +static int _abs(int x) { return x>=0? x:-x; } +static float _abs(float x) { return x>=0? x:-x; } + +/*static*/ float Controller::stickValuesX[NUM_STICKS] = {0}; +/*static*/ float Controller::stickValuesY[NUM_STICKS] = {0}; +/*static*/ bool Controller::isTouchedValues[NUM_STICKS] = {0}; + +bool Controller::isTouched( int stickIndex ) +{ + if (!isValidStick(stickIndex)) return false; + + return isTouchedValues[stickIndex-1]; +} + +void Controller::feed( int stickIndex, int state, float dx, float dy ) +{ + if (!isValidStick(stickIndex)) return; + + if (NUM_STICKS == 2) + stickIndex = dx<0? 1 : 2; + + isTouchedValues[stickIndex-1] = (state != STATE_RELEASE); + + // @note: Since I don't know where to put the Xperia Play specific + // calculations, I put them here! (normally I would probably have + // some kind of (XperiaPlay)ControllerReader but it doesn't make much + // more sense as long as we cant figure out (in code) whether or not + // we actually use an Xperia -> hardcode it here (Note#2, we CAN figure + // figure this out, at least by JNI/java-call but we arent doing it) + static float offsets[3] = {0, 0.64f, -0.64f}; + dx = linearTransform(dx + offsets[stickIndex], 0, 2.78f, true); + + stickValuesX[stickIndex-1] = dx; + stickValuesY[stickIndex-1] = dy; +} + +float Controller::getX( int stickIndex ) +{ + if (!isValidStick(stickIndex)) return 0; + return stickValuesX[stickIndex-1]; +} + +float Controller::getY( int stickIndex ) +{ + if (!isValidStick(stickIndex)) return 0; + return stickValuesY[stickIndex-1]; +} + +float Controller::getTransformedX( int stickIndex, float deadZone, float scale/*=1.0f*/, bool limit1/*=false*/ ) +{ + if (!isValidStick(stickIndex)) return 0; + return linearTransform(stickValuesX[stickIndex-1], deadZone, scale, limit1); +} + +float Controller::getTransformedY( int stickIndex, float deadZone, float scale/*=1.0f*/, bool limit1/*=false*/ ) +{ + if (!isValidStick(stickIndex)) return 0; + return linearTransform(stickValuesY[stickIndex-1], deadZone, scale, limit1); +} + +float Controller::linearTransform( float value, float deadZone, float scale/*=1.0f*/, bool limit1/*=false*/ ) +{ + float deadSigned = value >= 0? deadZone : -deadZone; + if (_abs(deadSigned) >= _abs(value)) return 0; + float ret = (value - deadSigned) * scale; + if (limit1 && _abs(ret) > 1) ret = ret>0.0f? 1.0f : -1.0f; + return ret; +} + +/*static*/ +bool Controller::isValidStick(int stick) { + return stick > 0 && stick <= NUM_STICKS; +} diff --git a/src/platform/input/Controller.h b/src/platform/input/Controller.hpp similarity index 96% rename from src/platform/input/Controller.h rename to src/platform/input/Controller.hpp index 9fa13bc..4c4314e 100755 --- a/src/platform/input/Controller.h +++ b/src/platform/input/Controller.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../log.h" +#include "platform/log.hpp" class Controller { diff --git a/src/platform/input/Keyboard.cpp b/src/platform/input/Keyboard.cpp index 3f9f0df..6e6d5ba 100755 --- a/src/platform/input/Keyboard.cpp +++ b/src/platform/input/Keyboard.cpp @@ -1,59 +1,59 @@ -#include "Keyboard.h" - -int Keyboard::_states[256] = {0}; - -std::vector Keyboard::_inputs; -std::vector Keyboard::_inputText; - -int Keyboard::_index = -1; - -int Keyboard::_textIndex = -1; - -const char* Keyboard::getKeyName(int key) { - switch (key) { - case KEY_A: return "A"; - case KEY_B: return "B"; - case KEY_C: return "C"; - case KEY_D: return "D"; - case KEY_E: return "E"; - case KEY_F: return "F"; - case KEY_G: return "G"; - case KEY_H: return "H"; - case KEY_I: return "I"; - case KEY_J: return "J"; - case KEY_K: return "K"; - case KEY_L: return "L"; - case KEY_M: return "M"; - case KEY_N: return "N"; - case KEY_O: return "O"; - case KEY_P: return "P"; - case KEY_Q: return "Q"; - case KEY_R: return "R"; - case KEY_S: return "S"; - case KEY_T: return "T"; - case KEY_U: return "U"; - case KEY_V: return "V"; - case KEY_W: return "W"; - case KEY_X: return "X"; - case KEY_Y: return "Y"; - case KEY_Z: return "Z"; - case KEY_BACKSPACE: return "Backspace"; - case KEY_RETURN: return "Return"; - case KEY_F1: return "F1"; - case KEY_F2: return "F2"; - case KEY_F3: return "F3"; - case KEY_F4: return "F4"; - case KEY_F5: return "F5"; - case KEY_F6: return "F6"; - case KEY_F7: return "F7"; - case KEY_F8: return "F8"; - case KEY_F9: return "F9"; - case KEY_F10: return "F10"; - case KEY_F11: return "F11"; - case KEY_F12: return "F12"; - case KEY_ESCAPE: return "Esc"; - case KEY_SPACE: return "Space"; - case KEY_LSHIFT: return "Left Shift"; - default: return "Unknown"; - } +#include "Keyboard.hpp" + +int Keyboard::_states[256] = {0}; + +std::vector Keyboard::_inputs; +std::vector Keyboard::_inputText; + +int Keyboard::_index = -1; + +int Keyboard::_textIndex = -1; + +const char* Keyboard::getKeyName(int key) { + switch (key) { + case KEY_A: return "A"; + case KEY_B: return "B"; + case KEY_C: return "C"; + case KEY_D: return "D"; + case KEY_E: return "E"; + case KEY_F: return "F"; + case KEY_G: return "G"; + case KEY_H: return "H"; + case KEY_I: return "I"; + case KEY_J: return "J"; + case KEY_K: return "K"; + case KEY_L: return "L"; + case KEY_M: return "M"; + case KEY_N: return "N"; + case KEY_O: return "O"; + case KEY_P: return "P"; + case KEY_Q: return "Q"; + case KEY_R: return "R"; + case KEY_S: return "S"; + case KEY_T: return "T"; + case KEY_U: return "U"; + case KEY_V: return "V"; + case KEY_W: return "W"; + case KEY_X: return "X"; + case KEY_Y: return "Y"; + case KEY_Z: return "Z"; + case KEY_BACKSPACE: return "Backspace"; + case KEY_RETURN: return "Return"; + case KEY_F1: return "F1"; + case KEY_F2: return "F2"; + case KEY_F3: return "F3"; + case KEY_F4: return "F4"; + case KEY_F5: return "F5"; + case KEY_F6: return "F6"; + case KEY_F7: return "F7"; + case KEY_F8: return "F8"; + case KEY_F9: return "F9"; + case KEY_F10: return "F10"; + case KEY_F11: return "F11"; + case KEY_F12: return "F12"; + case KEY_ESCAPE: return "Esc"; + case KEY_SPACE: return "Space"; + case KEY_LSHIFT: return "Left Shift"; + default: return "Unknown"; + } } \ No newline at end of file diff --git a/src/platform/input/Keyboard.h b/src/platform/input/Keyboard.hpp similarity index 100% rename from src/platform/input/Keyboard.h rename to src/platform/input/Keyboard.hpp diff --git a/src/platform/input/Mouse.cpp b/src/platform/input/Mouse.cpp index 05d77ac..859835b 100755 --- a/src/platform/input/Mouse.cpp +++ b/src/platform/input/Mouse.cpp @@ -1,169 +1,169 @@ -#include "Mouse.h" - -// -// MouseAction -// -MouseAction::MouseAction(char actionButtonId, char buttonData, short x, short y, char pointerId) -{ - this->action = actionButtonId; - this->data = buttonData; - this->x = x; - this->y = y; - this->dx = this->dy = 0; - this->pointerId = pointerId; -} - -MouseAction::MouseAction(char actionButtonId, char buttonData, short x, short y, short dx, short dy, char pointerId) -{ - this->action = actionButtonId; - this->data = buttonData; - this->x = x; - this->y = y; - this->dx = dx; - this->dy = dy; - this->pointerId = pointerId; -} - -bool MouseAction::isButton() const -{ - return action == ACTION_LEFT || action == ACTION_RIGHT; -} - -// -// MouseDevice -// -MouseDevice::MouseDevice() -: _index(-1), - _x(0), _xOld(0), - _y(0), _yOld(0), - _dx(DELTA_NOTSET), _dy(DELTA_NOTSET), - _firstMovementType(0) -{ - for (int i = 0; i < MAX_NUM_BUTTONS; ++i) - _buttonStates[i] = 0; -} - -void MouseDevice::reset() { - _index = -1; - _inputs.clear(); - _buttonStates[MouseAction::ACTION_WHEEL] = 0; -} - -char MouseDevice::getButtonState(int buttonId) { - if (buttonId < MouseAction::ACTION_LEFT || buttonId > MouseAction::ACTION_WHEEL) - return 0; - return _buttonStates[buttonId]; -} - -bool MouseDevice::isButtonDown(int buttonId) { - return getButtonState(buttonId) != 0; -} - -/// Was the current movement the first movement after mouse down? -bool MouseDevice::wasFirstMovement() { - return _firstMovementType == 1; -} - -short MouseDevice::getX() { return _x; } -short MouseDevice::getY() { return _y; } - -short MouseDevice::getDX() { return (DELTA_NOTSET != _dx)? _dx : _x - _xOld; } -short MouseDevice::getDY() { return (DELTA_NOTSET != _dy)? _dy : _y - _yOld; } - -void MouseDevice::reset2() { - _xOld = _x; - _yOld = _y; - _dx = _dy = DELTA_NOTSET; -} - -bool MouseDevice::next() { - if (_index + 1 >= (int)_inputs.size()) - return false; - - ++_index; - return true; -} - -void MouseDevice::rewind() { - _index = -1; -} - -bool MouseDevice::getEventButtonState() { - return _inputs[_index].data == MouseAction::DATA_DOWN; -} - -char MouseDevice::getEventButton() { - return _inputs[_index].action; -} - -const MouseAction& MouseDevice::getEvent() { return _inputs[_index]; } - -void MouseDevice::feed(char actionButtonId, char buttonData, short x, short y) { - feed(actionButtonId, buttonData, x, y, 0, 0); -} - -void MouseDevice::feed(char actionButtonId, char buttonData, short x, short y, short dx, short dy) { - - _inputs.push_back(MouseAction(actionButtonId, buttonData, x, y, dx, dy, 0)); - - if (actionButtonId != MouseAction::ACTION_MOVE) { - _buttonStates[actionButtonId] = buttonData; - - if (actionButtonId == MouseAction::ACTION_LEFT) - _firstMovementType = -1; - } else { - if (_dx == DELTA_NOTSET) { - _dx = _dy = 0; - } - _dx += dx; - _dy += dy; - - if (_firstMovementType == -1) - _firstMovementType = 1; - else - _firstMovementType = 0; - } - - _xOld = _x; - _yOld = _y; - _x = x; - _y = y; -} - -// -// Mouse - static class wrapping a MouseDevice -// -void Mouse::reset() { _instance.reset(); } - -char Mouse::getButtonState(int buttonId) { return _instance.getButtonState(buttonId); } - -bool Mouse::isButtonDown(int buttonId) { return _instance.isButtonDown(buttonId); } - -short Mouse::getX() { return _instance.getX(); } -short Mouse::getY() { return _instance.getY(); } - -short Mouse::getDX() { return _instance.getDX(); } -short Mouse::getDY() { return _instance.getDY(); } - -void Mouse::reset2() { _instance.reset2(); } - -bool Mouse::next() { return _instance.next(); } -void Mouse::rewind() { _instance.rewind(); } - -bool Mouse::getEventButtonState() { return _instance.getEventButtonState(); } - -char Mouse::getEventButton() { return _instance.getEventButton(); } - -const MouseAction& Mouse::getEvent() { return _instance.getEvent(); } - -void Mouse::feed(char actionButtonId, char buttonData, short x, short y) { - feed(actionButtonId, buttonData, x, y, 0, 0); -} -void Mouse::feed(char actionButtonId, char buttonData, short x, short y, short dx, short dy) { - //LOGI("Mouse::feed: %d, %d, xy: %d, %d\n", actionButtonId, buttonData, x, y); - return _instance.feed(actionButtonId, buttonData, x, y, dx, dy); -} - - -MouseDevice Mouse::_instance; - +#include "Mouse.hpp" + +// +// MouseAction +// +MouseAction::MouseAction(char actionButtonId, char buttonData, short x, short y, char pointerId) +{ + this->action = actionButtonId; + this->data = buttonData; + this->x = x; + this->y = y; + this->dx = this->dy = 0; + this->pointerId = pointerId; +} + +MouseAction::MouseAction(char actionButtonId, char buttonData, short x, short y, short dx, short dy, char pointerId) +{ + this->action = actionButtonId; + this->data = buttonData; + this->x = x; + this->y = y; + this->dx = dx; + this->dy = dy; + this->pointerId = pointerId; +} + +bool MouseAction::isButton() const +{ + return action == ACTION_LEFT || action == ACTION_RIGHT; +} + +// +// MouseDevice +// +MouseDevice::MouseDevice() +: _index(-1), + _x(0), _xOld(0), + _y(0), _yOld(0), + _dx(DELTA_NOTSET), _dy(DELTA_NOTSET), + _firstMovementType(0) +{ + for (int i = 0; i < MAX_NUM_BUTTONS; ++i) + _buttonStates[i] = 0; +} + +void MouseDevice::reset() { + _index = -1; + _inputs.clear(); + _buttonStates[MouseAction::ACTION_WHEEL] = 0; +} + +char MouseDevice::getButtonState(int buttonId) { + if (buttonId < MouseAction::ACTION_LEFT || buttonId > MouseAction::ACTION_WHEEL) + return 0; + return _buttonStates[buttonId]; +} + +bool MouseDevice::isButtonDown(int buttonId) { + return getButtonState(buttonId) != 0; +} + +/// Was the current movement the first movement after mouse down? +bool MouseDevice::wasFirstMovement() { + return _firstMovementType == 1; +} + +short MouseDevice::getX() { return _x; } +short MouseDevice::getY() { return _y; } + +short MouseDevice::getDX() { return (DELTA_NOTSET != _dx)? _dx : _x - _xOld; } +short MouseDevice::getDY() { return (DELTA_NOTSET != _dy)? _dy : _y - _yOld; } + +void MouseDevice::reset2() { + _xOld = _x; + _yOld = _y; + _dx = _dy = DELTA_NOTSET; +} + +bool MouseDevice::next() { + if (_index + 1 >= (int)_inputs.size()) + return false; + + ++_index; + return true; +} + +void MouseDevice::rewind() { + _index = -1; +} + +bool MouseDevice::getEventButtonState() { + return _inputs[_index].data == MouseAction::DATA_DOWN; +} + +char MouseDevice::getEventButton() { + return _inputs[_index].action; +} + +const MouseAction& MouseDevice::getEvent() { return _inputs[_index]; } + +void MouseDevice::feed(char actionButtonId, char buttonData, short x, short y) { + feed(actionButtonId, buttonData, x, y, 0, 0); +} + +void MouseDevice::feed(char actionButtonId, char buttonData, short x, short y, short dx, short dy) { + + _inputs.push_back(MouseAction(actionButtonId, buttonData, x, y, dx, dy, 0)); + + if (actionButtonId != MouseAction::ACTION_MOVE) { + _buttonStates[actionButtonId] = buttonData; + + if (actionButtonId == MouseAction::ACTION_LEFT) + _firstMovementType = -1; + } else { + if (_dx == DELTA_NOTSET) { + _dx = _dy = 0; + } + _dx += dx; + _dy += dy; + + if (_firstMovementType == -1) + _firstMovementType = 1; + else + _firstMovementType = 0; + } + + _xOld = _x; + _yOld = _y; + _x = x; + _y = y; +} + +// +// Mouse - static class wrapping a MouseDevice +// +void Mouse::reset() { _instance.reset(); } + +char Mouse::getButtonState(int buttonId) { return _instance.getButtonState(buttonId); } + +bool Mouse::isButtonDown(int buttonId) { return _instance.isButtonDown(buttonId); } + +short Mouse::getX() { return _instance.getX(); } +short Mouse::getY() { return _instance.getY(); } + +short Mouse::getDX() { return _instance.getDX(); } +short Mouse::getDY() { return _instance.getDY(); } + +void Mouse::reset2() { _instance.reset2(); } + +bool Mouse::next() { return _instance.next(); } +void Mouse::rewind() { _instance.rewind(); } + +bool Mouse::getEventButtonState() { return _instance.getEventButtonState(); } + +char Mouse::getEventButton() { return _instance.getEventButton(); } + +const MouseAction& Mouse::getEvent() { return _instance.getEvent(); } + +void Mouse::feed(char actionButtonId, char buttonData, short x, short y) { + feed(actionButtonId, buttonData, x, y, 0, 0); +} +void Mouse::feed(char actionButtonId, char buttonData, short x, short y, short dx, short dy) { + //LOGI("Mouse::feed: %d, %d, xy: %d, %d\n", actionButtonId, buttonData, x, y); + return _instance.feed(actionButtonId, buttonData, x, y, dx, dy); +} + + +MouseDevice Mouse::_instance; + diff --git a/src/platform/input/Mouse.h b/src/platform/input/Mouse.hpp similarity index 98% rename from src/platform/input/Mouse.h rename to src/platform/input/Mouse.hpp index 096223e..6306630 100755 --- a/src/platform/input/Mouse.h +++ b/src/platform/input/Mouse.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "../log.h" +#include "platform/log.hpp" /** A mouse action such as a button press, release or mouse movement */ diff --git a/src/platform/input/Multitouch.cpp b/src/platform/input/Multitouch.cpp index 8974536..5be59e5 100755 --- a/src/platform/input/Multitouch.cpp +++ b/src/platform/input/Multitouch.cpp @@ -1,20 +1,20 @@ -#include "Multitouch.h" - -int - Multitouch::_index = -1, - Multitouch::_activePointerCount = 0, - Multitouch::_activePointerList[Multitouch::MAX_POINTERS] = {-1}, - Multitouch::_activePointerThisUpdateCount = 0, - Multitouch::_activePointerThisUpdateList[Multitouch::MAX_POINTERS] = {-1}; - -bool - Multitouch::_wasPressed[Multitouch::MAX_POINTERS] = {false}, - Multitouch::_wasReleased[Multitouch::MAX_POINTERS] = {false}, - Multitouch::_wasPressedThisUpdate[Multitouch::MAX_POINTERS] = {false}, - Multitouch::_wasReleasedThisUpdate[Multitouch::MAX_POINTERS] = {false}; - -TouchPointer - Multitouch::_pointers[Multitouch::MAX_POINTERS]; - -std::vector - Multitouch::_inputs; +#include "Multitouch.hpp" + +int + Multitouch::_index = -1, + Multitouch::_activePointerCount = 0, + Multitouch::_activePointerList[Multitouch::MAX_POINTERS] = {-1}, + Multitouch::_activePointerThisUpdateCount = 0, + Multitouch::_activePointerThisUpdateList[Multitouch::MAX_POINTERS] = {-1}; + +bool + Multitouch::_wasPressed[Multitouch::MAX_POINTERS] = {false}, + Multitouch::_wasReleased[Multitouch::MAX_POINTERS] = {false}, + Multitouch::_wasPressedThisUpdate[Multitouch::MAX_POINTERS] = {false}, + Multitouch::_wasReleasedThisUpdate[Multitouch::MAX_POINTERS] = {false}; + +TouchPointer + Multitouch::_pointers[Multitouch::MAX_POINTERS]; + +std::vector + Multitouch::_inputs; diff --git a/src/platform/input/Multitouch.h b/src/platform/input/Multitouch.hpp similarity index 98% rename from src/platform/input/Multitouch.h rename to src/platform/input/Multitouch.hpp index ba122ee..18f9b7b 100755 --- a/src/platform/input/Multitouch.h +++ b/src/platform/input/Multitouch.hpp @@ -1,7 +1,7 @@ #pragma once -#include "Mouse.h" -#include "../log.h" +#include "Mouse.hpp" +#include "platform/log.hpp" typedef MouseDevice TouchPointer; diff --git a/src/platform/ios/AppPlatform_iOS.h b/src/platform/ios/AppPlatform_iOS.hpp similarity index 96% rename from src/platform/ios/AppPlatform_iOS.h rename to src/platform/ios/AppPlatform_iOS.hpp index 52e3ac1..0d089dd 100755 --- a/src/platform/ios/AppPlatform_iOS.h +++ b/src/platform/ios/AppPlatform_iOS.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include "client/renderer/gles.h" -#include "platform/log.h" +#include "client/renderer/gles.hpp" +#include "platform/log.hpp" #include #include #include diff --git a/src/platform/log.h b/src/platform/log.hpp similarity index 100% rename from src/platform/log.h rename to src/platform/log.hpp diff --git a/src/platform/server/PlatformServer.cpp b/src/platform/server/PlatformServer.cpp index 56f6885..f75b5b9 100644 --- a/src/platform/server/PlatformServer.cpp +++ b/src/platform/server/PlatformServer.cpp @@ -1,23 +1,23 @@ -#include "PlatformServer.h" - -#include - -#include "App.h" -#include "platform/time.h" - -void PlatformServer::runMainLoop(App& app) { - while (!app.wantToQuit()) { - app.update(); - - sleepMs(20); - } -} - -std::string PlatformServer::getDateString(int s) { - time_t tm = s; - - char mbstr[100]; - std::strftime(mbstr, sizeof(mbstr), "%F %T", std::localtime(&tm)); - - return std::string(mbstr); +#include "PlatformServer.hpp" + +#include + +#include "App.hpp" +#include "platform/time.hpp" + +void PlatformServer::runMainLoop(App& app) { + while (!app.wantToQuit()) { + app.update(); + + sleepMs(20); + } +} + +std::string PlatformServer::getDateString(int s) { + time_t tm = s; + + char mbstr[100]; + std::strftime(mbstr, sizeof(mbstr), "%F %T", std::localtime(&tm)); + + return std::string(mbstr); } \ No newline at end of file diff --git a/src/platform/server/PlatformServer.h b/src/platform/server/PlatformServer.hpp similarity index 91% rename from src/platform/server/PlatformServer.h rename to src/platform/server/PlatformServer.hpp index 97606d4..c72f5f2 100755 --- a/src/platform/server/PlatformServer.h +++ b/src/platform/server/PlatformServer.hpp @@ -1,5 +1,5 @@ #pragma once -#include +#include class PlatformServer : public IPlatform { public: diff --git a/src/platform/time.cpp b/src/platform/time.cpp index 4bfb48d..3e116c7 100755 --- a/src/platform/time.cpp +++ b/src/platform/time.cpp @@ -1,224 +1,224 @@ -#include "time.h" -#include - -#ifdef WIN32 - #include -#else - #include - #include -#endif - -// Ugly ass temporary solution; -// since gettimeofday() returns seconds & microseconds since -// Epoch(1970) rather than since computer started, getTimeMs() -// would overflow if just using an int -> subtract the number -// of seconds that had passed when starting the app before -// doing any calculations. -#ifdef WIN32 - static long long getStartTime() { - LARGE_INTEGER ts; - QueryPerformanceCounter(&ts); - return ts.QuadPart; - } - static unsigned long long _t_start = getStartTime(); - -#else - static int getStartTime() { - timeval now; - gettimeofday(&now, 0); - return now.tv_sec; - } - static unsigned int _t_start = getStartTime(); -#endif - -#include - -/// Returns a platform dependent time in seconds -/// This is allowed to be here, since getTimeS and getTimeMs both have t(0) -/// as base (and obviously not good for an initial random seed) -int getRawTimeS() { -#ifdef WIN32 - return (int)(GetTickCount() / 1000); -#else - timeval now; - gettimeofday(&now, 0); - return (int)now.tv_sec; -#endif -} - -float getTimeS() { -#ifdef WIN32 - // If the game seems to go with different speeds, this might most - // possibly be the cause. QueryPerformanceCounter has indeed high - // resolution, but (imho) only guaranteed to be correct for (short) - // deltas between consecutive calls - LARGE_INTEGER freq, ts; - QueryPerformanceFrequency(&freq); - QueryPerformanceCounter(&ts); - return (ts.QuadPart - _t_start) / (float)freq.QuadPart; -#else - timeval now; - gettimeofday(&now, 0); - return (float)(now.tv_sec - _t_start) + now.tv_usec / 1000000.0f; -#endif -} - -int getTimeMs() { - return (int)(getTimeS() * 1000.0f); -} - -void sleepMs(int ms) { -#ifdef WIN32 - Sleep(ms); -#else - usleep(ms * 1000); -#endif -} - -#include -int getEpochTimeS() { - return (int)std::time (NULL); -} - - -StopwatchNLast::StopwatchNLast( int numMeasurements ) -: n(numMeasurements), - k(0), - sum(0) -{ - t = new float[n]; - memset(t, 0, n * sizeof(float)); -} - -StopwatchNLast::~StopwatchNLast() { - delete[] t; -} - -float StopwatchNLast::stop() { - float total = Stopwatch::stop(); - float curr = Stopwatch::getLast(); - - float toDelete = t[k]; - if (++k == n) k = 0; - t[k] = curr; - - sum += (curr - toDelete); - - return total; -} - -void StopwatchNLast::print( const std::string& prepend /*= ""*/ ) { - LOGI("%s\tTime (AVGms for the last %d runs): %f (Max: %f)\n", - prepend.c_str(), n, (1000.0f*sum/n), 1000.0f * getMax()); -} - - -// -// Stopwatch -// -Stopwatch::Stopwatch() -: _count(0), - _printcounter(0) -{ - reset(); -} - -void Stopwatch::start() { - _st = getTimeS(); -} - -float Stopwatch::stop() { - if (_st == -1) return 0; - _last = getTimeS() - _st; - if (_last > _max) _max = _last; - _tt += _last; - _st = -1; - ++_count; - return _tt; -} - -float Stopwatch::stopContinue() { - if (_st == -1) return 0; - const float now = getTimeS(); - _last = now - _st; - if (_last > _max) _max = _last; - _tt += _last; - _st = now; - ++_count; - return _tt; -} - -float Stopwatch::getLast() { - return _last; -} - -float Stopwatch::getTotal() { - return _tt; -} - -float Stopwatch::getMax() { - return _max; -} - -int Stopwatch::getCount() { - return _count; -} - -void Stopwatch::reset() { - _st = -1; - _tt = 0; - _max = 0; -} - -void Stopwatch::printEvery( int n, const std::string& prepend /*= ""*/ ) { - if (++_printcounter >= n) { - _printcounter = 0; - print(prepend); - } -} - -void Stopwatch::print( const std::string& prepend /*= ""*/ ) { - if (!_count) return; - LOGI("%s\tTime (AVGms/LTs(MAXs)/TTs, C) : %.3f/%.6f(%.6f)/%.4f, %d\n", - prepend.c_str(), (1000.0f*_tt/_count), _last, _max, _tt, _count); -} - -// -// StopwatchHandler - a collection of StopWatch:es -// -Stopwatch& StopwatchHandler::get( const std::string& s ) { - Map::iterator it = _map.find(s); - if (it != _map.end()) - return *it->second; - - Stopwatch* watch = new Stopwatch; - _map.insert(make_pair(s, watch)); - return *watch; -} - -void StopwatchHandler::clear( const std::string& s ) { - Map::iterator it = _map.find(s); - if (it != _map.end()) { - delete it->second; - } - _map.erase(s); -} - -void StopwatchHandler::clearAll() { - for (Map::iterator it = _map.begin(); it != _map.end(); ++it) - delete it->second; - _map.clear(); -} - -void StopwatchHandler::print() { - for (Map::iterator it = _map.begin(); it != _map.end(); ++it) { - it->second->print(it->first.c_str()); - } -} - -void StopwatchHandler::printEvery( int n ) { - if (++_printcounter >= n) { - _printcounter = 0; - print(); - } -} +#include "time.hpp" +#include + +#ifdef WIN32 + #include +#else + #include + #include +#endif + +// Ugly ass temporary solution; +// since gettimeofday() returns seconds & microseconds since +// Epoch(1970) rather than since computer started, getTimeMs() +// would overflow if just using an int -> subtract the number +// of seconds that had passed when starting the app before +// doing any calculations. +#ifdef WIN32 + static long long getStartTime() { + LARGE_INTEGER ts; + QueryPerformanceCounter(&ts); + return ts.QuadPart; + } + static unsigned long long _t_start = getStartTime(); + +#else + static int getStartTime() { + timeval now; + gettimeofday(&now, 0); + return now.tv_sec; + } + static unsigned int _t_start = getStartTime(); +#endif + +#include + +/// Returns a platform dependent time in seconds +/// This is allowed to be here, since getTimeS and getTimeMs both have t(0) +/// as base (and obviously not good for an initial random seed) +int getRawTimeS() { +#ifdef WIN32 + return (int)(GetTickCount() / 1000); +#else + timeval now; + gettimeofday(&now, 0); + return (int)now.tv_sec; +#endif +} + +float getTimeS() { +#ifdef WIN32 + // If the game seems to go with different speeds, this might most + // possibly be the cause. QueryPerformanceCounter has indeed high + // resolution, but (imho) only guaranteed to be correct for (short) + // deltas between consecutive calls + LARGE_INTEGER freq, ts; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&ts); + return (ts.QuadPart - _t_start) / (float)freq.QuadPart; +#else + timeval now; + gettimeofday(&now, 0); + return (float)(now.tv_sec - _t_start) + now.tv_usec / 1000000.0f; +#endif +} + +int getTimeMs() { + return (int)(getTimeS() * 1000.0f); +} + +void sleepMs(int ms) { +#ifdef WIN32 + Sleep(ms); +#else + usleep(ms * 1000); +#endif +} + +#include +int getEpochTimeS() { + return (int)std::time (NULL); +} + + +StopwatchNLast::StopwatchNLast( int numMeasurements ) +: n(numMeasurements), + k(0), + sum(0) +{ + t = new float[n]; + memset(t, 0, n * sizeof(float)); +} + +StopwatchNLast::~StopwatchNLast() { + delete[] t; +} + +float StopwatchNLast::stop() { + float total = Stopwatch::stop(); + float curr = Stopwatch::getLast(); + + float toDelete = t[k]; + if (++k == n) k = 0; + t[k] = curr; + + sum += (curr - toDelete); + + return total; +} + +void StopwatchNLast::print( const std::string& prepend /*= ""*/ ) { + LOGI("%s\tTime (AVGms for the last %d runs): %f (Max: %f)\n", + prepend.c_str(), n, (1000.0f*sum/n), 1000.0f * getMax()); +} + + +// +// Stopwatch +// +Stopwatch::Stopwatch() +: _count(0), + _printcounter(0) +{ + reset(); +} + +void Stopwatch::start() { + _st = getTimeS(); +} + +float Stopwatch::stop() { + if (_st == -1) return 0; + _last = getTimeS() - _st; + if (_last > _max) _max = _last; + _tt += _last; + _st = -1; + ++_count; + return _tt; +} + +float Stopwatch::stopContinue() { + if (_st == -1) return 0; + const float now = getTimeS(); + _last = now - _st; + if (_last > _max) _max = _last; + _tt += _last; + _st = now; + ++_count; + return _tt; +} + +float Stopwatch::getLast() { + return _last; +} + +float Stopwatch::getTotal() { + return _tt; +} + +float Stopwatch::getMax() { + return _max; +} + +int Stopwatch::getCount() { + return _count; +} + +void Stopwatch::reset() { + _st = -1; + _tt = 0; + _max = 0; +} + +void Stopwatch::printEvery( int n, const std::string& prepend /*= ""*/ ) { + if (++_printcounter >= n) { + _printcounter = 0; + print(prepend); + } +} + +void Stopwatch::print( const std::string& prepend /*= ""*/ ) { + if (!_count) return; + LOGI("%s\tTime (AVGms/LTs(MAXs)/TTs, C) : %.3f/%.6f(%.6f)/%.4f, %d\n", + prepend.c_str(), (1000.0f*_tt/_count), _last, _max, _tt, _count); +} + +// +// StopwatchHandler - a collection of StopWatch:es +// +Stopwatch& StopwatchHandler::get( const std::string& s ) { + Map::iterator it = _map.find(s); + if (it != _map.end()) + return *it->second; + + Stopwatch* watch = new Stopwatch; + _map.insert(make_pair(s, watch)); + return *watch; +} + +void StopwatchHandler::clear( const std::string& s ) { + Map::iterator it = _map.find(s); + if (it != _map.end()) { + delete it->second; + } + _map.erase(s); +} + +void StopwatchHandler::clearAll() { + for (Map::iterator it = _map.begin(); it != _map.end(); ++it) + delete it->second; + _map.clear(); +} + +void StopwatchHandler::print() { + for (Map::iterator it = _map.begin(); it != _map.end(); ++it) { + it->second->print(it->first.c_str()); + } +} + +void StopwatchHandler::printEvery( int n ) { + if (++_printcounter >= n) { + _printcounter = 0; + print(); + } +} diff --git a/src/platform/time.h b/src/platform/time.hpp similarity index 99% rename from src/platform/time.h rename to src/platform/time.hpp index 044aeff..8de6798 100755 --- a/src/platform/time.h +++ b/src/platform/time.hpp @@ -2,7 +2,7 @@ #include #include -#include "log.h" +#include "log.hpp" float getTimeS(); int getTimeMs(); diff --git a/src/platform/win32/AppPlatform_win32.cpp b/src/platform/win32/AppPlatform_win32.cpp index f193e7c..a92661a 100755 --- a/src/platform/win32/AppPlatform_win32.cpp +++ b/src/platform/win32/AppPlatform_win32.cpp @@ -1,16 +1,16 @@ -#include "AppPlatform_win32.h" -#include "util/Mth.h" - -int AppPlatform_win32::getScreenWidth() { return 854; } -int AppPlatform_win32::getScreenHeight() { return 480; } - -float AppPlatform_win32::getPixelsPerMillimeter() { - // assuming 24" @ 1920x1200 - const int w = 1920; - const int h = 1200; - const float pixels = Mth::sqrt(w*w + h*h); - const float mm = 24 * 25.4f; - return pixels / mm; -} - -bool AppPlatform_win32::supportsTouchscreen() { return true; } +#include "AppPlatform_win32.hpp" +#include "util/Mth.hpp" + +int AppPlatform_win32::getScreenWidth() { return 854; } +int AppPlatform_win32::getScreenHeight() { return 480; } + +float AppPlatform_win32::getPixelsPerMillimeter() { + // assuming 24" @ 1920x1200 + const int w = 1920; + const int h = 1200; + const float pixels = Mth::sqrt(w*w + h*h); + const float mm = 24 * 25.4f; + return pixels / mm; +} + +bool AppPlatform_win32::supportsTouchscreen() { return true; } diff --git a/src/platform/win32/AppPlatform_win32.h b/src/platform/win32/AppPlatform_win32.hpp similarity index 93% rename from src/platform/win32/AppPlatform_win32.h rename to src/platform/win32/AppPlatform_win32.hpp index 01be48c..b94c32b 100755 --- a/src/platform/win32/AppPlatform_win32.h +++ b/src/platform/win32/AppPlatform_win32.hpp @@ -1,12 +1,12 @@ #pragma once -#include -#include "platform/log.h" -#include "platform/HttpClient.h" -#include "platform/PngLoader.h" -#include "client/renderer/gles.h" -#include "world/level/storage/FolderMethods.h" -#include "util/StringUtils.h" +#include +#include "platform/log.hpp" +#include "platform/HttpClient.hpp" +#include "platform/PngLoader.hpp" +#include "client/renderer/gles.hpp" +#include "world/level/storage/FolderMethods.hpp" +#include "util/StringUtils.hpp" #include #include #include diff --git a/src/rename.py b/src/rename.py deleted file mode 100644 index ad7cc5c..0000000 --- a/src/rename.py +++ /dev/null @@ -1,22 +0,0 @@ -import os - -for root, _, files in os.walk("."): - for f in files: - if f.endswith(".h"): - path = os.path.join(root, f) - with open(path, "r") as file: - lines = file.readlines() - - if len(lines) < 3: - continue - - if lines[0].startswith("#ifndef") and lines[1].startswith("#define"): - # убираем первые 2 строки и последний #endif - lines = lines[2:] - if lines[-1].strip().startswith("#endif"): - lines = lines[:-1] - - lines.insert(0, "#pragma once\n") - - with open(path, "w") as file: - file.writelines(lines) \ No newline at end of file diff --git a/src/server/ArgumentsSettings.cpp b/src/server/ArgumentsSettings.cpp index 88bcd51..2927913 100755 --- a/src/server/ArgumentsSettings.cpp +++ b/src/server/ArgumentsSettings.cpp @@ -1,4 +1,4 @@ -#include "ArgumentsSettings.h" +#include "ArgumentsSettings.hpp" #include #include #include diff --git a/src/server/ArgumentsSettings.h b/src/server/ArgumentsSettings.hpp similarity index 100% rename from src/server/ArgumentsSettings.h rename to src/server/ArgumentsSettings.hpp diff --git a/src/server/CreatorLevel.cpp b/src/server/CreatorLevel.cpp index bbef786..5fadb7e 100755 --- a/src/server/CreatorLevel.cpp +++ b/src/server/CreatorLevel.cpp @@ -1,6 +1,6 @@ -#include "CreatorLevel.h" -#include "../world/level/chunk/ChunkSource.h" -#include "../util/PerfTimer.h" +#include "CreatorLevel.hpp" +#include "world/level/chunk/ChunkSource.hpp" +#include "util/PerfTimer.hpp" CreatorLevel::CreatorLevel(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */) : super(levelStorage, levelName, settings, generatorVersion, fixedDimension) diff --git a/src/server/CreatorLevel.h b/src/server/CreatorLevel.hpp similarity index 88% rename from src/server/CreatorLevel.h rename to src/server/CreatorLevel.hpp index d35935c..e75f676 100755 --- a/src/server/CreatorLevel.h +++ b/src/server/CreatorLevel.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../world/level/Level.h" +#include "world/level/Level.hpp" class CreatorLevel: public Level { diff --git a/src/server/ServerLevel.cpp b/src/server/ServerLevel.cpp index e57d6b8..d48c3b3 100755 --- a/src/server/ServerLevel.cpp +++ b/src/server/ServerLevel.cpp @@ -1,67 +1,67 @@ -#include "ServerLevel.h" -#include "../network/RakNetInstance.h" -#include "../network/packet/SetTimePacket.h" -#include "../network/packet/SetHealthPacket.h" -#include "../world/level/tile/LevelEvent.h" -ServerLevel::ServerLevel(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */) - : super(levelStorage, levelName, settings, generatorVersion, fixedDimension), - allPlayersAreSleeping(false){ - -} - -void ServerLevel::updateSleepingPlayerList() { - bool allPlayersWasSleeping = allPlayersAreSleeping; - allPlayersAreSleeping = !players.empty(); - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { - Player* player = *it; - if(!player->isSleeping()) { - allPlayersAreSleeping = false; - break; - } - } - if(!allPlayersWasSleeping && allPlayersAreSleeping) { - levelEvent(NULL, LevelEvent::ALL_PLAYERS_SLEEPING, 0, 0, 0, 0); - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { - (*it)->setAllPlayersSleeping(); - } - } -} - -void ServerLevel::awakenAllPlayers() { - allPlayersAreSleeping = false; - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { - Player* player = *it; - if(player->isSleeping()) { - player->stopSleepInBed(false, false, true); - player->health = Player::MAX_HEALTH; - player->lastHealth = Player::MAX_HEALTH; - } - } - SetHealthPacket packet(Player::MAX_HEALTH); - raknetInstance->send(packet); -} - -bool ServerLevel::allPlayersSleeping() { - if(allPlayersAreSleeping && !isClientSide) { - // all players are sleeping, but have they slept long enough? - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { - if(!(*it)->isSleepingLongEnough()) { - return false; - } - } - // yep - return true; - } - return false; -} - -void ServerLevel::tick(){ - super::tick(); - if(allPlayersSleeping()) { - long newTime = levelData.getTime() + TICKS_PER_DAY; - levelData.setTime(newTime - (newTime % TICKS_PER_DAY)); - SetTimePacket packet(levelData.getTime()); - raknetInstance->send(packet); - awakenAllPlayers(); - } -} +#include "ServerLevel.hpp" +#include "network/RakNetInstance.hpp" +#include "network/packet/SetTimePacket.hpp" +#include "network/packet/SetHealthPacket.hpp" +#include "world/level/tile/LevelEvent.hpp" +ServerLevel::ServerLevel(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */) + : super(levelStorage, levelName, settings, generatorVersion, fixedDimension), + allPlayersAreSleeping(false){ + +} + +void ServerLevel::updateSleepingPlayerList() { + bool allPlayersWasSleeping = allPlayersAreSleeping; + allPlayersAreSleeping = !players.empty(); + for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + Player* player = *it; + if(!player->isSleeping()) { + allPlayersAreSleeping = false; + break; + } + } + if(!allPlayersWasSleeping && allPlayersAreSleeping) { + levelEvent(NULL, LevelEvent::ALL_PLAYERS_SLEEPING, 0, 0, 0, 0); + for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + (*it)->setAllPlayersSleeping(); + } + } +} + +void ServerLevel::awakenAllPlayers() { + allPlayersAreSleeping = false; + for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + Player* player = *it; + if(player->isSleeping()) { + player->stopSleepInBed(false, false, true); + player->health = Player::MAX_HEALTH; + player->lastHealth = Player::MAX_HEALTH; + } + } + SetHealthPacket packet(Player::MAX_HEALTH); + raknetInstance->send(packet); +} + +bool ServerLevel::allPlayersSleeping() { + if(allPlayersAreSleeping && !isClientSide) { + // all players are sleeping, but have they slept long enough? + for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + if(!(*it)->isSleepingLongEnough()) { + return false; + } + } + // yep + return true; + } + return false; +} + +void ServerLevel::tick(){ + super::tick(); + if(allPlayersSleeping()) { + long newTime = levelData.getTime() + TICKS_PER_DAY; + levelData.setTime(newTime - (newTime % TICKS_PER_DAY)); + SetTimePacket packet(levelData.getTime()); + raknetInstance->send(packet); + awakenAllPlayers(); + } +} diff --git a/src/server/ServerLevel.h b/src/server/ServerLevel.hpp similarity index 91% rename from src/server/ServerLevel.h rename to src/server/ServerLevel.hpp index 6aee26f..c30a3a5 100755 --- a/src/server/ServerLevel.h +++ b/src/server/ServerLevel.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../world/level/Level.h" +#include "world/level/Level.hpp" class ServerLevel: public Level { diff --git a/src/server/ServerPlayer.cpp b/src/server/ServerPlayer.cpp index 15d0e21..de00cc4 100755 --- a/src/server/ServerPlayer.cpp +++ b/src/server/ServerPlayer.cpp @@ -1,165 +1,165 @@ -#include "ServerPlayer.h" - -#include "../network/RakNetInstance.h" -#include "../network/packet/ContainerOpenPacket.h" -#include "../network/packet/ContainerClosePacket.h" -#include "../network/packet/ContainerSetDataPacket.h" -#include "../network/packet/ContainerSetSlotPacket.h" -#include "../network/packet/ContainerSetContentPacket.h" -#include "../network/packet/ChatPacket.h" -#include "../network/packet/EntityEventPacket.h" -#include "../network/packet/SetHealthPacket.h" -#include "../network/packet/TakeItemEntityPacket.h" -#include -#include "../world/level/tile/entity/FurnaceTileEntity.h" -#include "../world/inventory/FurnaceMenu.h" -#include "../world/inventory/FillingContainer.h" -#include "../world/inventory/ContainerMenu.h" -#include "../world/entity/EntityEvent.h" -#include "../network/packet/AnimatePacket.h" -#include "../world/level/tile/entity/ChestTileEntity.h" -#include "../network/packet/HurtArmorPacket.h" - -ServerPlayer::ServerPlayer( Minecraft* minecraft, Level* level ) -: super(level, minecraft->isCreativeMode()), - _mc(minecraft), - _prevHealth(-999), - _containerCounter(0) -{ - hasFakeInventory = true; - footSize = 0; -} - -ServerPlayer::~ServerPlayer() { - setContainerMenu(NULL); -} - -void ServerPlayer::stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint) { - if(isSleeping()) { - AnimatePacket packet(AnimatePacket::WAKE_UP, this); - _mc->raknetInstance->send(owner, packet); - } - super::stopSleepInBed(forcefulWakeUp, updateLevelList, saveRespawnPoint); -} - - -void ServerPlayer::aiStep() { - updateAttackAnim(); - super::aiStep(); -} - -void ServerPlayer::tick() { - super::tick(); - - if(!useItem.isNull()) - useItemDuration--; - - //LOGI("Server:tick. Cmenu: %p\n", containerMenu); - if (containerMenu) - containerMenu->broadcastChanges(); - - if (health != _prevHealth) { - _prevHealth = health; - SetHealthPacket packet(health); - _mc->raknetInstance->send(owner, packet); - } -} - -void ServerPlayer::take( Entity* e, int orgCount ) { - TakeItemEntityPacket packet(e->entityId, entityId); - _mc->raknetInstance->send(packet); - - super::take(e, orgCount); -} - -void ServerPlayer::hurtArmor(int dmg) { - super::hurtArmor(dmg); - HurtArmorPacket packet(dmg); - _mc->raknetInstance->send(owner, packet); -} - -void ServerPlayer::openContainer( ChestTileEntity* container) { - LOGI("Client is opening a container\n"); - nextContainerCounter(); - ContainerOpenPacket packet(_containerCounter, ContainerType::CONTAINER, container->getName(), container->getContainerSize()); - _mc->raknetInstance->send(owner, packet); - setContainerMenu(new ContainerMenu(container, container->runningId)); -} - -void ServerPlayer::openFurnace( FurnaceTileEntity* furnace ) { - LOGI("Client is opening a furnace\n"); - nextContainerCounter(); - ContainerOpenPacket packet(_containerCounter, ContainerType::FURNACE, furnace->getName(), furnace->getContainerSize()); - _mc->raknetInstance->send(owner, packet); - setContainerMenu(new FurnaceMenu(furnace)); -} - -void ServerPlayer::closeContainer() { - LOGI("Client is closing a container\n"); - ContainerClosePacket packet(containerMenu->containerId); - _mc->raknetInstance->send(owner, packet); - doCloseContainer(); -} - -void ServerPlayer::doCloseContainer() { - if (!containerMenu) { - LOGE("Container is missing @ doCloseContainer!\n"); - } - setContainerMenu(NULL); -} - -bool ServerPlayer::hasResource( int id ) { - return true; -} - -// -// IContainerListener -// -void ServerPlayer::setContainerData( BaseContainerMenu* menu, int id, int value ) { - ContainerSetDataPacket p(menu->containerId, id, value); - _mc->raknetInstance->send(owner, p); - //LOGI("Setting container data for id %d: %d\n", id, value); -} - -void ServerPlayer::slotChanged( BaseContainerMenu* menu, int slot, const ItemInstance& item, bool isResultSlot ) { - if (isResultSlot) return; - ContainerSetSlotPacket p(menu->containerId, slot, item); - _mc->raknetInstance->send(owner, p); - //LOGI("Slot %d changed\n", slot); -} - -void ServerPlayer::refreshContainer( BaseContainerMenu* menu, const std::vector& items ) { - ContainerSetContentPacket p(menu->containerId, menu->getItems()); - _mc->raknetInstance->send(owner, p); - //LOGI("Refreshing container with %d items\n", items.size()); -} - -void ServerPlayer::nextContainerCounter() { - if (++_containerCounter >= 100) - _containerCounter = 0; -} - -void ServerPlayer::setContainerMenu( BaseContainerMenu* menu ) { - if (containerMenu == menu) - return; - - if (containerMenu) - delete containerMenu; - - containerMenu = menu; - if (containerMenu) { - containerMenu->containerId = _containerCounter; - containerMenu->setListener(this); - } -} - -void ServerPlayer::completeUsingItem() { - EntityEventPacket p(entityId, EntityEvent::USE_ITEM_COMPLETE); - _mc->raknetInstance->send(owner, p); - super::completeUsingItem(); -} - -void ServerPlayer::displayClientMessage( const std::string& messageId ) { - ChatPacket package(messageId); - _mc->raknetInstance->send(owner, package); -} +#include "ServerPlayer.hpp" + +#include "network/RakNetInstance.hpp" +#include "network/packet/ContainerOpenPacket.hpp" +#include "network/packet/ContainerClosePacket.hpp" +#include "network/packet/ContainerSetDataPacket.hpp" +#include "network/packet/ContainerSetSlotPacket.hpp" +#include "network/packet/ContainerSetContentPacket.hpp" +#include "network/packet/ChatPacket.hpp" +#include "network/packet/EntityEventPacket.hpp" +#include "network/packet/SetHealthPacket.hpp" +#include "network/packet/TakeItemEntityPacket.hpp" +#include +#include "world/level/tile/entity/FurnaceTileEntity.hpp" +#include "world/inventory/FurnaceMenu.hpp" +#include "world/inventory/FillingContainer.hpp" +#include "world/inventory/ContainerMenu.hpp" +#include "world/entity/EntityEvent.hpp" +#include "network/packet/AnimatePacket.hpp" +#include "world/level/tile/entity/ChestTileEntity.hpp" +#include "network/packet/HurtArmorPacket.hpp" + +ServerPlayer::ServerPlayer( Minecraft* minecraft, Level* level ) +: super(level, minecraft->isCreativeMode()), + _mc(minecraft), + _prevHealth(-999), + _containerCounter(0) +{ + hasFakeInventory = true; + footSize = 0; +} + +ServerPlayer::~ServerPlayer() { + setContainerMenu(NULL); +} + +void ServerPlayer::stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint) { + if(isSleeping()) { + AnimatePacket packet(AnimatePacket::WAKE_UP, this); + _mc->raknetInstance->send(owner, packet); + } + super::stopSleepInBed(forcefulWakeUp, updateLevelList, saveRespawnPoint); +} + + +void ServerPlayer::aiStep() { + updateAttackAnim(); + super::aiStep(); +} + +void ServerPlayer::tick() { + super::tick(); + + if(!useItem.isNull()) + useItemDuration--; + + //LOGI("Server:tick. Cmenu: %p\n", containerMenu); + if (containerMenu) + containerMenu->broadcastChanges(); + + if (health != _prevHealth) { + _prevHealth = health; + SetHealthPacket packet(health); + _mc->raknetInstance->send(owner, packet); + } +} + +void ServerPlayer::take( Entity* e, int orgCount ) { + TakeItemEntityPacket packet(e->entityId, entityId); + _mc->raknetInstance->send(packet); + + super::take(e, orgCount); +} + +void ServerPlayer::hurtArmor(int dmg) { + super::hurtArmor(dmg); + HurtArmorPacket packet(dmg); + _mc->raknetInstance->send(owner, packet); +} + +void ServerPlayer::openContainer( ChestTileEntity* container) { + LOGI("Client is opening a container\n"); + nextContainerCounter(); + ContainerOpenPacket packet(_containerCounter, ContainerType::CONTAINER, container->getName(), container->getContainerSize()); + _mc->raknetInstance->send(owner, packet); + setContainerMenu(new ContainerMenu(container, container->runningId)); +} + +void ServerPlayer::openFurnace( FurnaceTileEntity* furnace ) { + LOGI("Client is opening a furnace\n"); + nextContainerCounter(); + ContainerOpenPacket packet(_containerCounter, ContainerType::FURNACE, furnace->getName(), furnace->getContainerSize()); + _mc->raknetInstance->send(owner, packet); + setContainerMenu(new FurnaceMenu(furnace)); +} + +void ServerPlayer::closeContainer() { + LOGI("Client is closing a container\n"); + ContainerClosePacket packet(containerMenu->containerId); + _mc->raknetInstance->send(owner, packet); + doCloseContainer(); +} + +void ServerPlayer::doCloseContainer() { + if (!containerMenu) { + LOGE("Container is missing @ doCloseContainer!\n"); + } + setContainerMenu(NULL); +} + +bool ServerPlayer::hasResource( int id ) { + return true; +} + +// +// IContainerListener +// +void ServerPlayer::setContainerData( BaseContainerMenu* menu, int id, int value ) { + ContainerSetDataPacket p(menu->containerId, id, value); + _mc->raknetInstance->send(owner, p); + //LOGI("Setting container data for id %d: %d\n", id, value); +} + +void ServerPlayer::slotChanged( BaseContainerMenu* menu, int slot, const ItemInstance& item, bool isResultSlot ) { + if (isResultSlot) return; + ContainerSetSlotPacket p(menu->containerId, slot, item); + _mc->raknetInstance->send(owner, p); + //LOGI("Slot %d changed\n", slot); +} + +void ServerPlayer::refreshContainer( BaseContainerMenu* menu, const std::vector& items ) { + ContainerSetContentPacket p(menu->containerId, menu->getItems()); + _mc->raknetInstance->send(owner, p); + //LOGI("Refreshing container with %d items\n", items.size()); +} + +void ServerPlayer::nextContainerCounter() { + if (++_containerCounter >= 100) + _containerCounter = 0; +} + +void ServerPlayer::setContainerMenu( BaseContainerMenu* menu ) { + if (containerMenu == menu) + return; + + if (containerMenu) + delete containerMenu; + + containerMenu = menu; + if (containerMenu) { + containerMenu->containerId = _containerCounter; + containerMenu->setListener(this); + } +} + +void ServerPlayer::completeUsingItem() { + EntityEventPacket p(entityId, EntityEvent::USE_ITEM_COMPLETE); + _mc->raknetInstance->send(owner, p); + super::completeUsingItem(); +} + +void ServerPlayer::displayClientMessage( const std::string& messageId ) { + ChatPacket package(messageId); + _mc->raknetInstance->send(owner, package); +} diff --git a/src/server/ServerPlayer.h b/src/server/ServerPlayer.hpp similarity index 92% rename from src/server/ServerPlayer.h rename to src/server/ServerPlayer.hpp index 9435043..b8b86ac 100755 --- a/src/server/ServerPlayer.h +++ b/src/server/ServerPlayer.hpp @@ -1,7 +1,7 @@ #pragma once -#include "../world/entity/player/Player.h" -#include "../world/inventory/BaseContainerMenu.h" +#include "world/entity/player/Player.hpp" +#include "world/inventory/BaseContainerMenu.hpp" class Minecraft; class FurnaceTileEntity; diff --git a/src/util/CollectionUtils.h b/src/util/CollectionUtils.hpp similarity index 100% rename from src/util/CollectionUtils.h rename to src/util/CollectionUtils.hpp diff --git a/src/util/DataIO.cpp b/src/util/DataIO.cpp index b535935..b98ded2 100755 --- a/src/util/DataIO.cpp +++ b/src/util/DataIO.cpp @@ -1,29 +1,29 @@ -#include "DataIO.h" - -// -// BytesDataOutput -// - -void BytesDataOutput::writeString( const std::string& v ) -{ - int length = v.length() & 0x7fff; - writeShort(length); - writeBytes(v.c_str(), length); - //LOGI("Writing: %d bytes as String: %s\n", v.length(), v.c_str()); -} - -// -// BytesDataInput -// -std::string BytesDataInput::readString() { - int len = readShort(); - if (len > MAX_STRING_LENGTH - 1) - len = MAX_STRING_LENGTH - 1; - char* buffer = new char[len + 1]; - readBytes(buffer, len); - buffer[len] = 0; - - std::string out(buffer); - delete[] buffer; - return out; -} +#include "DataIO.hpp" + +// +// BytesDataOutput +// + +void BytesDataOutput::writeString( const std::string& v ) +{ + int length = v.length() & 0x7fff; + writeShort(length); + writeBytes(v.c_str(), length); + //LOGI("Writing: %d bytes as String: %s\n", v.length(), v.c_str()); +} + +// +// BytesDataInput +// +std::string BytesDataInput::readString() { + int len = readShort(); + if (len > MAX_STRING_LENGTH - 1) + len = MAX_STRING_LENGTH - 1; + char* buffer = new char[len + 1]; + readBytes(buffer, len); + buffer[len] = 0; + + std::string out(buffer); + delete[] buffer; + return out; +} diff --git a/src/util/DataIO.h b/src/util/DataIO.hpp similarity index 99% rename from src/util/DataIO.h rename to src/util/DataIO.hpp index 2d3339e..d646e64 100755 --- a/src/util/DataIO.h +++ b/src/util/DataIO.hpp @@ -4,7 +4,7 @@ #include #include -#include "../platform/log.h" +#include "platform/log.hpp" // Interface for writing primitives to a stream class IDataOutput { diff --git a/src/util/IntHashMap.h b/src/util/IntHashMap.hpp similarity index 100% rename from src/util/IntHashMap.h rename to src/util/IntHashMap.hpp diff --git a/src/util/MemUtils.h b/src/util/MemUtils.hpp similarity index 100% rename from src/util/MemUtils.h rename to src/util/MemUtils.hpp diff --git a/src/util/Mth.cpp b/src/util/Mth.cpp index ad45157..cc73284 100755 --- a/src/util/Mth.cpp +++ b/src/util/Mth.cpp @@ -1,129 +1,129 @@ -#include "Mth.h" -#include "Random.h" -#include -#include - -#include "../Performance.h" - -static Random _rand; - -namespace Mth -{ - static float _sin[65536]; - static const float _sinScale = 65536.0f / (2.0f * PI); - - void initMth() { - for (int i = 0; i < 65536; ++i) - _sin[i] = ::sin(i / _sinScale); - } - - float sqrt(float x) { - //Stopwatch& w = Performance::watches.get("sqrt"); - //w.start(); - float ret = ::sqrt(x); - //w.stop(); - return ret; - } - - static inline float fastInvSqrt(float x) { - float xhalf = 0.5f*x; - int i = *(int*)&x; - i = 0x5f3759df - (i>>1); - x = *(float*)&i; - x = x*(1.5f - xhalf*x*x); - return x; - } - float invSqrt(float x) { - //Stopwatch& w = Performance::watches.get("invSqrt"); - //w.start(); - float ret = fastInvSqrt(x);//1.0f / sqrt(x); - //w.stop(); - return ret; - } - - int floor(float v) { - int i = (int) v; - return v < i ? i - 1 : i; - } - - float cos(float x) { - //Performance::watches.get("cos").start(); - //float ret = ::cos(x); - float ret = _sin[(int) (x * _sinScale + 65536 / 4) & 65535]; - //Performance::watches.get("cos").stop(); - return ret; - } - - float sin(float x) { - //Performance::watches.get("sin").start(); - //float ret = ::sin(x); - float ret = _sin[(int) (x * _sinScale) & 65535]; - //Performance::watches.get("sin").stop(); - return ret; - } - - float atan(float x) { - //Performance::watches.get("atan").start(); - float ret = ::atan(x); - //Performance::watches.get("atan").stop(); - return ret; - } - - float atan2(float dy, float dx) { - //Performance::watches.get("atan2").start(); - float ret = ::atan2(dy, dx); - //Performance::watches.get("atan2").stop(); - return ret; - } - - float random(){ - return _rand.nextFloat(); - } - int random(int n){ - return _rand.nextInt(n); - } - - int intFloorDiv(int a, int b) { - if (a < 0) return -((-a - 1) / b) - 1; - return a / b; - } - - float abs(float a) { return a>=0? a : -a; } - float Min(float a, float b) { return a<=b? a : b; } - float Max(float a, float b) { return a>=b? a : b; } - - int abs(int a) { return a>=0? a : -a; } - int Min(int a, int b) { return a<=b? a : b; } - int Max(int a, int b) { return a>=b? a : b; } - - float absDecrease(float value, float with, float min) { - if (value > 0) return Max(min, value - with); - return Min(value + with, -min); - } - //float absIncrease(float value, float with, float max); - - int clamp(int v, int low, int high) { - if (v > high) return high; - return v>low? v : low; - } - float clamp(float v, float low, float high) { - if (v > high) return high; - return v>low? v : low; - } - float lerp(float src, float dst, float alpha) { - return src + (dst - src) * alpha; - } - int lerp(int src, int dst, float alpha) { - return src + (int)((dst - src) * alpha); - } - - float absMax(float a, float b) { - if (a < 0) a = -a; - if (b < 0) b = -b; - return a > b ? a : b; - } - - float absMaxSigned(float a, float b) { - return abs(a) > abs(b)? a : b; - } -}; +#include "Mth.hpp" +#include "Random.hpp" +#include +#include + +#include "Performance.hpp" + +static Random _rand; + +namespace Mth +{ + static float _sin[65536]; + static const float _sinScale = 65536.0f / (2.0f * PI); + + void initMth() { + for (int i = 0; i < 65536; ++i) + _sin[i] = ::sin(i / _sinScale); + } + + float sqrt(float x) { + //Stopwatch& w = Performance::watches.get("sqrt"); + //w.start(); + float ret = ::sqrt(x); + //w.stop(); + return ret; + } + + static inline float fastInvSqrt(float x) { + float xhalf = 0.5f*x; + int i = *(int*)&x; + i = 0x5f3759df - (i>>1); + x = *(float*)&i; + x = x*(1.5f - xhalf*x*x); + return x; + } + float invSqrt(float x) { + //Stopwatch& w = Performance::watches.get("invSqrt"); + //w.start(); + float ret = fastInvSqrt(x);//1.0f / sqrt(x); + //w.stop(); + return ret; + } + + int floor(float v) { + int i = (int) v; + return v < i ? i - 1 : i; + } + + float cos(float x) { + //Performance::watches.get("cos").start(); + //float ret = ::cos(x); + float ret = _sin[(int) (x * _sinScale + 65536 / 4) & 65535]; + //Performance::watches.get("cos").stop(); + return ret; + } + + float sin(float x) { + //Performance::watches.get("sin").start(); + //float ret = ::sin(x); + float ret = _sin[(int) (x * _sinScale) & 65535]; + //Performance::watches.get("sin").stop(); + return ret; + } + + float atan(float x) { + //Performance::watches.get("atan").start(); + float ret = ::atan(x); + //Performance::watches.get("atan").stop(); + return ret; + } + + float atan2(float dy, float dx) { + //Performance::watches.get("atan2").start(); + float ret = ::atan2(dy, dx); + //Performance::watches.get("atan2").stop(); + return ret; + } + + float random(){ + return _rand.nextFloat(); + } + int random(int n){ + return _rand.nextInt(n); + } + + int intFloorDiv(int a, int b) { + if (a < 0) return -((-a - 1) / b) - 1; + return a / b; + } + + float abs(float a) { return a>=0? a : -a; } + float Min(float a, float b) { return a<=b? a : b; } + float Max(float a, float b) { return a>=b? a : b; } + + int abs(int a) { return a>=0? a : -a; } + int Min(int a, int b) { return a<=b? a : b; } + int Max(int a, int b) { return a>=b? a : b; } + + float absDecrease(float value, float with, float min) { + if (value > 0) return Max(min, value - with); + return Min(value + with, -min); + } + //float absIncrease(float value, float with, float max); + + int clamp(int v, int low, int high) { + if (v > high) return high; + return v>low? v : low; + } + float clamp(float v, float low, float high) { + if (v > high) return high; + return v>low? v : low; + } + float lerp(float src, float dst, float alpha) { + return src + (dst - src) * alpha; + } + int lerp(int src, int dst, float alpha) { + return src + (int)((dst - src) * alpha); + } + + float absMax(float a, float b) { + if (a < 0) a = -a; + if (b < 0) b = -b; + return a > b ? a : b; + } + + float absMaxSigned(float a, float b) { + return abs(a) > abs(b)? a : b; + } +}; diff --git a/src/util/Mth.h b/src/util/Mth.hpp similarity index 100% rename from src/util/Mth.h rename to src/util/Mth.hpp diff --git a/src/util/PerfRenderer.cpp b/src/util/PerfRenderer.cpp index a6543b8..d37a6bf 100755 --- a/src/util/PerfRenderer.cpp +++ b/src/util/PerfRenderer.cpp @@ -1,227 +1,227 @@ -#include "PerfRenderer.h" -#include "PerfTimer.h" - -#include "Mth.h" -#include "../client/gui/Font.h" -#include "../client/renderer/gles.h" -#include "../client/renderer/Tesselator.h" -#include - -PerfRenderer::PerfRenderer( Minecraft* mc, Font* font ) -: _mc(mc), - _font(font), - _debugPath("root"), - frameTimePos(0), - lastTimer(-1) -{ - for (int i = 0; i < 512; ++i) { - frameTimes.push_back(0); - tickTimes.push_back(0); - } -} - -void PerfRenderer::debugFpsMeterKeyPress( int key ) -{ - std::vector list = PerfTimer::getLog(_debugPath); - if (list.empty()) return; - - PerfTimer::ResultField node = list[0]; - list.erase(list.begin()); - if (key == 0) { - if (node.name.length() > 0) { - int pos = _debugPath.rfind("."); - if (pos != std::string::npos) _debugPath = _debugPath.substr(0, pos); - } - } else { - key--; - if (key < (int)list.size() && list[key].name != "unspecified") { - if (_debugPath.length() > 0) _debugPath += "."; - _debugPath += list[key].name; - } - } -} - -void PerfRenderer::renderFpsMeter( float tickTime ) -{ - std::vector list = PerfTimer::getLog(_debugPath); - if (list.empty()) - return; - - PerfTimer::ResultField node = list[0]; - list.erase(list.begin()); - - long usPer60Fps = 1000000l / 60; - if (lastTimer == -1) { - lastTimer = getTimeS(); - } - float now = getTimeS(); - tickTimes[ frameTimePos ] = tickTime; - frameTimes[frameTimePos ] = now - lastTimer; - lastTimer = now; - - if (++frameTimePos >= (int)frameTimes.size()) - frameTimePos = 0; - - glClear(GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_PROJECTION); - glEnable2(GL_COLOR_MATERIAL); - glLoadIdentity2(); - glOrthof(0, (GLfloat)_mc->width, (GLfloat)_mc->height, 0, 1000, 3000); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity2(); - glTranslatef2(0, 0, -2000); - - glLineWidth(1); - glDisable2(GL_TEXTURE_2D); - Tesselator& t = Tesselator::instance; - - t.begin(GL_TRIANGLES); - int hh1 = (int) (usPer60Fps / 200); - float count = (float)frameTimes.size(); - t.color(0x20000000); - t.vertex(0, (float)(_mc->height - hh1), 0); - t.vertex(0, (float)_mc->height, 0); - t.vertex(count, (float)_mc->height, 0); - t.vertex(count, (float)(_mc->height - hh1), 0); - - t.color(0x20200000); - t.vertex(0, (float)(_mc->height - hh1 * 2), 0); - t.vertex(0, (float)(_mc->height - hh1), 0); - t.vertex(count, (float)(_mc->height - hh1), 0); - t.vertex(count, (float)(_mc->height - hh1 * 2), 0); - - t.draw(); - float totalTime = 0; - for (unsigned int i = 0; i < frameTimes.size(); i++) { - totalTime += frameTimes[i]; - } - int hh = (int) (totalTime / 200 / frameTimes.size()); - t.begin(); - t.color(0x20400000); - t.vertex(0, (float)(_mc->height - hh), 0); - t.vertex(0, (float)_mc->height, 0); - t.vertex(count, (float)_mc->height, 0); - t.vertex(count, (float)(_mc->height - hh), 0); - t.draw(); - - t.begin(GL_LINES); - for (unsigned int i = 0; i < frameTimes.size(); i++) { - int col = ((i - frameTimePos) & (frameTimes.size() - 1)) * 255 / frameTimes.size(); - int cc = col * col / 255; - cc = cc * cc / 255; - int cc2 = cc * cc / 255; - cc2 = cc2 * cc2 / 255; - if (frameTimes[i] > usPer60Fps) { - t.color(0xff000000 + cc * 65536); - } else { - t.color(0xff000000 + cc * 256); - } - - float time = 10 * 1000 * frameTimes[i] / 200; - float time2 = 10 * 1000 * tickTimes[i] / 200; - - t.vertex(i + 0.5f, _mc->height - time + 0.5f, 0); - t.vertex(i + 0.5f, _mc->height + 0.5f, 0); - - // if (_mc->frameTimes[i]>nsPer60Fps) { - t.color(0xff000000 + cc * 65536 + cc * 256 + cc * 1); - // } else { - // t.color(0xff808080 + cc/2 * 256); - // } - t.vertex(i + 0.5f, _mc->height - time + 0.5f, 0); - t.vertex(i + 0.5f, _mc->height - (time - time2) + 0.5f, 0); - } - t.draw(); - //t.end(); - - int r = 160; - int x = _mc->width - r - 10; - int y = _mc->height - r * 2; - glEnable(GL_BLEND); - t.begin(); - t.color(0x000000, 200); - t.vertex(x - r * 1.1f, y - r * 0.6f - 16, 0); - t.vertex(x - r * 1.1f, y + r * 2.0f, 0); - t.vertex(x + r * 1.1f, y + r * 2.0f, 0); - t.vertex(x + r * 1.1f, y - r * 0.6f - 16, 0); - t.draw(); - glDisable(GL_BLEND); - - glDisable(GL_CULL_FACE); - - float totalPercentage = 0; - for (unsigned int i = 0; i < list.size(); i++) { - PerfTimer::ResultField& result = list[i]; - - int steps = Mth::floor(result.percentage / 4) + 1; - - t.begin(GL_TRIANGLE_FAN); - t.color(result.getColor()); - t.vertex((float)x, (float)y, 0); - for (int j = steps; j >= 0; j--) { - float dir = (float) ((totalPercentage + (result.percentage * j / steps)) * Mth::PI * 2 / 100); - float xx = Mth::sin(dir) * r; - float yy = Mth::cos(dir) * r * 0.5f; - t.vertex(x + xx, y - yy, 0); - //LOGI("xy: %f, %f\n", x+xx, y - yy); - } - t.draw(); - t.begin(GL_TRIANGLE_STRIP); - t.color((result.getColor() & 0xfefefe) >> 1); - for (int j = steps; j >= 0; j--) { - float dir = (float) ((totalPercentage + (result.percentage * j / steps)) * Mth::PI * 2 / 100); - float xx = Mth::sin(dir) * r; - float yy = Mth::cos(dir) * r * 0.5f; - t.vertex(x + xx, y - yy, 0); - t.vertex(x + xx, y - yy + 10, 0); - } - t.draw(); - - totalPercentage += result.percentage; - } - - glEnable(GL_TEXTURE_2D); - - { - std::stringstream msg; - if (node.name != "unspecified") { - msg << "[0] "; - } - if (node.name.length() == 0) { - msg << "ROOT "; - } else { - msg << node.name << " "; - } - int col = 0xffffff; - _font->drawShadow(msg.str(), (float)(x - r), (float)(y - r / 2 - 16), col); - std::string msg2 = toPercentString(node.globalPercentage); - _font->drawShadow(msg2, (float)(x + r - _font->width(msg2)), (float)(y - r / 2 - 16), col); - } - - for (unsigned int i = 0; i < list.size(); i++) { - PerfTimer::ResultField& result = list[i]; - std::stringstream msg; - if (result.name != "unspecified") { - msg << "[" << (i + 1) << "] "; - } else { - msg << "[?] "; - } - - msg << result.name; - float xx = (float)(x - r); - float yy = (float)(y + r/2 + i * 8 + 20); - _font->drawShadow(msg.str(), xx, yy, result.getColor()); - std::string msg2 = toPercentString(result.percentage); - //LOGI("name: %s: perc: %f == %s @ %d, %d\n", msg.str().c_str(), result.percentage, msg2.c_str(), xx, yy); - _font->drawShadow(msg2, xx - 50 - _font->width(msg2), yy, result.getColor()); - msg2 = toPercentString(result.globalPercentage); - _font->drawShadow(msg2, xx - _font->width(msg2), yy, result.getColor()); - } -} - -std::string PerfRenderer::toPercentString( float percentage ) -{ - char buf[32] = {0}; - sprintf(buf, "%3.2f%%", percentage); - return buf; -} +#include "PerfRenderer.hpp" +#include "PerfTimer.hpp" + +#include "Mth.hpp" +#include "client/gui/Font.hpp" +#include "client/renderer/gles.hpp" +#include "client/renderer/Tesselator.hpp" +#include + +PerfRenderer::PerfRenderer( Minecraft* mc, Font* font ) +: _mc(mc), + _font(font), + _debugPath("root"), + frameTimePos(0), + lastTimer(-1) +{ + for (int i = 0; i < 512; ++i) { + frameTimes.push_back(0); + tickTimes.push_back(0); + } +} + +void PerfRenderer::debugFpsMeterKeyPress( int key ) +{ + std::vector list = PerfTimer::getLog(_debugPath); + if (list.empty()) return; + + PerfTimer::ResultField node = list[0]; + list.erase(list.begin()); + if (key == 0) { + if (node.name.length() > 0) { + int pos = _debugPath.rfind("."); + if (pos != std::string::npos) _debugPath = _debugPath.substr(0, pos); + } + } else { + key--; + if (key < (int)list.size() && list[key].name != "unspecified") { + if (_debugPath.length() > 0) _debugPath += "."; + _debugPath += list[key].name; + } + } +} + +void PerfRenderer::renderFpsMeter( float tickTime ) +{ + std::vector list = PerfTimer::getLog(_debugPath); + if (list.empty()) + return; + + PerfTimer::ResultField node = list[0]; + list.erase(list.begin()); + + long usPer60Fps = 1000000l / 60; + if (lastTimer == -1) { + lastTimer = getTimeS(); + } + float now = getTimeS(); + tickTimes[ frameTimePos ] = tickTime; + frameTimes[frameTimePos ] = now - lastTimer; + lastTimer = now; + + if (++frameTimePos >= (int)frameTimes.size()) + frameTimePos = 0; + + glClear(GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glEnable2(GL_COLOR_MATERIAL); + glLoadIdentity2(); + glOrthof(0, (GLfloat)_mc->width, (GLfloat)_mc->height, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity2(); + glTranslatef2(0, 0, -2000); + + glLineWidth(1); + glDisable2(GL_TEXTURE_2D); + Tesselator& t = Tesselator::instance; + + t.begin(GL_TRIANGLES); + int hh1 = (int) (usPer60Fps / 200); + float count = (float)frameTimes.size(); + t.color(0x20000000); + t.vertex(0, (float)(_mc->height - hh1), 0); + t.vertex(0, (float)_mc->height, 0); + t.vertex(count, (float)_mc->height, 0); + t.vertex(count, (float)(_mc->height - hh1), 0); + + t.color(0x20200000); + t.vertex(0, (float)(_mc->height - hh1 * 2), 0); + t.vertex(0, (float)(_mc->height - hh1), 0); + t.vertex(count, (float)(_mc->height - hh1), 0); + t.vertex(count, (float)(_mc->height - hh1 * 2), 0); + + t.draw(); + float totalTime = 0; + for (unsigned int i = 0; i < frameTimes.size(); i++) { + totalTime += frameTimes[i]; + } + int hh = (int) (totalTime / 200 / frameTimes.size()); + t.begin(); + t.color(0x20400000); + t.vertex(0, (float)(_mc->height - hh), 0); + t.vertex(0, (float)_mc->height, 0); + t.vertex(count, (float)_mc->height, 0); + t.vertex(count, (float)(_mc->height - hh), 0); + t.draw(); + + t.begin(GL_LINES); + for (unsigned int i = 0; i < frameTimes.size(); i++) { + int col = ((i - frameTimePos) & (frameTimes.size() - 1)) * 255 / frameTimes.size(); + int cc = col * col / 255; + cc = cc * cc / 255; + int cc2 = cc * cc / 255; + cc2 = cc2 * cc2 / 255; + if (frameTimes[i] > usPer60Fps) { + t.color(0xff000000 + cc * 65536); + } else { + t.color(0xff000000 + cc * 256); + } + + float time = 10 * 1000 * frameTimes[i] / 200; + float time2 = 10 * 1000 * tickTimes[i] / 200; + + t.vertex(i + 0.5f, _mc->height - time + 0.5f, 0); + t.vertex(i + 0.5f, _mc->height + 0.5f, 0); + + // if (_mc->frameTimes[i]>nsPer60Fps) { + t.color(0xff000000 + cc * 65536 + cc * 256 + cc * 1); + // } else { + // t.color(0xff808080 + cc/2 * 256); + // } + t.vertex(i + 0.5f, _mc->height - time + 0.5f, 0); + t.vertex(i + 0.5f, _mc->height - (time - time2) + 0.5f, 0); + } + t.draw(); + //t.end(); + + int r = 160; + int x = _mc->width - r - 10; + int y = _mc->height - r * 2; + glEnable(GL_BLEND); + t.begin(); + t.color(0x000000, 200); + t.vertex(x - r * 1.1f, y - r * 0.6f - 16, 0); + t.vertex(x - r * 1.1f, y + r * 2.0f, 0); + t.vertex(x + r * 1.1f, y + r * 2.0f, 0); + t.vertex(x + r * 1.1f, y - r * 0.6f - 16, 0); + t.draw(); + glDisable(GL_BLEND); + + glDisable(GL_CULL_FACE); + + float totalPercentage = 0; + for (unsigned int i = 0; i < list.size(); i++) { + PerfTimer::ResultField& result = list[i]; + + int steps = Mth::floor(result.percentage / 4) + 1; + + t.begin(GL_TRIANGLE_FAN); + t.color(result.getColor()); + t.vertex((float)x, (float)y, 0); + for (int j = steps; j >= 0; j--) { + float dir = (float) ((totalPercentage + (result.percentage * j / steps)) * Mth::PI * 2 / 100); + float xx = Mth::sin(dir) * r; + float yy = Mth::cos(dir) * r * 0.5f; + t.vertex(x + xx, y - yy, 0); + //LOGI("xy: %f, %f\n", x+xx, y - yy); + } + t.draw(); + t.begin(GL_TRIANGLE_STRIP); + t.color((result.getColor() & 0xfefefe) >> 1); + for (int j = steps; j >= 0; j--) { + float dir = (float) ((totalPercentage + (result.percentage * j / steps)) * Mth::PI * 2 / 100); + float xx = Mth::sin(dir) * r; + float yy = Mth::cos(dir) * r * 0.5f; + t.vertex(x + xx, y - yy, 0); + t.vertex(x + xx, y - yy + 10, 0); + } + t.draw(); + + totalPercentage += result.percentage; + } + + glEnable(GL_TEXTURE_2D); + + { + std::stringstream msg; + if (node.name != "unspecified") { + msg << "[0] "; + } + if (node.name.length() == 0) { + msg << "ROOT "; + } else { + msg << node.name << " "; + } + int col = 0xffffff; + _font->drawShadow(msg.str(), (float)(x - r), (float)(y - r / 2 - 16), col); + std::string msg2 = toPercentString(node.globalPercentage); + _font->drawShadow(msg2, (float)(x + r - _font->width(msg2)), (float)(y - r / 2 - 16), col); + } + + for (unsigned int i = 0; i < list.size(); i++) { + PerfTimer::ResultField& result = list[i]; + std::stringstream msg; + if (result.name != "unspecified") { + msg << "[" << (i + 1) << "] "; + } else { + msg << "[?] "; + } + + msg << result.name; + float xx = (float)(x - r); + float yy = (float)(y + r/2 + i * 8 + 20); + _font->drawShadow(msg.str(), xx, yy, result.getColor()); + std::string msg2 = toPercentString(result.percentage); + //LOGI("name: %s: perc: %f == %s @ %d, %d\n", msg.str().c_str(), result.percentage, msg2.c_str(), xx, yy); + _font->drawShadow(msg2, xx - 50 - _font->width(msg2), yy, result.getColor()); + msg2 = toPercentString(result.globalPercentage); + _font->drawShadow(msg2, xx - _font->width(msg2), yy, result.getColor()); + } +} + +std::string PerfRenderer::toPercentString( float percentage ) +{ + char buf[32] = {0}; + sprintf(buf, "%3.2f%%", percentage); + return buf; +} diff --git a/src/util/PerfRenderer.h b/src/util/PerfRenderer.hpp similarity index 100% rename from src/util/PerfRenderer.h rename to src/util/PerfRenderer.hpp diff --git a/src/util/PerfTimer.cpp b/src/util/PerfTimer.cpp index e5b4df1..622d7b1 100755 --- a/src/util/PerfTimer.cpp +++ b/src/util/PerfTimer.cpp @@ -1,123 +1,123 @@ -#include "PerfTimer.h" -#include "../platform/time.h" -#include - -/*static*/ -bool - PerfTimer::enabled = false; - -std::vector - PerfTimer::paths; - -std::vector - PerfTimer::startTimes; - -std::string - PerfTimer::path; - -PerfTimer::TimeMap - PerfTimer::times; - - -/*static*/ -void PerfTimer::reset() -{ - times.clear(); -} - -/*static*/ -void PerfTimer::push( const std::string& name ) -{ - if (!enabled) return; - if (path.length() > 0) path += "."; - path += name; - paths.push_back(path); - startTimes.push_back(getTimeS()); -} - -/*static*/ -void PerfTimer::pop() -{ - if (!enabled) return; - float endTime = getTimeS(); - float startTime = startTimes.back(); - - paths.pop_back(); - startTimes.pop_back(); - - float time = endTime - startTime; - - TimeMap::iterator it = times.find(path); - if (it != times.end()) { - it->second += time; - } else { - times.insert(std::make_pair(path, time)); - } - - path = paths.size() > 0 ? paths.back() : ""; - - //if (paths.size() == 0) { - // for (TimeMap::iterator it = times.begin(); it != times.end(); ++it) { - // LOGI("p: %s t: %f\n", it->first.c_str(), it->second); - // } - //} -} - -/*static*/ -void PerfTimer::popPush( const std::string& name ) -{ - pop(); - push(name); -} - -/*static*/ -std::vector PerfTimer::getLog(const std::string& rawPath) { - if (!enabled) return std::vector(); - - std::string path = rawPath; - - TimeMap::const_iterator itRoot = times.find("root"); - float globalTime = (itRoot != times.end())? itRoot->second : 0; - - TimeMap::const_iterator itPath = times.find(path); - float totalTime2 = (itRoot != times.end())? itRoot->second : -1; - - std::vector result; - - if (path.length() > 0) path += "."; - float totalTime = 0; - - for (TimeMap::const_iterator cit = times.begin(); cit != times.end(); ++cit) { - const std::string& key = cit->first; - const float& time = cit->second; - if (key.length() > path.length() && Util::startsWith(key, path) && key.find(".", path.length() + 1) == std::string::npos) { - totalTime += time; - } - } - - float oldTime = totalTime; - if (totalTime < totalTime2) totalTime = totalTime2; - if (globalTime < totalTime) globalTime = totalTime; - - for (TimeMap::const_iterator cit = times.begin(); cit != times.end(); ++cit) { - const std::string& key = cit->first; - //const float& time = cit->second; - if (key.length() > path.length() && Util::startsWith(key, path) && key.find(".", path.length() + 1) == std::string::npos) { - float time = times.find(key)->second; - float timePercentage = time * 100.0f / totalTime; - float globalPercentage = time * 100.0f / globalTime; - std::string name = key.substr(path.length()); - result.push_back(ResultField(name, timePercentage, globalPercentage)); - } - } - - for (TimeMap::iterator it = times.begin(); it != times.end(); ++it) - it->second *= 0.999f; - - if (totalTime > oldTime) - result.push_back(ResultField("unspecified", (totalTime - oldTime) * 100.0f / totalTime, (totalTime - oldTime) * 100.0f / globalTime)); - - std::sort(result.begin(), result.end()); - result.insert(result.begin(), ResultField(rawPath, 100, totalTime * 100.0f / globalTime)); - return result; -} +#include "PerfTimer.hpp" +#include "platform/time.hpp" +#include + +/*static*/ +bool + PerfTimer::enabled = false; + +std::vector + PerfTimer::paths; + +std::vector + PerfTimer::startTimes; + +std::string + PerfTimer::path; + +PerfTimer::TimeMap + PerfTimer::times; + + +/*static*/ +void PerfTimer::reset() +{ + times.clear(); +} + +/*static*/ +void PerfTimer::push( const std::string& name ) +{ + if (!enabled) return; + if (path.length() > 0) path += "."; + path += name; + paths.push_back(path); + startTimes.push_back(getTimeS()); +} + +/*static*/ +void PerfTimer::pop() +{ + if (!enabled) return; + float endTime = getTimeS(); + float startTime = startTimes.back(); + + paths.pop_back(); + startTimes.pop_back(); + + float time = endTime - startTime; + + TimeMap::iterator it = times.find(path); + if (it != times.end()) { + it->second += time; + } else { + times.insert(std::make_pair(path, time)); + } + + path = paths.size() > 0 ? paths.back() : ""; + + //if (paths.size() == 0) { + // for (TimeMap::iterator it = times.begin(); it != times.end(); ++it) { + // LOGI("p: %s t: %f\n", it->first.c_str(), it->second); + // } + //} +} + +/*static*/ +void PerfTimer::popPush( const std::string& name ) +{ + pop(); + push(name); +} + +/*static*/ +std::vector PerfTimer::getLog(const std::string& rawPath) { + if (!enabled) return std::vector(); + + std::string path = rawPath; + + TimeMap::const_iterator itRoot = times.find("root"); + float globalTime = (itRoot != times.end())? itRoot->second : 0; + + TimeMap::const_iterator itPath = times.find(path); + float totalTime2 = (itRoot != times.end())? itRoot->second : -1; + + std::vector result; + + if (path.length() > 0) path += "."; + float totalTime = 0; + + for (TimeMap::const_iterator cit = times.begin(); cit != times.end(); ++cit) { + const std::string& key = cit->first; + const float& time = cit->second; + if (key.length() > path.length() && Util::startsWith(key, path) && key.find(".", path.length() + 1) == std::string::npos) { + totalTime += time; + } + } + + float oldTime = totalTime; + if (totalTime < totalTime2) totalTime = totalTime2; + if (globalTime < totalTime) globalTime = totalTime; + + for (TimeMap::const_iterator cit = times.begin(); cit != times.end(); ++cit) { + const std::string& key = cit->first; + //const float& time = cit->second; + if (key.length() > path.length() && Util::startsWith(key, path) && key.find(".", path.length() + 1) == std::string::npos) { + float time = times.find(key)->second; + float timePercentage = time * 100.0f / totalTime; + float globalPercentage = time * 100.0f / globalTime; + std::string name = key.substr(path.length()); + result.push_back(ResultField(name, timePercentage, globalPercentage)); + } + } + + for (TimeMap::iterator it = times.begin(); it != times.end(); ++it) + it->second *= 0.999f; + + if (totalTime > oldTime) + result.push_back(ResultField("unspecified", (totalTime - oldTime) * 100.0f / totalTime, (totalTime - oldTime) * 100.0f / globalTime)); + + std::sort(result.begin(), result.end()); + result.insert(result.begin(), ResultField(rawPath, 100, totalTime * 100.0f / globalTime)); + return result; +} diff --git a/src/util/PerfTimer.h b/src/util/PerfTimer.hpp similarity index 96% rename from src/util/PerfTimer.h rename to src/util/PerfTimer.hpp index 58a3d5f..1dcd513 100755 --- a/src/util/PerfTimer.h +++ b/src/util/PerfTimer.hpp @@ -2,7 +2,7 @@ #include #include -#include "StringUtils.h" +#include "StringUtils.hpp" //package util; #ifdef PROFILER @@ -10,7 +10,7 @@ #define TIMER_POP() PerfTimer::pop() #define TIMER_POP_PUSH(x) PerfTimer::popPush(x) // #elif defined(SERVER_PROFILER) -// #include "ServerProfiler.h" +// #include "ServerProfiler.hpp" // #define TIMER_PUSH(x) ServerProfiler::push(x) // #define TIMER_POP() ServerProfiler::pop() diff --git a/src/util/RakDataIO.h b/src/util/RakDataIO.hpp similarity index 97% rename from src/util/RakDataIO.h rename to src/util/RakDataIO.hpp index b875906..acfaa34 100755 --- a/src/util/RakDataIO.h +++ b/src/util/RakDataIO.hpp @@ -3,7 +3,7 @@ #include #include -#include "DataIO.h" +#include "DataIO.hpp" // Uses BitStream as a growing buffer class RakDataOutput: public BytesDataOutput { diff --git a/src/util/Random.h b/src/util/Random.hpp similarity index 99% rename from src/util/Random.h rename to src/util/Random.hpp index 5d38882..336b727 100755 --- a/src/util/Random.h +++ b/src/util/Random.hpp @@ -17,7 +17,7 @@ */ -#include "../platform/time.h" +#include "platform/time.hpp" #include class Random diff --git a/src/util/ServerProfiler.cpp b/src/util/ServerProfiler.cpp index 0fa3755..5f0b475 100644 --- a/src/util/ServerProfiler.cpp +++ b/src/util/ServerProfiler.cpp @@ -1,4 +1,4 @@ -// #include "ServerProfiler.h" +// #include "ServerProfiler.hpp" // std::stack ServerProfiler::stack; // std::unordered_map ServerProfiler::times; diff --git a/src/util/ServerProfiler.h b/src/util/ServerProfiler.hpp similarity index 100% rename from src/util/ServerProfiler.h rename to src/util/ServerProfiler.hpp diff --git a/src/util/SmoothFloat.h b/src/util/SmoothFloat.hpp similarity index 100% rename from src/util/SmoothFloat.h rename to src/util/SmoothFloat.hpp diff --git a/src/util/StringUtils.cpp b/src/util/StringUtils.cpp index c8c344e..8f4be83 100755 --- a/src/util/StringUtils.cpp +++ b/src/util/StringUtils.cpp @@ -1,73 +1,73 @@ -#include "StringUtils.h" -#include -#include "../platform/log.h" - -namespace Util -{ - -/// @return true if starts with , false if not -bool startsWith(const std::string& s, const std::string& start) { - const unsigned int len = start.length(); - return len <= s.length() - && s.substr(0, len) == start; -} - -// Naive (e.g. slow and stupid) implementation. @todo: fix -/// @return A reference to s -std::string& stringReplace(std::string& s, const std::string& src, const std::string& dst, int maxCount /*= -1*/) { - int srcLength = src.length(); - - while(maxCount--) { - std::string::size_type pos = s.find(src); - if (pos == std::string::npos) - break; - s.replace(pos, srcLength, dst); - } - return s; -} - -/// @return A string trimmed from white space characters on both ends -std::string stringTrim(const std::string& s) { - return stringTrim(s, " \t\n\r", true, true); -} - -/// @return A string trimmed from given characters on any end -std::string stringTrim(const std::string& s, const std::string& chars, bool left, bool right) { - const int len = s.length(); - const int lenChars = chars.length(); - - if (len == 0 || lenChars == 0 || ((left || right) == false)) - return ""; - - int i = 0, j = len-1; - - if (left) { - for (; i < len; ++i) - if (std::find(chars.begin(), chars.end(), s[i]) == chars.end()) - break; - } - if (right) { - for (; j >= i; --j) - if (std::find(chars.begin(), chars.end(), s[j]) == chars.end()) - break; - } - return s.substr(i, j - i + 1); -} - -/// @return The "Java" implementation for string hash codes -int hashCode(const std::string& s) { - const int len = s.length(); - - int hash = 0; - for (int i = 0; i < len; i++) { - hash = ((hash << 5) - hash) + s[i]; - } - return hash; -} - -void removeAll(std::string& s, const char** rep, int repCount) { - for (int i = 0; i < repCount; ++i) - stringReplace(s, rep[i], ""); -} - -}; // end namespace Util +#include "StringUtils.hpp" +#include +#include "platform/log.hpp" + +namespace Util +{ + +/// @return true if starts with , false if not +bool startsWith(const std::string& s, const std::string& start) { + const unsigned int len = start.length(); + return len <= s.length() + && s.substr(0, len) == start; +} + +// Naive (e.g. slow and stupid) implementation. @todo: fix +/// @return A reference to s +std::string& stringReplace(std::string& s, const std::string& src, const std::string& dst, int maxCount /*= -1*/) { + int srcLength = src.length(); + + while(maxCount--) { + std::string::size_type pos = s.find(src); + if (pos == std::string::npos) + break; + s.replace(pos, srcLength, dst); + } + return s; +} + +/// @return A string trimmed from white space characters on both ends +std::string stringTrim(const std::string& s) { + return stringTrim(s, " \t\n\r", true, true); +} + +/// @return A string trimmed from given characters on any end +std::string stringTrim(const std::string& s, const std::string& chars, bool left, bool right) { + const int len = s.length(); + const int lenChars = chars.length(); + + if (len == 0 || lenChars == 0 || ((left || right) == false)) + return ""; + + int i = 0, j = len-1; + + if (left) { + for (; i < len; ++i) + if (std::find(chars.begin(), chars.end(), s[i]) == chars.end()) + break; + } + if (right) { + for (; j >= i; --j) + if (std::find(chars.begin(), chars.end(), s[j]) == chars.end()) + break; + } + return s.substr(i, j - i + 1); +} + +/// @return The "Java" implementation for string hash codes +int hashCode(const std::string& s) { + const int len = s.length(); + + int hash = 0; + for (int i = 0; i < len; i++) { + hash = ((hash << 5) - hash) + s[i]; + } + return hash; +} + +void removeAll(std::string& s, const char** rep, int repCount) { + for (int i = 0; i < repCount; ++i) + stringReplace(s, rep[i], ""); +} + +}; // end namespace Util diff --git a/src/util/StringUtils.h b/src/util/StringUtils.hpp similarity index 100% rename from src/util/StringUtils.h rename to src/util/StringUtils.hpp diff --git a/src/util/WeighedRandom.h b/src/util/WeighedRandom.hpp similarity index 99% rename from src/util/WeighedRandom.h rename to src/util/WeighedRandom.hpp index 3a11745..ba80ced 100755 --- a/src/util/WeighedRandom.h +++ b/src/util/WeighedRandom.hpp @@ -2,7 +2,7 @@ //package util; -#include "Random.h" +#include "Random.hpp" class WeighedRandom { diff --git a/src/world/Container.h b/src/world/Container.hpp similarity index 97% rename from src/world/Container.h rename to src/world/Container.hpp index 213b3b7..c48ffa6 100755 --- a/src/world/Container.h +++ b/src/world/Container.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world; -#include "item/ItemInstance.h" +#include "item/ItemInstance.hpp" #include #include diff --git a/src/world/Difficulty.h b/src/world/Difficulty.hpp similarity index 100% rename from src/world/Difficulty.h rename to src/world/Difficulty.hpp diff --git a/src/world/Direction.cpp b/src/world/Direction.cpp index f7edd8c..3dec770 100755 --- a/src/world/Direction.cpp +++ b/src/world/Direction.cpp @@ -1,71 +1,71 @@ -#include "Direction.h" -#include "Facing.h" - -const int Direction::DIRECTION_FACING[4] = { - Facing::SOUTH, - Facing::WEST, - Facing::NORTH, - Facing::EAST -}; -const int Direction::FACING_DIRECTION[6] = { - Direction::UNDEFINED, - Direction::UNDEFINED, - Direction::NORTH, - Direction::SOUTH, - Direction::WEST, - Direction::EAST -}; -const int Direction::DIRECTION_OPPOSITE[4] = { - Direction::NORTH, - Direction::EAST, - Direction::SOUTH, - Direction::WEST -}; - -const int Direction::RELATIVE_DIRECTION_FACING[4][6] = { - // south - { Facing::DOWN, - Facing::UP, - Facing::SOUTH, - Facing::NORTH, - Facing::EAST, - Facing::WEST }, - // west - { Facing::DOWN, - Facing::UP, - Facing::EAST, - Facing::WEST, - Facing::NORTH, - Facing::SOUTH }, - // north - { Facing::DOWN, - Facing::UP, - Facing::NORTH, - Facing::SOUTH, - Facing::WEST, - Facing::EAST }, - // east - { Facing::DOWN, - Facing::UP, - Facing::WEST, - Facing::EAST, - Facing::SOUTH, - Facing::NORTH } -}; - -// declared in Facing.h - -const int Facing::OPPOSITE_FACING[6] = { - Facing::UP, Facing::DOWN, Facing::SOUTH, Facing::NORTH, Facing::EAST, Facing::WEST -}; - -const int Facing::STEP_X[6] = { - 0, 0, 0, 0, -1, 1 -}; -const int Facing::STEP_Y[6] = { - -1, 1, 0, 0, 0, 0 -}; -const int Facing::STEP_Z[6] = { - 0, 0, -1, 1, 0, 0 -}; - +#include "Direction.hpp" +#include "Facing.hpp" + +const int Direction::DIRECTION_FACING[4] = { + Facing::SOUTH, + Facing::WEST, + Facing::NORTH, + Facing::EAST +}; +const int Direction::FACING_DIRECTION[6] = { + Direction::UNDEFINED, + Direction::UNDEFINED, + Direction::NORTH, + Direction::SOUTH, + Direction::WEST, + Direction::EAST +}; +const int Direction::DIRECTION_OPPOSITE[4] = { + Direction::NORTH, + Direction::EAST, + Direction::SOUTH, + Direction::WEST +}; + +const int Direction::RELATIVE_DIRECTION_FACING[4][6] = { + // south + { Facing::DOWN, + Facing::UP, + Facing::SOUTH, + Facing::NORTH, + Facing::EAST, + Facing::WEST }, + // west + { Facing::DOWN, + Facing::UP, + Facing::EAST, + Facing::WEST, + Facing::NORTH, + Facing::SOUTH }, + // north + { Facing::DOWN, + Facing::UP, + Facing::NORTH, + Facing::SOUTH, + Facing::WEST, + Facing::EAST }, + // east + { Facing::DOWN, + Facing::UP, + Facing::WEST, + Facing::EAST, + Facing::SOUTH, + Facing::NORTH } +}; + +// declared in Facing.h + +const int Facing::OPPOSITE_FACING[6] = { + Facing::UP, Facing::DOWN, Facing::SOUTH, Facing::NORTH, Facing::EAST, Facing::WEST +}; + +const int Facing::STEP_X[6] = { + 0, 0, 0, 0, -1, 1 +}; +const int Facing::STEP_Y[6] = { + -1, 1, 0, 0, 0, 0 +}; +const int Facing::STEP_Z[6] = { + 0, 0, -1, 1, 0, 0 +}; + diff --git a/src/world/Direction.h b/src/world/Direction.hpp similarity index 100% rename from src/world/Direction.h rename to src/world/Direction.hpp diff --git a/src/world/Facing.h b/src/world/Facing.hpp similarity index 100% rename from src/world/Facing.h rename to src/world/Facing.hpp diff --git a/src/world/Pos.h b/src/world/Pos.hpp similarity index 100% rename from src/world/Pos.h rename to src/world/Pos.hpp diff --git a/src/world/PosTranslator.h b/src/world/PosTranslator.hpp similarity index 100% rename from src/world/PosTranslator.h rename to src/world/PosTranslator.hpp diff --git a/src/world/entity/AgableMob.cpp b/src/world/entity/AgableMob.cpp index 6dfc406..da22820 100755 --- a/src/world/entity/AgableMob.cpp +++ b/src/world/entity/AgableMob.cpp @@ -1,53 +1,53 @@ -#include "AgableMob.h" - -AgableMob::AgableMob( Level* level ) -: super(level), - age(-1) -{ - entityData.define(DATA_FLAGS_ID, (SynchedEntityData::TypeChar)0); - setAge(0); -} - -int AgableMob::getAge() { - return age; -} - -void AgableMob::setAge( int age ) { - if (this->age < 0 && age >= 0) { - entityData.clearFlag(DATA_FLAGS_ID, DATAFLAG_ISBABY); - } - else if (this->age >= 0 && age < 0) { - entityData.setFlag(DATA_FLAGS_ID, DATAFLAG_ISBABY); - } - this->age = age; -} - -void AgableMob::addAdditonalSaveData( CompoundTag* tag ) { - super::addAdditonalSaveData(tag); - tag->putInt("Age", getAge()); -} - -void AgableMob::readAdditionalSaveData( CompoundTag* tag ) { - super::readAdditionalSaveData(tag); - setAge(tag->getInt("Age")); -} - -void AgableMob::aiStep() { - super::aiStep(); - - //@note: keeping this for now, since we don't use breeding anyway - // and it feels better to have animals at age 0 then 99999999 - // if we decide to actually use it. - if (age < 0) - setAge(age + 1); - else if (age > 0) - setAge(age - 1); -} - -bool AgableMob::isBaby() { - if (!level->isClientSide) { - return age < 0; - } else { - return entityData.getFlag(DATA_FLAGS_ID, DATAFLAG_ISBABY); - } -} +#include "AgableMob.hpp" + +AgableMob::AgableMob( Level* level ) +: super(level), + age(-1) +{ + entityData.define(DATA_FLAGS_ID, (SynchedEntityData::TypeChar)0); + setAge(0); +} + +int AgableMob::getAge() { + return age; +} + +void AgableMob::setAge( int age ) { + if (this->age < 0 && age >= 0) { + entityData.clearFlag(DATA_FLAGS_ID, DATAFLAG_ISBABY); + } + else if (this->age >= 0 && age < 0) { + entityData.setFlag(DATA_FLAGS_ID, DATAFLAG_ISBABY); + } + this->age = age; +} + +void AgableMob::addAdditonalSaveData( CompoundTag* tag ) { + super::addAdditonalSaveData(tag); + tag->putInt("Age", getAge()); +} + +void AgableMob::readAdditionalSaveData( CompoundTag* tag ) { + super::readAdditionalSaveData(tag); + setAge(tag->getInt("Age")); +} + +void AgableMob::aiStep() { + super::aiStep(); + + //@note: keeping this for now, since we don't use breeding anyway + // and it feels better to have animals at age 0 then 99999999 + // if we decide to actually use it. + if (age < 0) + setAge(age + 1); + else if (age > 0) + setAge(age - 1); +} + +bool AgableMob::isBaby() { + if (!level->isClientSide) { + return age < 0; + } else { + return entityData.getFlag(DATA_FLAGS_ID, DATAFLAG_ISBABY); + } +} diff --git a/src/world/entity/AgableMob.h b/src/world/entity/AgableMob.hpp similarity index 94% rename from src/world/entity/AgableMob.h rename to src/world/entity/AgableMob.hpp index 958ad96..06e3886 100755 --- a/src/world/entity/AgableMob.h +++ b/src/world/entity/AgableMob.hpp @@ -1,6 +1,6 @@ #pragma once -#include "PathfinderMob.h" +#include "PathfinderMob.hpp" //package net.minecraft.world.entity; diff --git a/src/world/entity/Creature.h b/src/world/entity/Creature.hpp similarity index 100% rename from src/world/entity/Creature.h rename to src/world/entity/Creature.hpp diff --git a/src/world/entity/Entity.cpp b/src/world/entity/Entity.cpp index bfccad7..22134f5 100755 --- a/src/world/entity/Entity.cpp +++ b/src/world/entity/Entity.cpp @@ -1,963 +1,963 @@ -#include "Entity.h" -#include "EntityPos.h" -#include "../level/Level.h" -#include "../level/tile/LiquidTile.h" -#include "item/ItemEntity.h" -#include "../item/ItemInstance.h" -#include "../../nbt/CompoundTag.h" -#include "../../util/PerfTimer.h" - -int - Entity::entityCounter = 0; -Random - Entity::sharedRandom(getEpochTimeS()); - -Entity::Entity( Level* level ) -: level(level), - viewScale(1.0f), - blocksBuilding(false), - onGround(false), - wasInWater(false), - collision(false), - hurtMarked(false), - slide(true), - isStuckInWeb(false), - removed(false), - reallyRemoveIfPlayer(false), - canRemove(true), //@todo: remove - noPhysics(false), - firstTick(true), - - bbWidth(0.6f), - bbHeight(1.8f), - heightOffset(0 / 16.0f), - bb(0,0,0,0,0,0), - - ySlideOffset(0), - fallDistance(0), - footSize(0), - invulnerableTime(0), - pushthrough(0), - airCapacity(TOTAL_AIR_SUPPLY), - airSupply(TOTAL_AIR_SUPPLY), - - xOld(0),yOld(0),zOld(0), - horizontalCollision(false), verticalCollision(false), - - x(0), y(0), z(0), - xo(0),yo(0),zo(0),xd(0),yd(0),zd(0), - xRot(0), yRot(0), - xRotO(0), yRotO(0), - - xChunk(0), yChunk(0), zChunk(0), - inChunk(false), - - fireImmune(false), - onFire(0), - flameTime(1), - walkDist(0), walkDistO(0), - tickCount(0), - entityRendererId(ER_DEFAULT_RENDERER), - nextStep(1), - makeStepSound(true), - invisible(false) -{ - _init(); - - entityId = ++entityCounter; - - //ref = Ref::create(this); - - setPos(0, 0, 0); -} - -Entity::~Entity() { - //if (ref->isUnique()) - // delete ref; -} - -SynchedEntityData* Entity::getEntityData() { - return NULL; -} -const SynchedEntityData* Entity::getEntityData() const { - return NULL; -} - -bool Entity::isInWall() { - int xt = Mth::floor(x); - int yt = Mth::floor(y + getHeadHeight()); - int zt = Mth::floor(z); - return level->isSolidBlockingTile(xt, yt, zt); -} - -void Entity::resetPos(bool clearMore) { - if (level == NULL) return; - while (y > 0) { - setPos(x, y, z); - if (level->getCubes(this, bb).size() == 0) break; - y += 1; - } - - xd = yd = zd = 0; - xRot = 0; -} - -bool Entity::isInWater() { - return level->checkAndHandleWater(bb.grow(0, -0.4f, 0), Material::water, this); -} - -bool Entity::isInLava() { - return level->containsMaterial(bb.grow(-0.1f, -0.4f, -0.1f), Material::lava); -} - -bool Entity::isFree(float xa, float ya, float za, float grow) { - AABB box = bb.grow(grow, grow, grow).cloneMove(xa, ya, za); - const std::vector& aABBs = level->getCubes(this, box); - if (aABBs.size() > 0) return false; - if (level->containsAnyLiquid(box)) return false; - return true; -} - -bool Entity::isFree(float xa, float ya, float za) { - AABB box = bb.cloneMove(xa, ya, za); - const std::vector& aABBs = level->getCubes(this, box); - if (aABBs.size() > 0) return false; - if (level->containsAnyLiquid(box)) return false; - return true; -} - -//static void __attribute__((noinline)) setPositionFromBbox(Entity* e) { // @RPI -// const AABB& bb = e->bb; -// e->x = (e->bb.x0 + e->bb.x1) / 2.0f; -// e->y = bb.y0 + e->heightOffset - e->ySlideOffset; -// e->z = (bb.z0 + bb.z1) / 2.0f; -//} - -/*public*/ -void Entity::move(float xa, float ya, float za) { - //if (std::abs(xa) + std::abs(ya) + std::abs(za) < 0.00001f) //@RPI - // return; - - if (noPhysics) { - bb.move(xa, ya, za); - x = (bb.x0 + bb.x1) / 2.0f; - y = bb.y0 + heightOffset - ySlideOffset; - z = (bb.z0 + bb.z1) / 2.0f; - return; - } - - TIMER_PUSH("move"); - - float xo = x; - float zo = z; - - if (isStuckInWeb) { - isStuckInWeb = false; - - xa *= .25f; - ya *= .05f; - za *= .25f; - xd = .0f; - yd = .0f; - zd = .0f; - } - - float xaOrg = xa; - float yaOrg = ya; - float zaOrg = za; - - AABB bbOrg = bb; - - bool sneaking = onGround && isSneaking(); - - if (sneaking) { - float d = 0.05f; - while (xa != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, 0)).empty()) { - if (xa < d && xa >= -d) xa = 0; - else if (xa > 0) xa -= d; - else xa += d; - xaOrg = xa; - } - while (za != 0 && level->getCubes(this, bb.cloneMove(0, -1.0, za)).empty()) { - if (za < d && za >= -d) za = 0; - else if (za > 0) za -= d; - else za += d; - zaOrg = za; - } - - while (xa != 0 && za != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, za)).empty()) { - if (xa < d && xa >= -d) xa = 0; - else if (xa > 0) xa -= d; - else xa += d; - if (za < d && za >= -d) za = 0; - else if (za > 0) za -= d; - else za += d; - xaOrg = xa; - zaOrg = za; - } - - } - - std::vector& aABBs = level->getCubes(this, bb.expand(xa, ya, za)); - - // LAND FIRST, then x and z - for (unsigned int i = 0; i < aABBs.size(); i++) - ya = aABBs[i].clipYCollide(bb, ya); - bb.move(0, ya, 0); - - if (!slide && yaOrg != ya) { - xa = ya = za = 0; - } - - bool og = onGround || (yaOrg != ya && yaOrg < 0); - - for (unsigned int i = 0; i < aABBs.size(); i++) - xa = aABBs[i].clipXCollide(bb, xa); - - bb.move(xa, 0, 0); - - if (!slide && xaOrg != xa) { - xa = ya = za = 0; - } - - for (unsigned int i = 0; i < aABBs.size(); i++) - za = aABBs[i].clipZCollide(bb, za); - bb.move(0, 0, za); - - if (!slide && zaOrg != za) { - xa = ya = za = 0; - } - - if (footSize > 0 && og && (ySlideOffset < 0.05f) && ((xaOrg != xa) || (zaOrg != za))) { - - float xaN = xa; - float yaN = ya; - float zaN = za; - - xa = xaOrg; - ya = footSize; - za = zaOrg; - - AABB normal = bb; - bb.set(bbOrg); - aABBs = level->getCubes(this, bb.expand(xa, ya, za)); - - // LAND FIRST, then x and z - for (unsigned int i = 0; i < aABBs.size(); i++) - ya = aABBs[i].clipYCollide(bb, ya); - bb.move(0, ya, 0); - - if (!slide && yaOrg != ya) { - xa = ya = za = 0; - } - - for (unsigned int i = 0; i < aABBs.size(); i++) - xa = aABBs[i].clipXCollide(bb, xa); - bb.move(xa, 0, 0); - - if (!slide && xaOrg != xa) { - xa = ya = za = 0; - } - - for (unsigned int i = 0; i < aABBs.size(); i++) - za = aABBs[i].clipZCollide(bb, za); - bb.move(0, 0, za); - - if (!slide && zaOrg != za) { - xa = ya = za = 0; - } - - if (xaN * xaN + zaN * zaN >= xa * xa + za * za) { - xa = xaN; - ya = yaN; - za = zaN; - bb.set(normal); - } else { - ySlideOffset += 0.5f; - } - } - - TIMER_POP_PUSH("rest"); - - x = (bb.x0 + bb.x1) / 2.0f; - y = bb.y0 + heightOffset - ySlideOffset; - z = (bb.z0 + bb.z1) / 2.0f; - - horizontalCollision = (xaOrg != xa) || (zaOrg != za); - verticalCollision = (yaOrg != ya); - onGround = yaOrg != ya && yaOrg < 0; - collision = horizontalCollision || verticalCollision; - checkFallDamage(ya, onGround); - - if (xaOrg != xa) xd = 0; - if (yaOrg != ya) yd = 0; - if (zaOrg != za) zd = 0; - - float xm = x - xo; - float zm = z - zo; - - if (makeStepSound && !sneaking) { - walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6f; - int xt = Mth::floor(x); - int yt = Mth::floor(y - 0.2f - this->heightOffset); - int zt = Mth::floor(z); - - int t = level->getTile(xt, yt, zt); - if (t == 0) { - int under = level->getTile(xt, yt-1, zt); - if (Tile::fence->id == under || Tile::fenceGate->id == under) { - t = under; - } - } - - if (walkDist > nextStep && t > 0) { - nextStep = ((int) walkDist) + 1; - playStepSound(xt, yt, zt, t); - //Tile::tiles[t]->stepOn(level, xt, yt, zt, this); //@todo: step - } - } - - int x0 = Mth::floor(bb.x0); - int y0 = Mth::floor(bb.y0); - int z0 = Mth::floor(bb.z0); - int x1 = Mth::floor(bb.x1); - int y1 = Mth::floor(bb.y1); - int z1 = Mth::floor(bb.z1); - - if (level->hasChunksAt(x0, y0, z0, x1, y1, z1)) { - for (int x = x0; x <= x1; x++) - for (int y = y0; y <= y1; y++) - for (int z = z0; z <= z1; z++) { - int t = level->getTile(x, y, z); - if (t > 0) { - Tile::tiles[t]->entityInside(level, x, y, z, this); - } - } - } - - ySlideOffset *= 0.4f; - - bool water = this->isInWater(); - if (level->containsFireTile(bb)) { - burn(1); - if (!water) { - onFire++; - if (onFire == 0) onFire = 20 * 15; - } - } else { - if (onFire <= 0) { - onFire = -flameTime; - } - } - - if (water && onFire > 0) { - //level.playSound(this-> "random.fizz", 0.7f, 1.6f + (random.nextFloat() - random.nextFloat()) * 0.4f); - onFire = -flameTime; - } - - TIMER_POP(); -} - -void Entity::makeStuckInWeb() { - isStuckInWeb = true; - fallDistance = 0; -} - -/*public virtual*/ -bool Entity::isUnderLiquid(const Material* material) { - float yp = y + getHeadHeight(); - int xt = Mth::floor(x); - int yt = Mth::floor((float)Mth::floor(yp)); - int zt = Mth::floor(z); - int t = level->getTile(xt, yt, zt); - if (t != 0 && Tile::tiles[t]->material == material) { - float hh = LiquidTile::getHeight(level->getData(xt, yt, zt)) - 1 / 9.0f; - float h = yt + 1 - hh; - return yp < h; - } - return false; -} - -/*protected virtual*/ -void Entity::setPos(EntityPos* pos) -{ - if (pos->move) setPos(pos->x, pos->y, pos->z); - else setPos(x, y, z); - - if (pos->rot) setRot(pos->yRot, pos->xRot); - else setRot(yRot, xRot); -} - -void Entity::setPos( float x, float y, float z ) -{ - this->x = x; - this->y = y; - this->z = z; - float w = bbWidth / 2; - float h = bbHeight; - bb.set(x - w, y - heightOffset + ySlideOffset, z - w, x + w, y - heightOffset + ySlideOffset + h, z + w); -} - -/*virtual*/ -float Entity::getBrightness(float a) { - int xTile = Mth::floor(x); - - float hh = (bb.y1 - bb.y0) * 0.66f; - int yTile = Mth::floor(y - this->heightOffset + hh); - int zTile = Mth::floor(z); - if (level->hasChunksAt(Mth::floor(bb.x0), Mth::floor(bb.y0), Mth::floor(bb.z0), Mth::floor(bb.x1), Mth::floor(bb.y1), Mth::floor(bb.z1))) { - return level->getBrightness(xTile, yTile, zTile); - } - return 0; -} - -bool Entity::operator==( Entity& rhs ) -{ - return entityId == rhs.entityId; -} - -int Entity::hashCode() -{ - return entityId; -} - -void Entity::remove() -{ - removed = true; -} - -void Entity::setSize( float w, float h ) -{ - bbWidth = w; - bbHeight = h; -} - -void Entity::setRot( float yRot, float xRot ) -{ - this->yRot = yRotO = yRot; - this->xRot = xRotO = xRot; -} - -void Entity::turn( float xo, float yo ) -{ - float xRotOld = xRot; - float yRotOld = yRot; - - yRot += xo * 0.15f; - xRot -= yo * 0.15f; - if (xRot < -90) xRot = -90; - if (xRot > 90) xRot = 90; - - xRotO += xRot - xRotOld; - yRotO += yRot - yRotOld; -} - -void Entity::interpolateTurn( float xo, float yo ) -{ - yRot += xo * 0.15f; - xRot -= yo * 0.15f; - if (xRot < -90) xRot = -90; - if (xRot > 90) xRot = 90; -} - -void Entity::tick() -{ - baseTick(); -} - -void Entity::baseTick() -{ - TIMER_PUSH("entityBaseTick"); - - tickCount++; - walkDistO = walkDist; - xo = x; - yo = y; - zo = z; - xRotO = xRot; - yRotO = yRot; - - if (isInWater()) { - if (!wasInWater && !firstTick) { - float speed = sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f; - if (speed > 1) speed = 1; - level->playSound(this, "random.splash", speed, 1 + (sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.4f); - float yt = floorf(bb.y0); - for (int i = 0; i < 1 + bbWidth * 20; i++) { - float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; - float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; - level->addParticle(PARTICLETYPE(bubble), x + xo, yt + 1, z + zo, xd, yd - sharedRandom.nextFloat() * 0.2f, zd); - } - //for (int i = 0; i < 1 + bbWidth * 20; i++) { - // float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; - // float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; - // level->addParticle(PARTICLETYPE(splash), x + xo, yt + 1, z + zo, xd, yd, zd); - //} - } - fallDistance = 0; - wasInWater = true; - onFire = 0; - } else { - wasInWater = false; - } - - if (level->isClientSide) { - onFire = 0; - } else { - if (onFire > 0) { - if (fireImmune) { - onFire -= 4; - if (onFire < 0) onFire = 0; - } else { - if (onFire % 20 == 0) { - hurt(NULL, 1); - } - onFire--; - } - } - } - - if (isInLava()) { - lavaHurt(); - } - - if (y < -64) { - outOfWorld(); - } - - //if (!level->isOnline) { - // setSharedFlag(FLAG_ONFIRE, onFire > 0); - //} - - firstTick = false; - TIMER_POP(); -} - -void Entity::outOfWorld() -{ - remove(); -} - -void Entity::checkFallDamage( float ya, bool onGround ) -{ - if (onGround) { - if (fallDistance > 0) { - if(isMob()) { - int xt = Mth::floor(x); - int yt = Mth::floor(y - 0.2f - heightOffset); - int zt = Mth::floor(z); - int t = level->getTile(xt, yt, zt); - if (t == 0 && level->getTile(xt, yt - 1, zt) == Tile::fence->id) { - t = level->getTile(xt, yt - 1, zt); - } - - if (t > 0) { - Tile::tiles[t]->fallOn(level, xt, yt, zt, this, fallDistance); - } - } - causeFallDamage(fallDistance); - fallDistance = 0; - } - } else { - if (ya < 0) fallDistance -= ya; - } -} - -void Entity::causeFallDamage( float fallDamage2 ) -{ -} - -float Entity::getHeadHeight() -{ - return 0; -} - -void Entity::moveRelative( float xa, float za, float speed ) -{ - float dist = sqrt(xa * xa + za * za); - if (dist < 0.01f) return; - - if (dist < 1) dist = 1; - dist = speed / dist; - xa *= dist; - za *= dist; - - float sin_ = (float) sin(yRot * Mth::PI / 180); - float cos_ = (float) cos(yRot * Mth::PI / 180); - - xd += xa * cos_ - za * sin_; - zd += za * cos_ + xa * sin_; -} - -void Entity::setLevel( Level* level ) -{ - this->level = level; -} - -void Entity::moveTo( float x, float y, float z, float yRot, float xRot ) -{ - this->xOld = this->xo = this->x = x; - this->yOld = this->yo = this->y = y + heightOffset; - this->zOld = this->zo = this->z = z; - this->yRot = this->yRotO = yRot; - this->xRot = this->xRotO = xRot; - this->setPos(this->x, this->y, this->z); -} - -float Entity::distanceTo( Entity* e ) -{ - float xd = (float) (x - e->x); - float yd = (float) (y - e->y); - float zd = (float) (z - e->z); - return sqrt(xd * xd + yd * yd + zd * zd); -} - -float Entity::distanceTo( float x2, float y2, float z2 ) -{ - float xd = (x - x2); - float yd = (y - y2); - float zd = (z - z2); - return sqrt(xd * xd + yd * yd + zd * zd); -} - -float Entity::distanceToSqr( float x2, float y2, float z2 ) -{ - float xd = (x - x2); - float yd = (y - y2); - float zd = (z - z2); - return xd * xd + yd * yd + zd * zd; -} - -float Entity::distanceToSqr( Entity* e ) -{ - float xd = x - e->x; - float yd = y - e->y; - float zd = z - e->z; - return xd * xd + yd * yd + zd * zd; -} - -void Entity::playerTouch( Player* player ) -{ -} - -void Entity::push( Entity* e ) -{ - float xa = e->x - x; - float za = e->z - z; - - float dd = Mth::absMax(xa, za); - - if (dd >= 0.01f) { - dd = sqrt(dd); - xa /= dd; - za /= dd; - - float pow = 1 / dd; - if (pow > 1) pow = 1; - xa *= pow; - za *= pow; - - xa *= 0.05f; - za *= 0.05f; - - xa *= 1 - pushthrough; - za *= 1 - pushthrough; - - this->push(-xa, 0, -za); - e->push(xa, 0, za); - } -} - -void Entity::push( float xa, float ya, float za ) -{ - xd += xa; - yd += ya; - zd += za; -} - -void Entity::markHurt() -{ - this->hurtMarked = true; -} - -bool Entity::hurt( Entity* source, int damage ) -{ - markHurt(); - return false; -} - -void Entity::reset() { - this->_init(); -} -void Entity::_init() { - xo = xOld = x; - yo = yOld = y; - zo = zOld = z; - xRotO = xRot; - yRotO = yRot; - onFire = 0; - removed = false; - fallDistance = 0; -} - -bool Entity::intersects( float x0, float y0, float z0, float x1, float y1, float z1 ) -{ - return bb.intersects(x0, y0, z0, x1, y1, z1); -} - -bool Entity::isPickable() -{ - return false; -} - -bool Entity::isPushable() -{ - return false; -} - -bool Entity::isShootable() -{ - return false; -} - -void Entity::awardKillScore( Entity* victim, int score ) -{ -} - -bool Entity::shouldRender( Vec3& c ) -{ - if (invisible) return false; - float xd = x - c.x; - float yd = y - c.y; - float zd = z - c.z; - float distance = xd * xd + yd * yd + zd * zd; - return shouldRenderAtSqrDistance(distance); -} - -bool Entity::shouldRenderAtSqrDistance( float distance ) -{ - float size = bb.getSize(); - size *= 64.0f * viewScale; - return distance < size * size; -} - -bool Entity::isCreativeModeAllowed() -{ - return false; -} - -float Entity::getShadowHeightOffs() -{ - return bbHeight / 2; -} - -bool Entity::isAlive() -{ - return !removed; -} - -bool Entity::interact( Player* player ) -{ - return false; -} - -void Entity::lerpTo( float x, float y, float z, float yRot, float xRot, int steps ) -{ - setPos(x, y, z); - setRot(yRot, xRot); -} - -float Entity::getPickRadius() -{ - return 0.1f; -} - -void Entity::lerpMotion( float xd, float yd, float zd ) -{ - this->xd = xd; - this->yd = yd; - this->zd = zd; -} - -void Entity::animateHurt() -{ -} - -void Entity::setEquippedSlot( int slot, int item, int auxValue ) -{ -} - -bool Entity::isSneaking() -{ - return false; -} - -bool Entity::isPlayer() -{ - return false; -} - - -void Entity::lavaHurt() { - if (fireImmune) { - } else { - hurt(NULL, 4); - onFire = 30 * SharedConstants::TicksPerSecond; - } -} - -// AABB getCollideBox() { -// return NULL; -// } - -void Entity::burn(int dmg) { - if (!fireImmune) { - hurt(NULL, dmg); - } -} - -// std::string getTexture() { -// return NULL; -// } - -bool Entity::save(CompoundTag* entityTag) { - int id = getEntityTypeId(); - - if (removed || id == 0) { - return false; - } - entityTag->putInt("id", id); - saveWithoutId(entityTag); - return true; -} - -void Entity::saveWithoutId(CompoundTag* entityTag) { - entityTag->put("Pos", ListTagFloatAdder (x) (y) (z).tag); - entityTag->put("Motion", ListTagFloatAdder (xd) (yd) (zd).tag); - entityTag->put("Rotation", ListTagFloatAdder (yRot) (xRot).tag); - - entityTag->putFloat("FallDistance", fallDistance); - entityTag->putShort("Fire", (short) onFire); - entityTag->putShort("Air", (short) airSupply); - entityTag->putBoolean("OnGround", onGround); - - addAdditonalSaveData(entityTag); -} - -bool Entity::load( CompoundTag* tag ) -{ - ListTag* pos = tag->getList("Pos"); - ListTag* motion = tag->getList("Motion"); - ListTag* rotation = tag->getList("Rotation"); - setPos(0, 0, 0); - - xd = motion->getFloat(0); - yd = motion->getFloat(1); - zd = motion->getFloat(2); - - if (Mth::abs(xd) > 10.0) { - xd = 0; - } - if (Mth::abs(yd) > 10.0) { - yd = 0; - } - if (Mth::abs(zd) > 10.0) { - zd = 0; - } - - float xx = pos->getFloat(0); - float yy = pos->getFloat(1); - float zz = pos->getFloat(2); - - // Add a small padding if standing next to the world edges - const float padding = bbWidth * 0.5f + 0.001f; - xx = Mth::clamp(xx, padding, (float)LEVEL_WIDTH - padding); - zz = Mth::clamp(zz, padding, (float)LEVEL_DEPTH - padding); - - xo = xOld = x = xx; - yo = yOld = y = yy; - zo = zOld = z = zz; - - yRotO = yRot = fmod( rotation->getFloat(0), 360.0f); - xRotO = xRot = fmod( rotation->getFloat(1), 360.0f); - - fallDistance= tag->getFloat("FallDistance"); - onFire = tag->getShort("Fire"); - airSupply = tag->getShort("Air"); - onGround = tag->getBoolean("OnGround"); - - setPos(x, y, z); - - readAdditionalSaveData(tag); - return (tag->errorState == 0); -} - -// /*protected*/ const String getEncodeId() { -// return EntityIO.getEncodeId(this->; -// } - -ItemEntity* Entity::spawnAtLocation(int resource, int count) { - return spawnAtLocation(resource, count, 0); -} - -ItemEntity* Entity::spawnAtLocation(int resource, int count, float yOffs) { - return spawnAtLocation(new ItemInstance(resource, count, 0), yOffs); -} - -ItemEntity* Entity::spawnAtLocation(ItemInstance* itemInstance, float yOffs) { - ItemEntity* ie = new ItemEntity(level, x, y + yOffs, z, *itemInstance); - - { //@todo:itementity - delete itemInstance; - itemInstance = NULL; - } - - ie->throwTime = 10; - level->addEntity(ie); - return ie; -} - -bool Entity::isOnFire() { - return onFire > 0;// || getSharedFlag(FLAG_ONFIRE); -} - -bool Entity::interactPreventDefault() { - return false; -} - -// AABB getCollideAgainstBox(Entity entity) { -// return NULL; -// } - -// Vec3 getLookAngle() { -// return NULL; -// } - -// void prepareCustomTextures() { -// } - -// ItemInstance[] getEquipmentSlots() { -// return NULL; -// } - -bool Entity::isItemEntity() { - return false; -} - -bool Entity::isHangingEntity() { - return false; -} - -int Entity::getAuxData() { - return 0; -} - -void Entity::playStepSound( int xt, int yt, int zt, int t ) { - const Tile::SoundType* soundType = Tile::tiles[t]->soundType; - if (level->getTile(xt, yt + 1, zt) == Tile::topSnow->id) { - soundType = Tile::topSnow->soundType; - level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch()); // was * 0.15f - } else if (!Tile::tiles[t]->material->isLiquid()) { - level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch()); - } -} +#include "Entity.hpp" +#include "EntityPos.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/LiquidTile.hpp" +#include "item/ItemEntity.hpp" +#include "world/item/ItemInstance.hpp" +#include "nbt/CompoundTag.hpp" +#include "util/PerfTimer.hpp" + +int + Entity::entityCounter = 0; +Random + Entity::sharedRandom(getEpochTimeS()); + +Entity::Entity( Level* level ) +: level(level), + viewScale(1.0f), + blocksBuilding(false), + onGround(false), + wasInWater(false), + collision(false), + hurtMarked(false), + slide(true), + isStuckInWeb(false), + removed(false), + reallyRemoveIfPlayer(false), + canRemove(true), //@todo: remove + noPhysics(false), + firstTick(true), + + bbWidth(0.6f), + bbHeight(1.8f), + heightOffset(0 / 16.0f), + bb(0,0,0,0,0,0), + + ySlideOffset(0), + fallDistance(0), + footSize(0), + invulnerableTime(0), + pushthrough(0), + airCapacity(TOTAL_AIR_SUPPLY), + airSupply(TOTAL_AIR_SUPPLY), + + xOld(0),yOld(0),zOld(0), + horizontalCollision(false), verticalCollision(false), + + x(0), y(0), z(0), + xo(0),yo(0),zo(0),xd(0),yd(0),zd(0), + xRot(0), yRot(0), + xRotO(0), yRotO(0), + + xChunk(0), yChunk(0), zChunk(0), + inChunk(false), + + fireImmune(false), + onFire(0), + flameTime(1), + walkDist(0), walkDistO(0), + tickCount(0), + entityRendererId(ER_DEFAULT_RENDERER), + nextStep(1), + makeStepSound(true), + invisible(false) +{ + _init(); + + entityId = ++entityCounter; + + //ref = Ref::create(this); + + setPos(0, 0, 0); +} + +Entity::~Entity() { + //if (ref->isUnique()) + // delete ref; +} + +SynchedEntityData* Entity::getEntityData() { + return NULL; +} +const SynchedEntityData* Entity::getEntityData() const { + return NULL; +} + +bool Entity::isInWall() { + int xt = Mth::floor(x); + int yt = Mth::floor(y + getHeadHeight()); + int zt = Mth::floor(z); + return level->isSolidBlockingTile(xt, yt, zt); +} + +void Entity::resetPos(bool clearMore) { + if (level == NULL) return; + while (y > 0) { + setPos(x, y, z); + if (level->getCubes(this, bb).size() == 0) break; + y += 1; + } + + xd = yd = zd = 0; + xRot = 0; +} + +bool Entity::isInWater() { + return level->checkAndHandleWater(bb.grow(0, -0.4f, 0), Material::water, this); +} + +bool Entity::isInLava() { + return level->containsMaterial(bb.grow(-0.1f, -0.4f, -0.1f), Material::lava); +} + +bool Entity::isFree(float xa, float ya, float za, float grow) { + AABB box = bb.grow(grow, grow, grow).cloneMove(xa, ya, za); + const std::vector& aABBs = level->getCubes(this, box); + if (aABBs.size() > 0) return false; + if (level->containsAnyLiquid(box)) return false; + return true; +} + +bool Entity::isFree(float xa, float ya, float za) { + AABB box = bb.cloneMove(xa, ya, za); + const std::vector& aABBs = level->getCubes(this, box); + if (aABBs.size() > 0) return false; + if (level->containsAnyLiquid(box)) return false; + return true; +} + +//static void __attribute__((noinline)) setPositionFromBbox(Entity* e) { // @RPI +// const AABB& bb = e->bb; +// e->x = (e->bb.x0 + e->bb.x1) / 2.0f; +// e->y = bb.y0 + e->heightOffset - e->ySlideOffset; +// e->z = (bb.z0 + bb.z1) / 2.0f; +//} + +/*public*/ +void Entity::move(float xa, float ya, float za) { + //if (std::abs(xa) + std::abs(ya) + std::abs(za) < 0.00001f) //@RPI + // return; + + if (noPhysics) { + bb.move(xa, ya, za); + x = (bb.x0 + bb.x1) / 2.0f; + y = bb.y0 + heightOffset - ySlideOffset; + z = (bb.z0 + bb.z1) / 2.0f; + return; + } + + TIMER_PUSH("move"); + + float xo = x; + float zo = z; + + if (isStuckInWeb) { + isStuckInWeb = false; + + xa *= .25f; + ya *= .05f; + za *= .25f; + xd = .0f; + yd = .0f; + zd = .0f; + } + + float xaOrg = xa; + float yaOrg = ya; + float zaOrg = za; + + AABB bbOrg = bb; + + bool sneaking = onGround && isSneaking(); + + if (sneaking) { + float d = 0.05f; + while (xa != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, 0)).empty()) { + if (xa < d && xa >= -d) xa = 0; + else if (xa > 0) xa -= d; + else xa += d; + xaOrg = xa; + } + while (za != 0 && level->getCubes(this, bb.cloneMove(0, -1.0, za)).empty()) { + if (za < d && za >= -d) za = 0; + else if (za > 0) za -= d; + else za += d; + zaOrg = za; + } + + while (xa != 0 && za != 0 && level->getCubes(this, bb.cloneMove(xa, -1.0, za)).empty()) { + if (xa < d && xa >= -d) xa = 0; + else if (xa > 0) xa -= d; + else xa += d; + if (za < d && za >= -d) za = 0; + else if (za > 0) za -= d; + else za += d; + xaOrg = xa; + zaOrg = za; + } + + } + + std::vector& aABBs = level->getCubes(this, bb.expand(xa, ya, za)); + + // LAND FIRST, then x and z + for (unsigned int i = 0; i < aABBs.size(); i++) + ya = aABBs[i].clipYCollide(bb, ya); + bb.move(0, ya, 0); + + if (!slide && yaOrg != ya) { + xa = ya = za = 0; + } + + bool og = onGround || (yaOrg != ya && yaOrg < 0); + + for (unsigned int i = 0; i < aABBs.size(); i++) + xa = aABBs[i].clipXCollide(bb, xa); + + bb.move(xa, 0, 0); + + if (!slide && xaOrg != xa) { + xa = ya = za = 0; + } + + for (unsigned int i = 0; i < aABBs.size(); i++) + za = aABBs[i].clipZCollide(bb, za); + bb.move(0, 0, za); + + if (!slide && zaOrg != za) { + xa = ya = za = 0; + } + + if (footSize > 0 && og && (ySlideOffset < 0.05f) && ((xaOrg != xa) || (zaOrg != za))) { + + float xaN = xa; + float yaN = ya; + float zaN = za; + + xa = xaOrg; + ya = footSize; + za = zaOrg; + + AABB normal = bb; + bb.set(bbOrg); + aABBs = level->getCubes(this, bb.expand(xa, ya, za)); + + // LAND FIRST, then x and z + for (unsigned int i = 0; i < aABBs.size(); i++) + ya = aABBs[i].clipYCollide(bb, ya); + bb.move(0, ya, 0); + + if (!slide && yaOrg != ya) { + xa = ya = za = 0; + } + + for (unsigned int i = 0; i < aABBs.size(); i++) + xa = aABBs[i].clipXCollide(bb, xa); + bb.move(xa, 0, 0); + + if (!slide && xaOrg != xa) { + xa = ya = za = 0; + } + + for (unsigned int i = 0; i < aABBs.size(); i++) + za = aABBs[i].clipZCollide(bb, za); + bb.move(0, 0, za); + + if (!slide && zaOrg != za) { + xa = ya = za = 0; + } + + if (xaN * xaN + zaN * zaN >= xa * xa + za * za) { + xa = xaN; + ya = yaN; + za = zaN; + bb.set(normal); + } else { + ySlideOffset += 0.5f; + } + } + + TIMER_POP_PUSH("rest"); + + x = (bb.x0 + bb.x1) / 2.0f; + y = bb.y0 + heightOffset - ySlideOffset; + z = (bb.z0 + bb.z1) / 2.0f; + + horizontalCollision = (xaOrg != xa) || (zaOrg != za); + verticalCollision = (yaOrg != ya); + onGround = yaOrg != ya && yaOrg < 0; + collision = horizontalCollision || verticalCollision; + checkFallDamage(ya, onGround); + + if (xaOrg != xa) xd = 0; + if (yaOrg != ya) yd = 0; + if (zaOrg != za) zd = 0; + + float xm = x - xo; + float zm = z - zo; + + if (makeStepSound && !sneaking) { + walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6f; + int xt = Mth::floor(x); + int yt = Mth::floor(y - 0.2f - this->heightOffset); + int zt = Mth::floor(z); + + int t = level->getTile(xt, yt, zt); + if (t == 0) { + int under = level->getTile(xt, yt-1, zt); + if (Tile::fence->id == under || Tile::fenceGate->id == under) { + t = under; + } + } + + if (walkDist > nextStep && t > 0) { + nextStep = ((int) walkDist) + 1; + playStepSound(xt, yt, zt, t); + //Tile::tiles[t]->stepOn(level, xt, yt, zt, this); //@todo: step + } + } + + int x0 = Mth::floor(bb.x0); + int y0 = Mth::floor(bb.y0); + int z0 = Mth::floor(bb.z0); + int x1 = Mth::floor(bb.x1); + int y1 = Mth::floor(bb.y1); + int z1 = Mth::floor(bb.z1); + + if (level->hasChunksAt(x0, y0, z0, x1, y1, z1)) { + for (int x = x0; x <= x1; x++) + for (int y = y0; y <= y1; y++) + for (int z = z0; z <= z1; z++) { + int t = level->getTile(x, y, z); + if (t > 0) { + Tile::tiles[t]->entityInside(level, x, y, z, this); + } + } + } + + ySlideOffset *= 0.4f; + + bool water = this->isInWater(); + if (level->containsFireTile(bb)) { + burn(1); + if (!water) { + onFire++; + if (onFire == 0) onFire = 20 * 15; + } + } else { + if (onFire <= 0) { + onFire = -flameTime; + } + } + + if (water && onFire > 0) { + //level.playSound(this-> "random.fizz", 0.7f, 1.6f + (random.nextFloat() - random.nextFloat()) * 0.4f); + onFire = -flameTime; + } + + TIMER_POP(); +} + +void Entity::makeStuckInWeb() { + isStuckInWeb = true; + fallDistance = 0; +} + +/*public virtual*/ +bool Entity::isUnderLiquid(const Material* material) { + float yp = y + getHeadHeight(); + int xt = Mth::floor(x); + int yt = Mth::floor((float)Mth::floor(yp)); + int zt = Mth::floor(z); + int t = level->getTile(xt, yt, zt); + if (t != 0 && Tile::tiles[t]->material == material) { + float hh = LiquidTile::getHeight(level->getData(xt, yt, zt)) - 1 / 9.0f; + float h = yt + 1 - hh; + return yp < h; + } + return false; +} + +/*protected virtual*/ +void Entity::setPos(EntityPos* pos) +{ + if (pos->move) setPos(pos->x, pos->y, pos->z); + else setPos(x, y, z); + + if (pos->rot) setRot(pos->yRot, pos->xRot); + else setRot(yRot, xRot); +} + +void Entity::setPos( float x, float y, float z ) +{ + this->x = x; + this->y = y; + this->z = z; + float w = bbWidth / 2; + float h = bbHeight; + bb.set(x - w, y - heightOffset + ySlideOffset, z - w, x + w, y - heightOffset + ySlideOffset + h, z + w); +} + +/*virtual*/ +float Entity::getBrightness(float a) { + int xTile = Mth::floor(x); + + float hh = (bb.y1 - bb.y0) * 0.66f; + int yTile = Mth::floor(y - this->heightOffset + hh); + int zTile = Mth::floor(z); + if (level->hasChunksAt(Mth::floor(bb.x0), Mth::floor(bb.y0), Mth::floor(bb.z0), Mth::floor(bb.x1), Mth::floor(bb.y1), Mth::floor(bb.z1))) { + return level->getBrightness(xTile, yTile, zTile); + } + return 0; +} + +bool Entity::operator==( Entity& rhs ) +{ + return entityId == rhs.entityId; +} + +int Entity::hashCode() +{ + return entityId; +} + +void Entity::remove() +{ + removed = true; +} + +void Entity::setSize( float w, float h ) +{ + bbWidth = w; + bbHeight = h; +} + +void Entity::setRot( float yRot, float xRot ) +{ + this->yRot = yRotO = yRot; + this->xRot = xRotO = xRot; +} + +void Entity::turn( float xo, float yo ) +{ + float xRotOld = xRot; + float yRotOld = yRot; + + yRot += xo * 0.15f; + xRot -= yo * 0.15f; + if (xRot < -90) xRot = -90; + if (xRot > 90) xRot = 90; + + xRotO += xRot - xRotOld; + yRotO += yRot - yRotOld; +} + +void Entity::interpolateTurn( float xo, float yo ) +{ + yRot += xo * 0.15f; + xRot -= yo * 0.15f; + if (xRot < -90) xRot = -90; + if (xRot > 90) xRot = 90; +} + +void Entity::tick() +{ + baseTick(); +} + +void Entity::baseTick() +{ + TIMER_PUSH("entityBaseTick"); + + tickCount++; + walkDistO = walkDist; + xo = x; + yo = y; + zo = z; + xRotO = xRot; + yRotO = yRot; + + if (isInWater()) { + if (!wasInWater && !firstTick) { + float speed = sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f; + if (speed > 1) speed = 1; + level->playSound(this, "random.splash", speed, 1 + (sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.4f); + float yt = floorf(bb.y0); + for (int i = 0; i < 1 + bbWidth * 20; i++) { + float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; + float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; + level->addParticle(PARTICLETYPE(bubble), x + xo, yt + 1, z + zo, xd, yd - sharedRandom.nextFloat() * 0.2f, zd); + } + //for (int i = 0; i < 1 + bbWidth * 20; i++) { + // float xo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; + // float zo = (sharedRandom.nextFloat() * 2 - 1) * bbWidth; + // level->addParticle(PARTICLETYPE(splash), x + xo, yt + 1, z + zo, xd, yd, zd); + //} + } + fallDistance = 0; + wasInWater = true; + onFire = 0; + } else { + wasInWater = false; + } + + if (level->isClientSide) { + onFire = 0; + } else { + if (onFire > 0) { + if (fireImmune) { + onFire -= 4; + if (onFire < 0) onFire = 0; + } else { + if (onFire % 20 == 0) { + hurt(NULL, 1); + } + onFire--; + } + } + } + + if (isInLava()) { + lavaHurt(); + } + + if (y < -64) { + outOfWorld(); + } + + //if (!level->isOnline) { + // setSharedFlag(FLAG_ONFIRE, onFire > 0); + //} + + firstTick = false; + TIMER_POP(); +} + +void Entity::outOfWorld() +{ + remove(); +} + +void Entity::checkFallDamage( float ya, bool onGround ) +{ + if (onGround) { + if (fallDistance > 0) { + if(isMob()) { + int xt = Mth::floor(x); + int yt = Mth::floor(y - 0.2f - heightOffset); + int zt = Mth::floor(z); + int t = level->getTile(xt, yt, zt); + if (t == 0 && level->getTile(xt, yt - 1, zt) == Tile::fence->id) { + t = level->getTile(xt, yt - 1, zt); + } + + if (t > 0) { + Tile::tiles[t]->fallOn(level, xt, yt, zt, this, fallDistance); + } + } + causeFallDamage(fallDistance); + fallDistance = 0; + } + } else { + if (ya < 0) fallDistance -= ya; + } +} + +void Entity::causeFallDamage( float fallDamage2 ) +{ +} + +float Entity::getHeadHeight() +{ + return 0; +} + +void Entity::moveRelative( float xa, float za, float speed ) +{ + float dist = sqrt(xa * xa + za * za); + if (dist < 0.01f) return; + + if (dist < 1) dist = 1; + dist = speed / dist; + xa *= dist; + za *= dist; + + float sin_ = (float) sin(yRot * Mth::PI / 180); + float cos_ = (float) cos(yRot * Mth::PI / 180); + + xd += xa * cos_ - za * sin_; + zd += za * cos_ + xa * sin_; +} + +void Entity::setLevel( Level* level ) +{ + this->level = level; +} + +void Entity::moveTo( float x, float y, float z, float yRot, float xRot ) +{ + this->xOld = this->xo = this->x = x; + this->yOld = this->yo = this->y = y + heightOffset; + this->zOld = this->zo = this->z = z; + this->yRot = this->yRotO = yRot; + this->xRot = this->xRotO = xRot; + this->setPos(this->x, this->y, this->z); +} + +float Entity::distanceTo( Entity* e ) +{ + float xd = (float) (x - e->x); + float yd = (float) (y - e->y); + float zd = (float) (z - e->z); + return sqrt(xd * xd + yd * yd + zd * zd); +} + +float Entity::distanceTo( float x2, float y2, float z2 ) +{ + float xd = (x - x2); + float yd = (y - y2); + float zd = (z - z2); + return sqrt(xd * xd + yd * yd + zd * zd); +} + +float Entity::distanceToSqr( float x2, float y2, float z2 ) +{ + float xd = (x - x2); + float yd = (y - y2); + float zd = (z - z2); + return xd * xd + yd * yd + zd * zd; +} + +float Entity::distanceToSqr( Entity* e ) +{ + float xd = x - e->x; + float yd = y - e->y; + float zd = z - e->z; + return xd * xd + yd * yd + zd * zd; +} + +void Entity::playerTouch( Player* player ) +{ +} + +void Entity::push( Entity* e ) +{ + float xa = e->x - x; + float za = e->z - z; + + float dd = Mth::absMax(xa, za); + + if (dd >= 0.01f) { + dd = sqrt(dd); + xa /= dd; + za /= dd; + + float pow = 1 / dd; + if (pow > 1) pow = 1; + xa *= pow; + za *= pow; + + xa *= 0.05f; + za *= 0.05f; + + xa *= 1 - pushthrough; + za *= 1 - pushthrough; + + this->push(-xa, 0, -za); + e->push(xa, 0, za); + } +} + +void Entity::push( float xa, float ya, float za ) +{ + xd += xa; + yd += ya; + zd += za; +} + +void Entity::markHurt() +{ + this->hurtMarked = true; +} + +bool Entity::hurt( Entity* source, int damage ) +{ + markHurt(); + return false; +} + +void Entity::reset() { + this->_init(); +} +void Entity::_init() { + xo = xOld = x; + yo = yOld = y; + zo = zOld = z; + xRotO = xRot; + yRotO = yRot; + onFire = 0; + removed = false; + fallDistance = 0; +} + +bool Entity::intersects( float x0, float y0, float z0, float x1, float y1, float z1 ) +{ + return bb.intersects(x0, y0, z0, x1, y1, z1); +} + +bool Entity::isPickable() +{ + return false; +} + +bool Entity::isPushable() +{ + return false; +} + +bool Entity::isShootable() +{ + return false; +} + +void Entity::awardKillScore( Entity* victim, int score ) +{ +} + +bool Entity::shouldRender( Vec3& c ) +{ + if (invisible) return false; + float xd = x - c.x; + float yd = y - c.y; + float zd = z - c.z; + float distance = xd * xd + yd * yd + zd * zd; + return shouldRenderAtSqrDistance(distance); +} + +bool Entity::shouldRenderAtSqrDistance( float distance ) +{ + float size = bb.getSize(); + size *= 64.0f * viewScale; + return distance < size * size; +} + +bool Entity::isCreativeModeAllowed() +{ + return false; +} + +float Entity::getShadowHeightOffs() +{ + return bbHeight / 2; +} + +bool Entity::isAlive() +{ + return !removed; +} + +bool Entity::interact( Player* player ) +{ + return false; +} + +void Entity::lerpTo( float x, float y, float z, float yRot, float xRot, int steps ) +{ + setPos(x, y, z); + setRot(yRot, xRot); +} + +float Entity::getPickRadius() +{ + return 0.1f; +} + +void Entity::lerpMotion( float xd, float yd, float zd ) +{ + this->xd = xd; + this->yd = yd; + this->zd = zd; +} + +void Entity::animateHurt() +{ +} + +void Entity::setEquippedSlot( int slot, int item, int auxValue ) +{ +} + +bool Entity::isSneaking() +{ + return false; +} + +bool Entity::isPlayer() +{ + return false; +} + + +void Entity::lavaHurt() { + if (fireImmune) { + } else { + hurt(NULL, 4); + onFire = 30 * SharedConstants::TicksPerSecond; + } +} + +// AABB getCollideBox() { +// return NULL; +// } + +void Entity::burn(int dmg) { + if (!fireImmune) { + hurt(NULL, dmg); + } +} + +// std::string getTexture() { +// return NULL; +// } + +bool Entity::save(CompoundTag* entityTag) { + int id = getEntityTypeId(); + + if (removed || id == 0) { + return false; + } + entityTag->putInt("id", id); + saveWithoutId(entityTag); + return true; +} + +void Entity::saveWithoutId(CompoundTag* entityTag) { + entityTag->put("Pos", ListTagFloatAdder (x) (y) (z).tag); + entityTag->put("Motion", ListTagFloatAdder (xd) (yd) (zd).tag); + entityTag->put("Rotation", ListTagFloatAdder (yRot) (xRot).tag); + + entityTag->putFloat("FallDistance", fallDistance); + entityTag->putShort("Fire", (short) onFire); + entityTag->putShort("Air", (short) airSupply); + entityTag->putBoolean("OnGround", onGround); + + addAdditonalSaveData(entityTag); +} + +bool Entity::load( CompoundTag* tag ) +{ + ListTag* pos = tag->getList("Pos"); + ListTag* motion = tag->getList("Motion"); + ListTag* rotation = tag->getList("Rotation"); + setPos(0, 0, 0); + + xd = motion->getFloat(0); + yd = motion->getFloat(1); + zd = motion->getFloat(2); + + if (Mth::abs(xd) > 10.0) { + xd = 0; + } + if (Mth::abs(yd) > 10.0) { + yd = 0; + } + if (Mth::abs(zd) > 10.0) { + zd = 0; + } + + float xx = pos->getFloat(0); + float yy = pos->getFloat(1); + float zz = pos->getFloat(2); + + // Add a small padding if standing next to the world edges + const float padding = bbWidth * 0.5f + 0.001f; + xx = Mth::clamp(xx, padding, (float)LEVEL_WIDTH - padding); + zz = Mth::clamp(zz, padding, (float)LEVEL_DEPTH - padding); + + xo = xOld = x = xx; + yo = yOld = y = yy; + zo = zOld = z = zz; + + yRotO = yRot = fmod( rotation->getFloat(0), 360.0f); + xRotO = xRot = fmod( rotation->getFloat(1), 360.0f); + + fallDistance= tag->getFloat("FallDistance"); + onFire = tag->getShort("Fire"); + airSupply = tag->getShort("Air"); + onGround = tag->getBoolean("OnGround"); + + setPos(x, y, z); + + readAdditionalSaveData(tag); + return (tag->errorState == 0); +} + +// /*protected*/ const String getEncodeId() { +// return EntityIO.getEncodeId(this->; +// } + +ItemEntity* Entity::spawnAtLocation(int resource, int count) { + return spawnAtLocation(resource, count, 0); +} + +ItemEntity* Entity::spawnAtLocation(int resource, int count, float yOffs) { + return spawnAtLocation(new ItemInstance(resource, count, 0), yOffs); +} + +ItemEntity* Entity::spawnAtLocation(ItemInstance* itemInstance, float yOffs) { + ItemEntity* ie = new ItemEntity(level, x, y + yOffs, z, *itemInstance); + + { //@todo:itementity + delete itemInstance; + itemInstance = NULL; + } + + ie->throwTime = 10; + level->addEntity(ie); + return ie; +} + +bool Entity::isOnFire() { + return onFire > 0;// || getSharedFlag(FLAG_ONFIRE); +} + +bool Entity::interactPreventDefault() { + return false; +} + +// AABB getCollideAgainstBox(Entity entity) { +// return NULL; +// } + +// Vec3 getLookAngle() { +// return NULL; +// } + +// void prepareCustomTextures() { +// } + +// ItemInstance[] getEquipmentSlots() { +// return NULL; +// } + +bool Entity::isItemEntity() { + return false; +} + +bool Entity::isHangingEntity() { + return false; +} + +int Entity::getAuxData() { + return 0; +} + +void Entity::playStepSound( int xt, int yt, int zt, int t ) { + const Tile::SoundType* soundType = Tile::tiles[t]->soundType; + if (level->getTile(xt, yt + 1, zt) == Tile::topSnow->id) { + soundType = Tile::topSnow->soundType; + level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch()); // was * 0.15f + } else if (!Tile::tiles[t]->material->isLiquid()) { + level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.25f, soundType->getPitch()); + } +} diff --git a/src/world/entity/Entity.h b/src/world/entity/Entity.hpp similarity index 96% rename from src/world/entity/Entity.h rename to src/world/entity/Entity.hpp index b6ac74b..71ebbba 100755 --- a/src/world/entity/Entity.h +++ b/src/world/entity/Entity.hpp @@ -10,12 +10,12 @@ class ItemEntity; class ItemInstance; class CompoundTag; -#include "EntityRendererId.h" -#include "../phys/AABB.h" -#include "../../SharedConstants.h" -//#include "../../util/MemUtils.h" -#include "../../util/Mth.h" -#include "../../util/Random.h" +#include "EntityRendererId.hpp" +#include "world/phys/AABB.hpp" +#include "SharedConstants.hpp" +//#include "util/MemUtils.hpp" +#include "util/Mth.hpp" +#include "util/Random.hpp" class SynchedEntityData; diff --git a/src/world/entity/EntityEvent.h b/src/world/entity/EntityEvent.hpp similarity index 100% rename from src/world/entity/EntityEvent.h rename to src/world/entity/EntityEvent.hpp diff --git a/src/world/entity/EntityFactory.cpp b/src/world/entity/EntityFactory.cpp index 28483cf..c422def 100755 --- a/src/world/entity/EntityFactory.cpp +++ b/src/world/entity/EntityFactory.cpp @@ -1,57 +1,57 @@ -#include "EntityFactory.h" -#include "MobFactory.h" -#include "../../nbt/CompoundTag.h" - -#include "item/PrimedTnt.h" -#include "projectile/Arrow.h" -#include "projectile/ThrownEgg.h" -#include "projectile/Snowball.h" -#include "Painting.h" -#include "item/FallingTile.h" - -Entity* EntityFactory::CreateEntity( int typeId, Level* level ) -{ - switch (typeId) { - case EntityTypes::IdItemEntity: return new ItemEntity(level); - case EntityTypes::IdFallingTile:return new FallingTile(level); - case EntityTypes::IdPrimedTnt: return new PrimedTnt(level); - case EntityTypes::IdArrow: return new Arrow(level); - case EntityTypes::IdThrownEgg: return new ThrownEgg(level); - case EntityTypes::IdSnowball: return new Snowball(level); - case EntityTypes::IdPainting: return new Painting(level); - } - return NULL; -} - -Entity* EntityFactory::loadEntity( CompoundTag* tag, Level* level ) -{ - if (!tag) return NULL; - if (!tag->contains("id")) return NULL; - int id = tag->getInt("id"); - - Entity* e = NULL; - - if (id < 0) { - LOGE("Negative ItemId: %d at MobFactory::loadEntity\n", id); - } else if (id < 64) { - e = MobFactory::CreateMob(id, level); - } else { - e = CreateEntity(id, level); - } - - if (e) { - e->load(tag); - - // Add "fixes" here :p - if (e->isItemEntity()) { - const ItemInstance& item = ((ItemEntity*)e)->item; - // Remove items out of range, and now invalid - if(item.isNull() || item.id < 0 || item.id >= Item::MAX_ITEMS || !Item::items[item.id]) { - delete e; - e = NULL; - } - } - } - - return e; -} +#include "EntityFactory.hpp" +#include "MobFactory.hpp" +#include "nbt/CompoundTag.hpp" + +#include "item/PrimedTnt.hpp" +#include "projectile/Arrow.hpp" +#include "projectile/ThrownEgg.hpp" +#include "projectile/Snowball.hpp" +#include "Painting.hpp" +#include "item/FallingTile.hpp" + +Entity* EntityFactory::CreateEntity( int typeId, Level* level ) +{ + switch (typeId) { + case EntityTypes::IdItemEntity: return new ItemEntity(level); + case EntityTypes::IdFallingTile:return new FallingTile(level); + case EntityTypes::IdPrimedTnt: return new PrimedTnt(level); + case EntityTypes::IdArrow: return new Arrow(level); + case EntityTypes::IdThrownEgg: return new ThrownEgg(level); + case EntityTypes::IdSnowball: return new Snowball(level); + case EntityTypes::IdPainting: return new Painting(level); + } + return NULL; +} + +Entity* EntityFactory::loadEntity( CompoundTag* tag, Level* level ) +{ + if (!tag) return NULL; + if (!tag->contains("id")) return NULL; + int id = tag->getInt("id"); + + Entity* e = NULL; + + if (id < 0) { + LOGE("Negative ItemId: %d at MobFactory::loadEntity\n", id); + } else if (id < 64) { + e = MobFactory::CreateMob(id, level); + } else { + e = CreateEntity(id, level); + } + + if (e) { + e->load(tag); + + // Add "fixes" here :p + if (e->isItemEntity()) { + const ItemInstance& item = ((ItemEntity*)e)->item; + // Remove items out of range, and now invalid + if(item.isNull() || item.id < 0 || item.id >= Item::MAX_ITEMS || !Item::items[item.id]) { + delete e; + e = NULL; + } + } + } + + return e; +} diff --git a/src/world/entity/EntityFactory.h b/src/world/entity/EntityFactory.hpp similarity index 100% rename from src/world/entity/EntityFactory.h rename to src/world/entity/EntityFactory.hpp diff --git a/src/world/entity/EntityPos.h b/src/world/entity/EntityPos.hpp similarity index 98% rename from src/world/entity/EntityPos.h rename to src/world/entity/EntityPos.hpp index d37dd35..f21ea4e 100755 --- a/src/world/entity/EntityPos.h +++ b/src/world/entity/EntityPos.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity; -#include "Entity.h" +#include "Entity.hpp" class EntityPos { diff --git a/src/world/entity/EntityRendererId.h b/src/world/entity/EntityRendererId.hpp similarity index 100% rename from src/world/entity/EntityRendererId.h rename to src/world/entity/EntityRendererId.hpp diff --git a/src/world/entity/EntityTypes.h b/src/world/entity/EntityTypes.hpp similarity index 99% rename from src/world/entity/EntityTypes.h rename to src/world/entity/EntityTypes.hpp index 1800ea8..782bd83 100755 --- a/src/world/entity/EntityTypes.h +++ b/src/world/entity/EntityTypes.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../util/Mth.h" +#include "util/Mth.hpp" //? 3 bits ? class BaseTypes { diff --git a/src/world/entity/FlyingMob.cpp b/src/world/entity/FlyingMob.cpp index 1a6e92d..9c14ae6 100755 --- a/src/world/entity/FlyingMob.cpp +++ b/src/world/entity/FlyingMob.cpp @@ -1,71 +1,71 @@ -#include "FlyingMob.h" -#include "../level/Level.h" -#include "../level/tile/Tile.h" -#include "../../util/Mth.h" - - -FlyingMob::FlyingMob( Level* level ) -: super(level) -{ -} - -void FlyingMob::travel( float xa, float ya ) -{ - if (isInWater()) { - moveRelative(xa, ya, 0.02f); - move(xd, yd, zd); - - xd *= 0.80f; - yd *= 0.80f; - zd *= 0.80f; - } else if (isInLava()) { - moveRelative(xa, ya, 0.02f); - move(xd, yd, zd); - xd *= 0.50f; - yd *= 0.50f; - zd *= 0.50f; - } else { - float friction = 0.91f; - if (onGround) { - friction = 0.6f * 0.91f; - int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); - if (t > 0) { - friction = Tile::tiles[t]->friction * 0.91f; - } - } - - float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction); - moveRelative(xa, ya, (onGround ? 0.1f * friction2 : 0.02f)); - - friction = 0.91f; - if (onGround) { - friction = 0.6f * 0.91f; - int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); - if (t > 0) { - friction = Tile::tiles[t]->friction * 0.91f; - } - } - - move(xd, yd, zd); - - xd *= friction; - yd *= friction; - zd *= friction; - } - walkAnimSpeedO = walkAnimSpeed; - float xxd = x - xo; - float zzd = z - zo; - float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4; - if (wst > 1) wst = 1; - walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; - walkAnimPos += walkAnimSpeed; -} - -bool FlyingMob::onLadder() -{ - return false; -} - -void FlyingMob::causeFallDamage( float distance ) -{ -} +#include "FlyingMob.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Mth.hpp" + + +FlyingMob::FlyingMob( Level* level ) +: super(level) +{ +} + +void FlyingMob::travel( float xa, float ya ) +{ + if (isInWater()) { + moveRelative(xa, ya, 0.02f); + move(xd, yd, zd); + + xd *= 0.80f; + yd *= 0.80f; + zd *= 0.80f; + } else if (isInLava()) { + moveRelative(xa, ya, 0.02f); + move(xd, yd, zd); + xd *= 0.50f; + yd *= 0.50f; + zd *= 0.50f; + } else { + float friction = 0.91f; + if (onGround) { + friction = 0.6f * 0.91f; + int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); + if (t > 0) { + friction = Tile::tiles[t]->friction * 0.91f; + } + } + + float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction); + moveRelative(xa, ya, (onGround ? 0.1f * friction2 : 0.02f)); + + friction = 0.91f; + if (onGround) { + friction = 0.6f * 0.91f; + int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); + if (t > 0) { + friction = Tile::tiles[t]->friction * 0.91f; + } + } + + move(xd, yd, zd); + + xd *= friction; + yd *= friction; + zd *= friction; + } + walkAnimSpeedO = walkAnimSpeed; + float xxd = x - xo; + float zzd = z - zo; + float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4; + if (wst > 1) wst = 1; + walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; + walkAnimPos += walkAnimSpeed; +} + +bool FlyingMob::onLadder() +{ + return false; +} + +void FlyingMob::causeFallDamage( float distance ) +{ +} diff --git a/src/world/entity/FlyingMob.h b/src/world/entity/FlyingMob.hpp similarity index 93% rename from src/world/entity/FlyingMob.h rename to src/world/entity/FlyingMob.hpp index 59323b5..605adb1 100755 --- a/src/world/entity/FlyingMob.h +++ b/src/world/entity/FlyingMob.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity; -#include "Mob.h" +#include "Mob.hpp" class Level; diff --git a/src/world/entity/HangingEntity.cpp b/src/world/entity/HangingEntity.cpp index 1240b6c..6c08ee8 100755 --- a/src/world/entity/HangingEntity.cpp +++ b/src/world/entity/HangingEntity.cpp @@ -1,234 +1,234 @@ -#include "HangingEntity.h" -#include "../Direction.h" -#include "../level/Level.h" -#include "../level/material/Material.h" -HangingEntity::HangingEntity( Level* level ) - : super(level) { - init(); -} - -HangingEntity::HangingEntity( Level* level, int xTile, int yTile, int zTile, int dir ) - : super(level), xTile(xTile), yTile(yTile), zTile(zTile) { - init(); -} -void HangingEntity::setPosition( int x, int y, int z ) { - xTile = x; - yTile = y; - zTile = z; -} -void HangingEntity::init() { - heightOffset = 0; - setSize(0.5f, 0.5f); - dir = 0; - checkInterval = 0; -} - -void HangingEntity::setDir( int dir ) { - //printf("HangingEntity dir: %d\n", dir); - this->dir = dir; - yRotO = yRot = float(dir * 90); - - float w = float(getWidth()); - float h = float(getHeight()); - float d = float(getWidth()); - - if (dir == Direction::NORTH || dir == Direction::SOUTH) { - d = 2.0f; - yRot = yRotO = float(Direction::DIRECTION_OPPOSITE[dir] * 90); - } else { - w = 2.0f; - } - - w /= 32.0f; - h /= 32.0f; - d /= 32.0f; - - float x = xTile + 0.5f; - float y = yTile + 0.5f; - float z = zTile + 0.5f; - - float offset = 0.5f + 1.0f / 16.0f; - - if (dir == Direction::NORTH) z -= offset; - if (dir == Direction::WEST) x -= offset; - if (dir == Direction::SOUTH) z += offset; - if (dir == Direction::EAST) x += offset; - - if (dir == Direction::NORTH) x -= offs(getWidth()); - if (dir == Direction::WEST) z += offs(getWidth()); - if (dir == Direction::SOUTH) x += offs(getWidth()); - if (dir == Direction::EAST) z -= offs(getWidth()); - y += offs(getHeight()); - - setPos(x, y, z); - - float ss = -(0.5f / 16.0f); - bb.set(x - w - ss, y - h - ss, z - d - ss, x + w + ss, y + h + ss, z + d + ss); -} -float HangingEntity::offs( int w ) { - if(w == 32) return 0.5f; - if(w == 64) return 0.5f; - return 0; -} - -void HangingEntity::tick() { - if(checkInterval++ == 20 * 5 && !level->isClientSide) { - checkInterval = 0; - if(!removed && !survives()) { - remove(); - dropItem(); - } - } -} - -bool HangingEntity::survives() { - if (!level->getCubes(this, bb).empty()) { - return false; - } else { - int ws = Mth::Max(1, getWidth() / 16); - int hs = Mth::Max(1, getHeight() / 16); - - int xt = xTile; - int yt = yTile; - int zt = zTile; - if (dir == Direction::NORTH) xt = Mth::floor(x - getWidth() / 32.0f); - if (dir == Direction::WEST) zt = Mth::floor(z - getWidth() / 32.0f); - if (dir == Direction::SOUTH) xt = Mth::floor(x - getWidth() / 32.0f); - if (dir == Direction::EAST) zt = Mth::floor(z - getWidth() / 32.0f); - yt = Mth::floor(y - getHeight() / 32.0f); - - for (int ss = 0; ss < ws; ++ss) { - for (int yy = 0; yy < hs; ++yy) { - const Material* m; - if (dir == Direction::NORTH || dir == Direction::SOUTH) { - m = level->getMaterial(xt + ss, yt + yy, zTile); - } else { - m = level->getMaterial(xTile, yt + yy, zt + ss); - } - if (!m->isSolid()) - return false; - } - EntityList entities = level->getEntities(this, bb); - for(EntityList::iterator ei = entities.begin(); ei != entities.end(); ++ei) { - Entity* entity = *(ei); - if(entity->isHangingEntity()) - return false; - } - } - } - return true; -} - -bool HangingEntity::isHangingEntity() { - return true; -} - -bool HangingEntity::isPickable() { - return true; -} - -bool HangingEntity::interact(Player* player) { - if(!removed && !level->isClientSide) { - if(player != NULL - && player->inventory != NULL - && player->inventory->getSelected() != NULL - && player->inventory->getSelected()->id == Item::bow->id) - return false; - remove(); - markHurt(); - if(player != NULL && !player->abilities.instabuild) - dropItem(); - return true; - } else { - return !removed; - } -} - -void HangingEntity::move( float xa, float ya, float za ) { - if(!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) { - dropItem(); - remove(); - } -} - -void HangingEntity::push( float xa, float ya, float za ) { - if (!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) { - dropItem(); - remove(); - } -} - -void HangingEntity::addAdditonalSaveData( CompoundTag* tag ) { - tag->putByte("Direction", (char) dir); - tag->putInt("TileX", xTile); - tag->putInt("TileY", yTile); - tag->putInt("TileZ", zTile); - - // Back compat - switch (dir) { - case Direction::NORTH: - tag->putByte("Dir", char(0)); - break; - case Direction::WEST: - tag->putByte("Dir", char(1)); - break; - case Direction::SOUTH: - tag->putByte("Dir", char(2)); - break; - case Direction::EAST: - tag->putByte("Dir", char(3)); - break; - } -} - -void HangingEntity::readAdditionalSaveData( CompoundTag* tag ) { - if (tag->contains("Direction")) { - dir = tag->getByte("Direction"); - } else { - switch (tag->getByte("Dir")) { - case 0: - dir = Direction::NORTH; - break; - case 1: - dir = Direction::WEST; - break; - case 2: - dir = Direction::SOUTH; - break; - case 3: - dir = Direction::EAST; - break; - } - } - xTile = tag->getInt("TileX"); - yTile = tag->getInt("TileY"); - zTile = tag->getInt("TileZ"); - setDir(dir); -} - -float HangingEntity::getBrightness( float a ) { - int xTile = Mth::floor(x); - int zTile = Mth::floor(z); - //if (dir == Direction::NORTH) xTile--; - //if (dir == Direction::WEST) zTile++; - //if (dir == Direction::SOUTH) xTile++; - //if (dir == Direction::EAST) zTile--; - if (level->hasChunkAt(xTile, 0, zTile)) { - int yTile = Mth::floor(y); - return level->getBrightness(xTile, yTile, zTile); - } - return 0; -} - -bool HangingEntity::hurt( Entity* source, int damage ) { - if(!removed && !level->isClientSide) { - remove(); - markHurt(); - Player* player = Player::asPlayer(source); - if(player != NULL && player->abilities.instabuild) { - return true; - } - dropItem(); - } - return true; -} +#include "HangingEntity.hpp" +#include "world/Direction.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +HangingEntity::HangingEntity( Level* level ) + : super(level) { + init(); +} + +HangingEntity::HangingEntity( Level* level, int xTile, int yTile, int zTile, int dir ) + : super(level), xTile(xTile), yTile(yTile), zTile(zTile) { + init(); +} +void HangingEntity::setPosition( int x, int y, int z ) { + xTile = x; + yTile = y; + zTile = z; +} +void HangingEntity::init() { + heightOffset = 0; + setSize(0.5f, 0.5f); + dir = 0; + checkInterval = 0; +} + +void HangingEntity::setDir( int dir ) { + //printf("HangingEntity dir: %d\n", dir); + this->dir = dir; + yRotO = yRot = float(dir * 90); + + float w = float(getWidth()); + float h = float(getHeight()); + float d = float(getWidth()); + + if (dir == Direction::NORTH || dir == Direction::SOUTH) { + d = 2.0f; + yRot = yRotO = float(Direction::DIRECTION_OPPOSITE[dir] * 90); + } else { + w = 2.0f; + } + + w /= 32.0f; + h /= 32.0f; + d /= 32.0f; + + float x = xTile + 0.5f; + float y = yTile + 0.5f; + float z = zTile + 0.5f; + + float offset = 0.5f + 1.0f / 16.0f; + + if (dir == Direction::NORTH) z -= offset; + if (dir == Direction::WEST) x -= offset; + if (dir == Direction::SOUTH) z += offset; + if (dir == Direction::EAST) x += offset; + + if (dir == Direction::NORTH) x -= offs(getWidth()); + if (dir == Direction::WEST) z += offs(getWidth()); + if (dir == Direction::SOUTH) x += offs(getWidth()); + if (dir == Direction::EAST) z -= offs(getWidth()); + y += offs(getHeight()); + + setPos(x, y, z); + + float ss = -(0.5f / 16.0f); + bb.set(x - w - ss, y - h - ss, z - d - ss, x + w + ss, y + h + ss, z + d + ss); +} +float HangingEntity::offs( int w ) { + if(w == 32) return 0.5f; + if(w == 64) return 0.5f; + return 0; +} + +void HangingEntity::tick() { + if(checkInterval++ == 20 * 5 && !level->isClientSide) { + checkInterval = 0; + if(!removed && !survives()) { + remove(); + dropItem(); + } + } +} + +bool HangingEntity::survives() { + if (!level->getCubes(this, bb).empty()) { + return false; + } else { + int ws = Mth::Max(1, getWidth() / 16); + int hs = Mth::Max(1, getHeight() / 16); + + int xt = xTile; + int yt = yTile; + int zt = zTile; + if (dir == Direction::NORTH) xt = Mth::floor(x - getWidth() / 32.0f); + if (dir == Direction::WEST) zt = Mth::floor(z - getWidth() / 32.0f); + if (dir == Direction::SOUTH) xt = Mth::floor(x - getWidth() / 32.0f); + if (dir == Direction::EAST) zt = Mth::floor(z - getWidth() / 32.0f); + yt = Mth::floor(y - getHeight() / 32.0f); + + for (int ss = 0; ss < ws; ++ss) { + for (int yy = 0; yy < hs; ++yy) { + const Material* m; + if (dir == Direction::NORTH || dir == Direction::SOUTH) { + m = level->getMaterial(xt + ss, yt + yy, zTile); + } else { + m = level->getMaterial(xTile, yt + yy, zt + ss); + } + if (!m->isSolid()) + return false; + } + EntityList entities = level->getEntities(this, bb); + for(EntityList::iterator ei = entities.begin(); ei != entities.end(); ++ei) { + Entity* entity = *(ei); + if(entity->isHangingEntity()) + return false; + } + } + } + return true; +} + +bool HangingEntity::isHangingEntity() { + return true; +} + +bool HangingEntity::isPickable() { + return true; +} + +bool HangingEntity::interact(Player* player) { + if(!removed && !level->isClientSide) { + if(player != NULL + && player->inventory != NULL + && player->inventory->getSelected() != NULL + && player->inventory->getSelected()->id == Item::bow->id) + return false; + remove(); + markHurt(); + if(player != NULL && !player->abilities.instabuild) + dropItem(); + return true; + } else { + return !removed; + } +} + +void HangingEntity::move( float xa, float ya, float za ) { + if(!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) { + dropItem(); + remove(); + } +} + +void HangingEntity::push( float xa, float ya, float za ) { + if (!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) { + dropItem(); + remove(); + } +} + +void HangingEntity::addAdditonalSaveData( CompoundTag* tag ) { + tag->putByte("Direction", (char) dir); + tag->putInt("TileX", xTile); + tag->putInt("TileY", yTile); + tag->putInt("TileZ", zTile); + + // Back compat + switch (dir) { + case Direction::NORTH: + tag->putByte("Dir", char(0)); + break; + case Direction::WEST: + tag->putByte("Dir", char(1)); + break; + case Direction::SOUTH: + tag->putByte("Dir", char(2)); + break; + case Direction::EAST: + tag->putByte("Dir", char(3)); + break; + } +} + +void HangingEntity::readAdditionalSaveData( CompoundTag* tag ) { + if (tag->contains("Direction")) { + dir = tag->getByte("Direction"); + } else { + switch (tag->getByte("Dir")) { + case 0: + dir = Direction::NORTH; + break; + case 1: + dir = Direction::WEST; + break; + case 2: + dir = Direction::SOUTH; + break; + case 3: + dir = Direction::EAST; + break; + } + } + xTile = tag->getInt("TileX"); + yTile = tag->getInt("TileY"); + zTile = tag->getInt("TileZ"); + setDir(dir); +} + +float HangingEntity::getBrightness( float a ) { + int xTile = Mth::floor(x); + int zTile = Mth::floor(z); + //if (dir == Direction::NORTH) xTile--; + //if (dir == Direction::WEST) zTile++; + //if (dir == Direction::SOUTH) xTile++; + //if (dir == Direction::EAST) zTile--; + if (level->hasChunkAt(xTile, 0, zTile)) { + int yTile = Mth::floor(y); + return level->getBrightness(xTile, yTile, zTile); + } + return 0; +} + +bool HangingEntity::hurt( Entity* source, int damage ) { + if(!removed && !level->isClientSide) { + remove(); + markHurt(); + Player* player = Player::asPlayer(source); + if(player != NULL && player->abilities.instabuild) { + return true; + } + dropItem(); + } + return true; +} diff --git a/src/world/entity/HangingEntity.h b/src/world/entity/HangingEntity.hpp similarity index 97% rename from src/world/entity/HangingEntity.h rename to src/world/entity/HangingEntity.hpp index 119adf6..1c61313 100755 --- a/src/world/entity/HangingEntity.h +++ b/src/world/entity/HangingEntity.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Entity.h" +#include "Entity.hpp" class HangingEntity : public Entity { typedef Entity super; public: diff --git a/src/world/entity/Mob.cpp b/src/world/entity/Mob.cpp index cc784f0..7f2de3f 100755 --- a/src/world/entity/Mob.cpp +++ b/src/world/entity/Mob.cpp @@ -1,1185 +1,1185 @@ -#include "Mob.h" - -#include - -#include "player/Player.h" -#include "SharedFlags.h" -#include "../entity/EntityEvent.h" -#include "../level/Level.h" -#include "../level/material/Material.h" -#include "../level/tile/Tile.h" -#include "../../util/Random.h" -#include "../../util/PerfTimer.h" - -#include "../../nbt/CompoundTag.h" - -#include "../../network/RakNetInstance.h" -#include "../../network/packet/MoveEntityPacket.h" -#include "ai/control/MoveControl.h" -#include "ai/control/JumpControl.h" -#include "ai/PathNavigation.h" -#include "ai/Sensing.h" -#include "ai/goal/GoalSelector.h" -#include "../../network/packet/SetEntityMotionPacket.h" -#include "../item/ArmorItem.h" - - -Mob::Mob(Level* level) -: super(level), - invulnerableDuration(20), - //hasHair(false), - textureName("mob/char.png"), - capeTextureName(""), - allowAlpha(true), - modelName(""), - bobStrength(1), - deathScore(0), - renderOffset(0), - //interpolateOnly(false), - lookingAtId(0), - jumping(false), - defaultLookAngle(0.0f), - runSpeed(0.7f), - walkingSpeed(0.1f), - flyingSpeed(0.02f), - run(0), oRun(0), - animStep(0), animStepO(0), - lx(0), ly(0), lz(0), lxr(0), lyr(0), - lSteps(0), - walkAnimSpeed(0), walkAnimSpeedO(0), walkAnimPos(0), - attackAnim(0), oAttackAnim(0), - - autoSendPosRot(true), - sentX(0), sentY(0), sentZ(0), - sentRotX(0), sentRotY(0), - sentXd(0), sentYd(0), sentZd(0), - arrowCount(0), - removeArrowTime(0), - speed(0), - moveControl(NULL), - jumpControl(NULL), - navigation(NULL), - goalSelector(NULL), - targetSelector(NULL), - sensing(NULL), - swinging(false), - swingTime(0), - lastHurt(0), - dmgSpill(0), - bypassArmor(false) -{ - entityData.define(SharedFlagsInformation::DATA_SHARED_FLAGS_ID, (SynchedEntityData::TypeChar) 0); - entityData.define(DATA_AIR_SUPPLY_ID, (SynchedEntityData::TypeShort) TOTAL_AIR_SUPPLY); - - _init(); - health = getMaxHealth(); - - blocksBuilding = true; - ambientSoundTime = -level->random.nextInt(100); - - rotA = (float) (Mth::random() + 1) * 0.01f; - setPos(x, y, z); - timeOffs = (float) Mth::random() * 12398; - yRot = (float) (Mth::random() * Mth::PI * 2); - - this->footSize = 0.5f; - - // Initialize cape inertia positions - xCape = x; - yCape = y; - zCape = z; - - xc = xCape; - yc = yCape; - zc = zCape; -} - -Mob::~Mob() { - //LOGI("destroying an entity! %p\n", this); -} - -float Mob::getWalkingSpeedModifier() { - float speed = 0.7f; // is 1.0f in desktop Minecraft - - //if (hasEffect(MobEffect.movementSpeed)) { - // speed *= 1.0f + .2f * (getEffect(MobEffect.movementSpeed).getAmplifier() + 1); - //} - //if (hasEffect(MobEffect.movementSlowdown)) { - // speed *= 1.0f - .15f * (getEffect(MobEffect.movementSlowdown).getAmplifier() + 1); - //} - return speed; -} - -bool Mob::canSee( Entity* target ) -{ - return !level->clip(Vec3(x, y + getHeadHeight(), z), Vec3(target->x, target->y + target->getHeadHeight(), target->z)).isHit(); -} - -std::string Mob::getTexture() -{ - return textureName; -} - -void Mob::setTextureName(const std::string& name) -{ - textureName = name; -} - -std::string Mob::getCapeTexture() -{ - return capeTextureName; -} - -void Mob::setCapeTextureName(const std::string& name) -{ - capeTextureName = name; -} - -bool Mob::isPickable() -{ - return !removed; -} - -bool Mob::isPushable() -{ - return !removed; -} - -float Mob::getHeadHeight() -{ - return bbHeight * 0.85f; -} - -float Mob::getVoicePitch() { - if (isBaby()) { - return (random.nextFloat() - random.nextFloat()) * 0.2f + 1.5f; - } - return (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f; -} - -int Mob::getAmbientSoundInterval() -{ - return 8 * SharedConstants::TicksPerSecond; -} - -void Mob::playAmbientSound() -{ - const char* ambient = getAmbientSound(); - if (ambient != NULL) { - level->playSound(this, ambient, getSoundVolume(), getVoicePitch()); - } -} - -void Mob::baseTick() -{ - oAttackAnim = attackAnim; - super::baseTick(); - - TIMER_PUSH("mobBaseTick"); - - if (((ambientSoundTime++ & 15) == 0) && random.nextInt(2000) < ambientSoundTime) { - ambientSoundTime = -getAmbientSoundInterval(); - playAmbientSound(); - } - - if (isAlive() && isInWall()) { - hurt(NULL, 1); - } - - //if (fireImmune || level.isOnline) onFire = 0; - - if (isAlive() && isUnderLiquid(Material::water) && !isWaterMob()) { - airSupply--; - if (airSupply == -20) { - airSupply = 0; - for (int i = 0; i < 8; i++) { - float xo = random.nextFloat() - random.nextFloat(); - float yo = random.nextFloat() - random.nextFloat(); - float zo = random.nextFloat() - random.nextFloat(); - level->addParticle(PARTICLETYPE(bubble), x + xo, y + yo, z + zo, xd, yd, zd); - } - hurt(NULL, 2); - } - //onFire = 0; - } else { - airSupply = airCapacity; - } - - oTilt = tilt; - if (attackTime > 0) attackTime--; - if (hurtTime > 0) hurtTime--; - if (invulnerableTime > 0) invulnerableTime--; - - if (health <= 0) { - deathTime++; - if (deathTime > SharedConstants::TicksPerSecond) { - beforeRemove(); - remove(); - for (int i = 0; i < 20; i++) { - float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); - } - } - } - - animStepO = animStep; - - yBodyRotO = yBodyRot; - yRotO = yRot; - xRotO = xRot; - - TIMER_POP(); - - if (!level->isClientSide) { - if (autoSendPosRot) { - if (autoSendPosRot && (std::abs(x - sentX) > .1f || std::abs(y - sentY) > .05f || std::abs(z - sentZ) > .1f || std::abs(sentRotX - xRot) > 1 || std::abs(sentRotY - yRot) > 1)) { - MoveEntityPacket_PosRot packet(this); - level->raknetInstance->send(packet); - sentX = x; - sentY = y; - sentZ = z; - sentRotX = xRot; - sentRotY = yRot; - } - } - - float ddx = std::abs(xd - sentXd); - float ddy = std::abs(yd - sentYd); - float ddz = std::abs(zd - sentZd); - const float max = 0.02f; - const float diff = ddx*ddx + ddy*ddy + ddz*ddz; - if (diff > max*max || (diff > 0 && xd == 0 && yd == 0 && zd == 0)) { - sentXd = xd; - sentYd = yd; - sentZd = zd; - SetEntityMotionPacket packet(this); - level->raknetInstance->send(packet); - //LOGI("Motion-packet: %d\n", entityId); - } - } -} - -void Mob::spawnAnim() -{ - /* - for (int i = 0; i < 20; i++) { - float xa = random.nextGaussian() * 0.02; - float ya = random.nextGaussian() * 0.02; - float za = random.nextGaussian() * 0.02; - float dd = 10; - level.addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth - xa * dd, y + random.nextFloat() * bbHeight - ya * dd, z + random.nextFloat() * bbWidth * 2 - bbWidth - za - * dd, xa, ya, za); - } - */ -} - -void Mob::lerpTo( float x, float y, float z, float yRot, float xRot, int steps ) -{ - //heightOffset = 0; - lx = x; - ly = y + heightOffset; - lz = z; - lyr = yRot; - lxr = xRot; - - lSteps = steps; -} - -void Mob::superTick() -{ - super::tick(); -} - -void Mob::tick() -{ - xc = xCape; - yc = yCape; - zc = zCape; - - super::tick(); - - if (arrowCount > 0) { - if (removeArrowTime <= 0) { - removeArrowTime = 20 * 3; - } - removeArrowTime--; - if (removeArrowTime <= 0) { - arrowCount--; - } - } - - if (lSteps > 0) { - float xt = x + (lx - x) / lSteps; - float yt = y + (ly - y) / lSteps; - float zt = z + (lz - z) / lSteps; - - float yrd = lyr - yRot; - while (yrd < -180) - yrd += 360; - while (yrd >= 180) - yrd -= 360; - - yRot += (yrd) / lSteps; - xRot += (lxr - xRot) / lSteps; - - lSteps--; - this->setPos(xt, yt, zt); - this->setRot(yRot, xRot); - } - - aiStep(); - - updateWalkAnim(); - - float xd = x - xo; - float zd = z - zo; - - float sideDist = (float) Mth::sqrt(xd * xd + zd * zd); - - float yBodyRotT = yBodyRot; - - float walkSpeed = 0; - oRun = run; - float tRun = 0; - if (sideDist <= 0.05f) { - // animStep = 0; - } else { - tRun = 1; - walkSpeed = sideDist * 3; - yBodyRotT = Mth::atan2(zd, xd) * Mth::RADDEG - 90; - } - if (attackAnim > 0) { - yBodyRotT = yRot; - } - if (!onGround) { - tRun = 0; - } - run = run + (tRun - run) * 0.3f; - - /* - * float yBodyRotD = yRot-yBodyRot; while (yBodyRotD < -180) yBodyRotD - * += 360; while (yBodyRotD >= 180) yBodyRotD -= 360; yBodyRot += - * yBodyRotD * 0.1f; - */ - - float yBodyRotD = yBodyRotT - yBodyRot; - while (yBodyRotD < -180) - yBodyRotD += 360; - while (yBodyRotD >= 180) - yBodyRotD -= 360; - yBodyRot += yBodyRotD * 0.3f; - - float headDiff = yRot - yBodyRot; - while (headDiff < -180) - headDiff += 360; - while (headDiff >= 180) - headDiff -= 360; - bool behind = headDiff < -90 || headDiff >= 90; - if (headDiff < -75) headDiff = -75; - if (headDiff >= 75) headDiff = +75; - yBodyRot = yRot - headDiff; - if (headDiff * headDiff > 50 * 50) { - yBodyRot += headDiff * 0.2f; - } - - if (behind) { - walkSpeed *= -1; - } - while (yRot - yRotO < -180) - yRotO -= 360; - while (yRot - yRotO >= 180) - yRotO += 360; - - while (yBodyRot - yBodyRotO < -180) - yBodyRotO -= 360; - while (yBodyRot - yBodyRotO >= 180) - yBodyRotO += 360; - - while (xRot - xRotO < -180) - xRotO -= 360; - while (xRot - xRotO >= 180) - xRotO += 360; - animStep += walkSpeed; - - // Reduce jitter by using a smaller interpolation factor (more lag, smoother motion) - double dxCape = x - xCape; - double dyCape = y - yCape; - double dzCape = z - zCape; - - const double interp = 0.15; // small value for smoother cape motion - const double interpY = 0.12; // extra smoothing on vertical movement - - xCape += dxCape * interp; - yCape += dyCape * interpY; - zCape += dzCape * interp; -} - -void Mob::setSize( float w, float h ) -{ - super::setSize(w, h); -} - -void Mob::heal( int heal ) -{ - if (health <= 0) return; - health += heal; - if (health > 20) health = 20; - invulnerableTime = invulnerableDuration / 2; -} - -bool Mob::hurt( Entity* source, int dmg ) -{ - if (level->isClientSide) return false; - noActionTime = 0; - if (health <= 0) return false; - - this->walkAnimSpeed = 1.5f; - - bool sound = true; - if (invulnerableTime > invulnerableDuration / 2.0f) { - if (dmg <= lastHurt) return false; - actuallyHurt(dmg - lastHurt); - lastHurt = dmg; - sound = false; - } else { - lastHurt = dmg; - lastHealth = health; - invulnerableTime = invulnerableDuration; - actuallyHurt(dmg); - hurtTime = hurtDuration = 10; - hurtDuration = 10; - } - - hurtDir = 0; - - if (sound) { - level->broadcastEntityEvent(this, EntityEvent::HURT); - markHurt(); - if (source != NULL) { - float xd = source->x - x; - float zd = source->z - z; - while (xd * xd + zd * zd < 0.0001) { - xd = (Mth::random() - Mth::random()) * 0.01f; - zd = (Mth::random() - Mth::random()) * 0.01f; - } - hurtDir = (float) (std::atan2(zd, xd) * Mth::RADDEG) - yRot; - knockback(source, dmg, xd, zd); - } else { - hurtDir = (int) (Mth::random() * 2.0f) * 180.0f; - } - } - - if (health <= 0) { - if (sound) level->playSound(this, getDeathSound(), getSoundVolume(), getVoicePitch()); - die(source); - } else { - if (sound) level->playSound(this, getHurtSound(), getSoundVolume(), getVoicePitch()); - } - - return true; -} - -void Mob::actuallyHurt( int dmg ) -{ - if (!bypassArmor) { - dmg = getDamageAfterArmorAbsorb(dmg); - } - health -= dmg; -} - -float Mob::getSoundVolume() -{ - return 1; -} - -const char* Mob::getAmbientSound() -{ - return NULL; -} - -std::string Mob::getHurtSound() -{ - return "random.hurt"; -} - -std::string Mob::getDeathSound() -{ - return "random.hurt"; -} - -void Mob::knockback( Entity* source, int dmg, float xd, float zd ) -{ - float dd = Mth::invSqrt(xd * xd + zd * zd); - float pow = 0.4f; - - this->xd *= 0.5f; - this->yd *= 0.5f; - this->zd *= 0.5f; - - this->xd -= xd * dd * pow; - this->yd += 0.4f; - this->zd -= zd * dd * pow; - - if (this->yd > 0.4f) this->yd = 0.4f; -} - -void Mob::die( Entity* source ) -{ - if (deathScore > 0 && source != NULL) source->awardKillScore(this, deathScore); - - if (!level->isClientSide) { - if (!isBaby()) { - dropDeathLoot(); - } - level->broadcastEntityEvent(this, EntityEvent::DEATH); - } -} - -void Mob::dropDeathLoot() -{ - int loot = getDeathLoot(); - if (loot > 0) { - int count = random.nextInt(3); - for (int i = 0; i < count; i++) - spawnAtLocation(loot, 1); - } -} - -int Mob::getDeathLoot() -{ - return 0; -} - -void Mob::reset() { - super::reset(); - this->_init(); -} - -void Mob::_init() { - yBodyRot = 0; - yBodyRotO = 0; - rotOffs = 0; - fallTime = 0; - lastHurt = 0; - deathTime = 0; - attackTime = 0; - tilt = 0; - oTilt = 0; - hurtDuration = 0; - hurtTime = 0; - hurtDir = 0; - lookTime = 0; - noActionTime = 0; - xxa = 0; yya = 0; - yRotA = 0; - - health = 10; - lastHealth = 20; -} - -void Mob::causeFallDamage( float distance ) -{ - int dmg = (int) ceil((distance - 3)); - - if (dmg > 0) { - level->playSound(this, (dmg > 4)?"damage.fallbig":"damage.fallsmall", 0.75f, 1); - - hurt(NULL, dmg); - - int t = level->getTile(Mth::floor(x), Mth::floor(y - 0.2f - this->heightOffset), Mth::floor(z)); - if (t > 0) { - const Tile::SoundType* soundType = Tile::tiles[t]->soundType; - level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.5f, soundType->getPitch() * 0.75f); - } - } -} - -void Mob::travel( float xa, float ya ) -{ - if (isInWater()) { - float yo = y; - moveRelative(xa, ya, 0.02f); - move(xd, yd, zd); - - xd *= 0.80f; - yd *= 0.80f; - zd *= 0.80f; - yd -= 0.02f; - - if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) { - yd = 0.3f; - } - } else if (isInLava()) { - float yo = y; - moveRelative(xa, ya, 0.02f); - move(xd, yd, zd); - xd *= 0.50f; - yd *= 0.50f; - zd *= 0.50f; - yd -= 0.02f; - - if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) { - yd = 0.3f; - } - } else { - float friction = 0.91f; - if (onGround) { - friction = 0.6f * 0.91f; - int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); - if (t > 0) { - friction = Tile::tiles[t]->friction * 0.91f; - } - } - - float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction); - moveRelative(xa, ya, (onGround ? walkingSpeed * friction2 : flyingSpeed)); - - friction = 0.91f; - if (onGround) { - friction = 0.6f * 0.91f; - int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); - if (t > 0) { - friction = Tile::tiles[t]->friction * 0.91f; - } - } - //@todo: make it easier to climb ladders - if (onLadder()) { - this->fallDistance = 0; - if (yd < -0.15) yd = -0.15f; - if (isSneaking() && yd < 0) yd = 0; - } - - move(xd, yd, zd); - - //@todo: make it easier to climb ladders - if (horizontalCollision && onLadder()) { - yd = 0.2f; - } - - yd -= 0.08f; - yd *= 0.98f; - xd *= friction; - zd *= friction; - } - -} - -void Mob::updateWalkAnim() -{ - walkAnimSpeedO = walkAnimSpeed; - float xxd = x - xo; - float zzd = z - zo; - float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4; - if (wst > 1) wst = 1; - walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; - walkAnimPos += walkAnimSpeed; -} - -bool Mob::onLadder() -{ - int xt = Mth::floor(x); - int yt = Mth::floor(bb.y0); - int zt = Mth::floor(z); - return level->getTile(xt, yt, zt) == Tile::ladder->id || level->getTile(xt, yt + 1, zt) == Tile::ladder->id; -} - -bool Mob::isShootable() -{ - return true; -} - -void Mob::addAdditonalSaveData( CompoundTag* entityTag ) -{ - entityTag->putShort("Health", (short) health); - entityTag->putShort("HurtTime", (short) hurtTime); - entityTag->putShort("DeathTime", (short) deathTime); - entityTag->putShort("AttackTime", (short) attackTime); - - //if (isPlayer()) LOGI("Saving %d, %d, %d, %d\n", health, hurtTime, deathTime, attackTime); -} - -void Mob::readAdditionalSaveData( CompoundTag* tag ) -{ - health = tag->getShort("Health"); - hurtTime = tag->getShort("HurtTime"); - deathTime = tag->getShort("DeathTime"); - attackTime = tag->getShort("AttackTime"); - - //if (isPlayer()) LOGI("Reading %d, %d, %d, %d\n", health, hurtTime, deathTime, attackTime); -} - -void Mob::animateHurt() -{ - hurtTime = hurtDuration = 10; - hurtDir = 0; -} - -bool Mob::isAlive() -{ - return !removed && health > 0; -} - -bool Mob::isWaterMob() -{ - return false; -} - -void Mob::aiStep() -{ - //@todo? 30 lines of code here in java version - - TIMER_PUSH("ai"); - if (isImmobile()) { - jumping = false; - xxa = 0; - yya = 0; - yRotA = 0; - } else { - if (!interpolateOnly()) { - if (useNewAi()) { - TIMER_PUSH("newAi"); - newServerAiStep(); - TIMER_POP(); - } - else { - TIMER_PUSH("oldAi"); - updateAi(); - TIMER_POP(); - } - } - } - TIMER_POP_PUSH("move"); - - bool inWater = isInWater(); - bool inLava = isInLava(); - - if (jumping) { - if (inWater) { - yd += 0.04f; - } else if (inLava) { - yd += 0.04f; - } else if (onGround) { - jumpFromGround(); - } - } - - xxa *= 0.98f; - yya *= 0.98f; - yRotA *= 0.9f; - - float normalSpeed = walkingSpeed; - float normalAirControllSpeed = flyingSpeed; - walkingSpeed *= getWalkingSpeedModifier(); - flyingSpeed *= getWalkingSpeedModifier(); - travel(xxa, yya); - walkingSpeed = normalSpeed; - flyingSpeed = normalAirControllSpeed; - - TIMER_POP_PUSH("push"); - Player* player = NULL; - if(isPlayer()) { - player = (Player*)this; - } - if(player == NULL || !player->isSleeping()) { - EntityList& entities = level->getEntities(this, this->bb.grow(0.2f, 0, 0.2f)); - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - if(e->isPlayer()) { - Player* p = (Player*)e; - if(p->isSleeping()) - continue; - } - if (e->isPushable()) e->push(this); - } - } - TIMER_POP(); -} - -/*protected*/ -void Mob::updateAi() { - noActionTime++; - - Player* player = level->getNearestPlayer(this, -1); - checkDespawn(player); - - xxa = 0; - yya = 0; - - float lookDistance = 8; - if (random.nextFloat() < 0.02f) { - player = level->getNearestPlayer(this, lookDistance); - if (player != NULL) { - lookingAtId = player->entityId; - lookTime = 10 + random.nextInt(20); - } else { - yRotA = (random.nextFloat() - 0.5f) * 20; - } - } - - if (lookingAtId != 0) { - Entity* lookingAt = level->getEntity(lookingAtId); - lookingAtId = 0; - if (lookingAt != NULL) { - lookAt(lookingAt, 10, (float)getMaxHeadXRot()); - if (lookTime-- <= 0 || lookingAt->removed || lookingAt->distanceToSqr(this) > lookDistance * lookDistance) { - lookingAtId = 0; - } else { - lookingAtId = lookingAt->entityId; - } - } - } else { - if (random.nextFloat() < 0.05f) { - yRotA = (random.nextFloat() - 0.5f) * 20; - } - yRot += yRotA; - xRot = defaultLookAngle; - } - - bool inWater = isInWater(); - bool inLava = isInLava(); - if (inWater || inLava) jumping = random.nextFloat() < 0.8f; -} - -void Mob::newServerAiStep() { - noActionTime++; - - TIMER_PUSH("checkDespawn"); - checkDespawn(); - jumping = false; - - TIMER_POP_PUSH("sensing"); - if (sensing) sensing->tick(); - - if (random.nextInt(5) == 0) { - TIMER_POP_PUSH("targetSelector"); - //LOGI("tg1\n"); - if (targetSelector) targetSelector->tick(); - //LOGI("tg2\n"); - - TIMER_POP_PUSH("goalSelector"); - //LOGI("gs1\n"); - if (goalSelector) goalSelector->tick(); - //LOGI("gs2\n"); - } - - TIMER_POP_PUSH("navigation"); - if (navigation) navigation->tick(); - - //TIMER_POP_PUSH("mob tick"); - //serverAiMobStep(); - - TIMER_POP_PUSH("controls"); - if (moveControl) moveControl->tick(); //@todo; we shouldn't be here if not - if (jumpControl) jumpControl->tick(); - - TIMER_POP(); -} - -bool Mob::isImmobile() -{ - return health <= 0; -} - -void Mob::jumpFromGround() -{ - yd = 0.42f; -} - -bool Mob::removeWhenFarAway() -{ - return true; -} - -int Mob::getMaxHeadXRot() -{ - return 10; -} - -void Mob::lookAt( Entity* e, float yMax, float xMax ) -{ - float xd = e->x - x; - float yd; - float zd = e->z - z; - - if (false) { //if (e->isMob()) { //@todo? - Mob* mob = (Mob*) e; - yd = (y + getHeadHeight()) - (mob->y + mob->getHeadHeight()); - } else { - yd = (e->bb.y0 + e->bb.y1) / 2 - (y + getHeadHeight()); - } - - float sd = Mth::sqrt(xd * xd + zd * zd); - - float yRotD = (float) (atan2(zd, xd) * 180 / Mth::PI) - 90; - float xRotD = (float) (atan2(yd, sd) * 180 / Mth::PI); - xRot = -rotlerp(xRot, xRotD, xMax); - yRot = rotlerp(yRot, yRotD, yMax); -} - -bool Mob::isLookingAtAnEntity() -{ - return lookingAtId != 0; -} - -//Entity* Mob::getLookingAt() -//{ -// return lookingAt; -//} - -float Mob::rotlerp( float a, float b, float max ) -{ - float diff = b - a; - while (diff < -180) - diff += 360; - while (diff >= 180) - diff -= 360; - if (diff > max) { - diff = max; - } - if (diff < -max) { - diff = -max; - } - return a + diff; -} - -void Mob::beforeRemove() -{ -} - -bool Mob::canSpawn() -{ - return level->isUnobstructed(bb) && level->getCubes(this, bb).size() == 0 && !level->containsAnyLiquid(bb); -} - -void Mob::outOfWorld() -{ - int oldHealth = health; - hurt(NULL, 4); - if (health >= oldHealth) - actuallyHurt(4); -} - -float Mob::getAttackAnim( float a ) -{ - float diff = attackAnim - oAttackAnim; - if (diff < 0) diff += 1; - return oAttackAnim + diff * a; -} - -Vec3 Mob::getPos( float a ) -{ - if (a == 1) { - return Vec3(x, y, z); - } - float x = xo + (this->x - xo) * a; - float y = yo + (this->y - yo) * a; - float z = zo + (this->z - zo) * a; - - return Vec3(x, y, z); -} - -Vec3 Mob::getLookAngle() -{ - return getViewVector(1); -} - -Vec3 Mob::getViewVector( float a ) -{ - if (a == 1) { - float yCos = (float) Mth::cos(-yRot * Mth::DEGRAD - Mth::PI); - float ySin = (float) Mth::sin(-yRot * Mth::DEGRAD - Mth::PI); - float xCos = (float) -Mth::cos(-xRot * Mth::DEGRAD); - float xSin = (float) Mth::sin(-xRot * Mth::DEGRAD); - - return Vec3(ySin * xCos, xSin, yCos * xCos); // newTemp - } - float xRot = xRotO + (this->xRot - xRotO) * a; - float yRot = yRotO + (this->yRot - yRotO) * a; - - float yCos = (float) Mth::cos(-yRot * Mth::DEGRAD - Mth::PI); - float ySin = (float) Mth::sin(-yRot * Mth::DEGRAD - Mth::PI); - float xCos = (float) -Mth::cos(-xRot * Mth::DEGRAD); - float xSin = (float) Mth::sin(-xRot * Mth::DEGRAD); - - return Vec3(ySin * xCos, xSin, yCos * xCos); // newTemp -} - -HitResult Mob::pick( float range, float a ) -{ - Vec3 from = getPos(a); - return level->clip(from, from + getViewVector(a) * range); -} - -int Mob::getMaxSpawnClusterSize() -{ - return 4; -} - -bool Mob::interpolateOnly() -{ - return level->isClientSide; -} - -//ItemInstance getCarriedItem() { -// return NULL; -//} - -void Mob::handleEntityEvent(char id) { - if (id == EntityEvent::HURT) { - this->walkAnimSpeed = 1.5f; - - invulnerableTime = invulnerableDuration; - hurtTime = hurtDuration = 10; - hurtDir = 0; - - level->playSound(this, getHurtSound(), getSoundVolume(), getVoicePitch()); - hurt(NULL, 0); - } else if (id == EntityEvent::DEATH) { - level->playSound(this, getDeathSound(), getSoundVolume(), getVoicePitch()); - health = 0; - die(NULL); - } else { - super::handleEntityEvent(id); - } -} - -SynchedEntityData* Mob::getEntityData() { - return &entityData; -} - -const SynchedEntityData* Mob::getEntityData() const { - return &entityData; -} - -MoveControl* Mob::getMoveControl() { - return moveControl; -} - -JumpControl* Mob::getJumpControl() { - return jumpControl; -} - -void Mob::setYya( float yya ) -{ - this->yya = yya; -} - -float Mob::getSpeed() { - return speed; -} - -void Mob::setSpeed( float speed ) { - this->speed = speed; - this->yya = speed; -} - -void Mob::setJumping(bool jump) { - jumping = jump; -} - -bool Mob::useNewAi() { - return false; -} - -void Mob::checkDespawn() { - checkDespawn(level->getNearestPlayer(this, -1)); -} - -void Mob::checkDespawn(Mob* nearestBlocking) { - if (nearestBlocking != NULL) { - const bool removeIfFar = removeWhenFarAway(); - float xd = nearestBlocking->x - x; - float yd = nearestBlocking->y - y; - float zd = nearestBlocking->z - z; - float sd = xd * xd + yd * yd + zd * zd; - - if (removeIfFar && sd > 96 * 96) { - //LOGI("removed some angry mob more than 10 meters away!\n"); - remove(); - } - - if (noActionTime > 30 * SharedConstants::TicksPerSecond && random.nextInt(800) == 0 && removeIfFar && sd > 32 * 32) - remove(); - else - noActionTime = 0; - } -} -bool Mob::getSharedFlag(int flag) { - return entityData.getFlag (SharedFlagsInformation::DATA_SHARED_FLAGS_ID, flag); -} -void Mob::setSharedFlag(int flag, bool value) { - if(value) { - entityData.setFlag(SharedFlagsInformation::DATA_SHARED_FLAGS_ID, flag); - } - else { - entityData.clearFlag(SharedFlagsInformation::DATA_SHARED_FLAGS_ID, flag); - } -} - -void Mob::updateAttackAnim() { - if (swinging) { - if (++swingTime >= SWING_DURATION) { - swingTime = 0; - swinging = false; - //LOGI("Swinging! %d/%d (%f)\n", swingTime, SWING_DURATION, attackAnim); - } - } else { - swingTime = 0; - } - - attackAnim = swingTime / (float) SWING_DURATION; -} - -void Mob::swing() { - if (!swinging || swingTime >= 3 || swingTime < 0) { - swingTime = -1; - swinging = true; - } -} - -bool Mob::isSneaking() { - return getSharedFlag(SharedFlagsInformation::FLAG_SNEAKING); -} - -bool Mob::isSleeping() { - return false; -} - -void Mob::setSneaking(bool value) { - setSharedFlag(SharedFlagsInformation::FLAG_SNEAKING, value); -} - -// -// Armor -// -int Mob::getDamageAfterArmorAbsorb(int damage) { - int absorb = 25 - getArmorValue(); - int v = (damage) * absorb + dmgSpill; - hurtArmor(damage); - damage = v / 25; - dmgSpill = v % 25; - return damage; -} - -static std::vector getEquipmentSlots() { - return std::vector(); -} - -int Mob::getArmorValue() { - int val = 0; - /* - const std::vector items = getEquipmentSlots(); - for (unsigned int i = 0; i < items.size(); ++i) { - ItemInstance* item = items[i]; - if (item != NULL && ItemInstance::isArmorItem(item)) { - int baseProtection = ((ArmorItem*) item->getItem())->defense; - val += baseProtection; - } - } - */ - return val; -} - -void Mob::hurtArmor(int damage) {} +#include "Mob.hpp" + +#include + +#include "player/Player.hpp" +#include "SharedFlags.hpp" +#include "world/entity/EntityEvent.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Random.hpp" +#include "util/PerfTimer.hpp" + +#include "nbt/CompoundTag.hpp" + +#include "network/RakNetInstance.hpp" +#include "network/packet/MoveEntityPacket.hpp" +#include "ai/control/MoveControl.hpp" +#include "ai/control/JumpControl.hpp" +#include "ai/PathNavigation.hpp" +#include "ai/Sensing.hpp" +#include "ai/goal/GoalSelector.hpp" +#include "network/packet/SetEntityMotionPacket.hpp" +#include "world/item/ArmorItem.hpp" + + +Mob::Mob(Level* level) +: super(level), + invulnerableDuration(20), + //hasHair(false), + textureName("mob/char.png"), + capeTextureName(""), + allowAlpha(true), + modelName(""), + bobStrength(1), + deathScore(0), + renderOffset(0), + //interpolateOnly(false), + lookingAtId(0), + jumping(false), + defaultLookAngle(0.0f), + runSpeed(0.7f), + walkingSpeed(0.1f), + flyingSpeed(0.02f), + run(0), oRun(0), + animStep(0), animStepO(0), + lx(0), ly(0), lz(0), lxr(0), lyr(0), + lSteps(0), + walkAnimSpeed(0), walkAnimSpeedO(0), walkAnimPos(0), + attackAnim(0), oAttackAnim(0), + + autoSendPosRot(true), + sentX(0), sentY(0), sentZ(0), + sentRotX(0), sentRotY(0), + sentXd(0), sentYd(0), sentZd(0), + arrowCount(0), + removeArrowTime(0), + speed(0), + moveControl(NULL), + jumpControl(NULL), + navigation(NULL), + goalSelector(NULL), + targetSelector(NULL), + sensing(NULL), + swinging(false), + swingTime(0), + lastHurt(0), + dmgSpill(0), + bypassArmor(false) +{ + entityData.define(SharedFlagsInformation::DATA_SHARED_FLAGS_ID, (SynchedEntityData::TypeChar) 0); + entityData.define(DATA_AIR_SUPPLY_ID, (SynchedEntityData::TypeShort) TOTAL_AIR_SUPPLY); + + _init(); + health = getMaxHealth(); + + blocksBuilding = true; + ambientSoundTime = -level->random.nextInt(100); + + rotA = (float) (Mth::random() + 1) * 0.01f; + setPos(x, y, z); + timeOffs = (float) Mth::random() * 12398; + yRot = (float) (Mth::random() * Mth::PI * 2); + + this->footSize = 0.5f; + + // Initialize cape inertia positions + xCape = x; + yCape = y; + zCape = z; + + xc = xCape; + yc = yCape; + zc = zCape; +} + +Mob::~Mob() { + //LOGI("destroying an entity! %p\n", this); +} + +float Mob::getWalkingSpeedModifier() { + float speed = 0.7f; // is 1.0f in desktop Minecraft + + //if (hasEffect(MobEffect.movementSpeed)) { + // speed *= 1.0f + .2f * (getEffect(MobEffect.movementSpeed).getAmplifier() + 1); + //} + //if (hasEffect(MobEffect.movementSlowdown)) { + // speed *= 1.0f - .15f * (getEffect(MobEffect.movementSlowdown).getAmplifier() + 1); + //} + return speed; +} + +bool Mob::canSee( Entity* target ) +{ + return !level->clip(Vec3(x, y + getHeadHeight(), z), Vec3(target->x, target->y + target->getHeadHeight(), target->z)).isHit(); +} + +std::string Mob::getTexture() +{ + return textureName; +} + +void Mob::setTextureName(const std::string& name) +{ + textureName = name; +} + +std::string Mob::getCapeTexture() +{ + return capeTextureName; +} + +void Mob::setCapeTextureName(const std::string& name) +{ + capeTextureName = name; +} + +bool Mob::isPickable() +{ + return !removed; +} + +bool Mob::isPushable() +{ + return !removed; +} + +float Mob::getHeadHeight() +{ + return bbHeight * 0.85f; +} + +float Mob::getVoicePitch() { + if (isBaby()) { + return (random.nextFloat() - random.nextFloat()) * 0.2f + 1.5f; + } + return (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f; +} + +int Mob::getAmbientSoundInterval() +{ + return 8 * SharedConstants::TicksPerSecond; +} + +void Mob::playAmbientSound() +{ + const char* ambient = getAmbientSound(); + if (ambient != NULL) { + level->playSound(this, ambient, getSoundVolume(), getVoicePitch()); + } +} + +void Mob::baseTick() +{ + oAttackAnim = attackAnim; + super::baseTick(); + + TIMER_PUSH("mobBaseTick"); + + if (((ambientSoundTime++ & 15) == 0) && random.nextInt(2000) < ambientSoundTime) { + ambientSoundTime = -getAmbientSoundInterval(); + playAmbientSound(); + } + + if (isAlive() && isInWall()) { + hurt(NULL, 1); + } + + //if (fireImmune || level.isOnline) onFire = 0; + + if (isAlive() && isUnderLiquid(Material::water) && !isWaterMob()) { + airSupply--; + if (airSupply == -20) { + airSupply = 0; + for (int i = 0; i < 8; i++) { + float xo = random.nextFloat() - random.nextFloat(); + float yo = random.nextFloat() - random.nextFloat(); + float zo = random.nextFloat() - random.nextFloat(); + level->addParticle(PARTICLETYPE(bubble), x + xo, y + yo, z + zo, xd, yd, zd); + } + hurt(NULL, 2); + } + //onFire = 0; + } else { + airSupply = airCapacity; + } + + oTilt = tilt; + if (attackTime > 0) attackTime--; + if (hurtTime > 0) hurtTime--; + if (invulnerableTime > 0) invulnerableTime--; + + if (health <= 0) { + deathTime++; + if (deathTime > SharedConstants::TicksPerSecond) { + beforeRemove(); + remove(); + for (int i = 0; i < 20; i++) { + float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); + } + } + } + + animStepO = animStep; + + yBodyRotO = yBodyRot; + yRotO = yRot; + xRotO = xRot; + + TIMER_POP(); + + if (!level->isClientSide) { + if (autoSendPosRot) { + if (autoSendPosRot && (std::abs(x - sentX) > .1f || std::abs(y - sentY) > .05f || std::abs(z - sentZ) > .1f || std::abs(sentRotX - xRot) > 1 || std::abs(sentRotY - yRot) > 1)) { + MoveEntityPacket_PosRot packet(this); + level->raknetInstance->send(packet); + sentX = x; + sentY = y; + sentZ = z; + sentRotX = xRot; + sentRotY = yRot; + } + } + + float ddx = std::abs(xd - sentXd); + float ddy = std::abs(yd - sentYd); + float ddz = std::abs(zd - sentZd); + const float max = 0.02f; + const float diff = ddx*ddx + ddy*ddy + ddz*ddz; + if (diff > max*max || (diff > 0 && xd == 0 && yd == 0 && zd == 0)) { + sentXd = xd; + sentYd = yd; + sentZd = zd; + SetEntityMotionPacket packet(this); + level->raknetInstance->send(packet); + //LOGI("Motion-packet: %d\n", entityId); + } + } +} + +void Mob::spawnAnim() +{ + /* + for (int i = 0; i < 20; i++) { + float xa = random.nextGaussian() * 0.02; + float ya = random.nextGaussian() * 0.02; + float za = random.nextGaussian() * 0.02; + float dd = 10; + level.addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth - xa * dd, y + random.nextFloat() * bbHeight - ya * dd, z + random.nextFloat() * bbWidth * 2 - bbWidth - za + * dd, xa, ya, za); + } + */ +} + +void Mob::lerpTo( float x, float y, float z, float yRot, float xRot, int steps ) +{ + //heightOffset = 0; + lx = x; + ly = y + heightOffset; + lz = z; + lyr = yRot; + lxr = xRot; + + lSteps = steps; +} + +void Mob::superTick() +{ + super::tick(); +} + +void Mob::tick() +{ + xc = xCape; + yc = yCape; + zc = zCape; + + super::tick(); + + if (arrowCount > 0) { + if (removeArrowTime <= 0) { + removeArrowTime = 20 * 3; + } + removeArrowTime--; + if (removeArrowTime <= 0) { + arrowCount--; + } + } + + if (lSteps > 0) { + float xt = x + (lx - x) / lSteps; + float yt = y + (ly - y) / lSteps; + float zt = z + (lz - z) / lSteps; + + float yrd = lyr - yRot; + while (yrd < -180) + yrd += 360; + while (yrd >= 180) + yrd -= 360; + + yRot += (yrd) / lSteps; + xRot += (lxr - xRot) / lSteps; + + lSteps--; + this->setPos(xt, yt, zt); + this->setRot(yRot, xRot); + } + + aiStep(); + + updateWalkAnim(); + + float xd = x - xo; + float zd = z - zo; + + float sideDist = (float) Mth::sqrt(xd * xd + zd * zd); + + float yBodyRotT = yBodyRot; + + float walkSpeed = 0; + oRun = run; + float tRun = 0; + if (sideDist <= 0.05f) { + // animStep = 0; + } else { + tRun = 1; + walkSpeed = sideDist * 3; + yBodyRotT = Mth::atan2(zd, xd) * Mth::RADDEG - 90; + } + if (attackAnim > 0) { + yBodyRotT = yRot; + } + if (!onGround) { + tRun = 0; + } + run = run + (tRun - run) * 0.3f; + + /* + * float yBodyRotD = yRot-yBodyRot; while (yBodyRotD < -180) yBodyRotD + * += 360; while (yBodyRotD >= 180) yBodyRotD -= 360; yBodyRot += + * yBodyRotD * 0.1f; + */ + + float yBodyRotD = yBodyRotT - yBodyRot; + while (yBodyRotD < -180) + yBodyRotD += 360; + while (yBodyRotD >= 180) + yBodyRotD -= 360; + yBodyRot += yBodyRotD * 0.3f; + + float headDiff = yRot - yBodyRot; + while (headDiff < -180) + headDiff += 360; + while (headDiff >= 180) + headDiff -= 360; + bool behind = headDiff < -90 || headDiff >= 90; + if (headDiff < -75) headDiff = -75; + if (headDiff >= 75) headDiff = +75; + yBodyRot = yRot - headDiff; + if (headDiff * headDiff > 50 * 50) { + yBodyRot += headDiff * 0.2f; + } + + if (behind) { + walkSpeed *= -1; + } + while (yRot - yRotO < -180) + yRotO -= 360; + while (yRot - yRotO >= 180) + yRotO += 360; + + while (yBodyRot - yBodyRotO < -180) + yBodyRotO -= 360; + while (yBodyRot - yBodyRotO >= 180) + yBodyRotO += 360; + + while (xRot - xRotO < -180) + xRotO -= 360; + while (xRot - xRotO >= 180) + xRotO += 360; + animStep += walkSpeed; + + // Reduce jitter by using a smaller interpolation factor (more lag, smoother motion) + double dxCape = x - xCape; + double dyCape = y - yCape; + double dzCape = z - zCape; + + const double interp = 0.15; // small value for smoother cape motion + const double interpY = 0.12; // extra smoothing on vertical movement + + xCape += dxCape * interp; + yCape += dyCape * interpY; + zCape += dzCape * interp; +} + +void Mob::setSize( float w, float h ) +{ + super::setSize(w, h); +} + +void Mob::heal( int heal ) +{ + if (health <= 0) return; + health += heal; + if (health > 20) health = 20; + invulnerableTime = invulnerableDuration / 2; +} + +bool Mob::hurt( Entity* source, int dmg ) +{ + if (level->isClientSide) return false; + noActionTime = 0; + if (health <= 0) return false; + + this->walkAnimSpeed = 1.5f; + + bool sound = true; + if (invulnerableTime > invulnerableDuration / 2.0f) { + if (dmg <= lastHurt) return false; + actuallyHurt(dmg - lastHurt); + lastHurt = dmg; + sound = false; + } else { + lastHurt = dmg; + lastHealth = health; + invulnerableTime = invulnerableDuration; + actuallyHurt(dmg); + hurtTime = hurtDuration = 10; + hurtDuration = 10; + } + + hurtDir = 0; + + if (sound) { + level->broadcastEntityEvent(this, EntityEvent::HURT); + markHurt(); + if (source != NULL) { + float xd = source->x - x; + float zd = source->z - z; + while (xd * xd + zd * zd < 0.0001) { + xd = (Mth::random() - Mth::random()) * 0.01f; + zd = (Mth::random() - Mth::random()) * 0.01f; + } + hurtDir = (float) (std::atan2(zd, xd) * Mth::RADDEG) - yRot; + knockback(source, dmg, xd, zd); + } else { + hurtDir = (int) (Mth::random() * 2.0f) * 180.0f; + } + } + + if (health <= 0) { + if (sound) level->playSound(this, getDeathSound(), getSoundVolume(), getVoicePitch()); + die(source); + } else { + if (sound) level->playSound(this, getHurtSound(), getSoundVolume(), getVoicePitch()); + } + + return true; +} + +void Mob::actuallyHurt( int dmg ) +{ + if (!bypassArmor) { + dmg = getDamageAfterArmorAbsorb(dmg); + } + health -= dmg; +} + +float Mob::getSoundVolume() +{ + return 1; +} + +const char* Mob::getAmbientSound() +{ + return NULL; +} + +std::string Mob::getHurtSound() +{ + return "random.hurt"; +} + +std::string Mob::getDeathSound() +{ + return "random.hurt"; +} + +void Mob::knockback( Entity* source, int dmg, float xd, float zd ) +{ + float dd = Mth::invSqrt(xd * xd + zd * zd); + float pow = 0.4f; + + this->xd *= 0.5f; + this->yd *= 0.5f; + this->zd *= 0.5f; + + this->xd -= xd * dd * pow; + this->yd += 0.4f; + this->zd -= zd * dd * pow; + + if (this->yd > 0.4f) this->yd = 0.4f; +} + +void Mob::die( Entity* source ) +{ + if (deathScore > 0 && source != NULL) source->awardKillScore(this, deathScore); + + if (!level->isClientSide) { + if (!isBaby()) { + dropDeathLoot(); + } + level->broadcastEntityEvent(this, EntityEvent::DEATH); + } +} + +void Mob::dropDeathLoot() +{ + int loot = getDeathLoot(); + if (loot > 0) { + int count = random.nextInt(3); + for (int i = 0; i < count; i++) + spawnAtLocation(loot, 1); + } +} + +int Mob::getDeathLoot() +{ + return 0; +} + +void Mob::reset() { + super::reset(); + this->_init(); +} + +void Mob::_init() { + yBodyRot = 0; + yBodyRotO = 0; + rotOffs = 0; + fallTime = 0; + lastHurt = 0; + deathTime = 0; + attackTime = 0; + tilt = 0; + oTilt = 0; + hurtDuration = 0; + hurtTime = 0; + hurtDir = 0; + lookTime = 0; + noActionTime = 0; + xxa = 0; yya = 0; + yRotA = 0; + + health = 10; + lastHealth = 20; +} + +void Mob::causeFallDamage( float distance ) +{ + int dmg = (int) ceil((distance - 3)); + + if (dmg > 0) { + level->playSound(this, (dmg > 4)?"damage.fallbig":"damage.fallsmall", 0.75f, 1); + + hurt(NULL, dmg); + + int t = level->getTile(Mth::floor(x), Mth::floor(y - 0.2f - this->heightOffset), Mth::floor(z)); + if (t > 0) { + const Tile::SoundType* soundType = Tile::tiles[t]->soundType; + level->playSound(this, soundType->getStepSound(), soundType->getVolume() * 0.5f, soundType->getPitch() * 0.75f); + } + } +} + +void Mob::travel( float xa, float ya ) +{ + if (isInWater()) { + float yo = y; + moveRelative(xa, ya, 0.02f); + move(xd, yd, zd); + + xd *= 0.80f; + yd *= 0.80f; + zd *= 0.80f; + yd -= 0.02f; + + if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) { + yd = 0.3f; + } + } else if (isInLava()) { + float yo = y; + moveRelative(xa, ya, 0.02f); + move(xd, yd, zd); + xd *= 0.50f; + yd *= 0.50f; + zd *= 0.50f; + yd -= 0.02f; + + if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) { + yd = 0.3f; + } + } else { + float friction = 0.91f; + if (onGround) { + friction = 0.6f * 0.91f; + int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); + if (t > 0) { + friction = Tile::tiles[t]->friction * 0.91f; + } + } + + float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction); + moveRelative(xa, ya, (onGround ? walkingSpeed * friction2 : flyingSpeed)); + + friction = 0.91f; + if (onGround) { + friction = 0.6f * 0.91f; + int t = level->getTile(Mth::floor(x), Mth::floor(bb.y0 - 0.5f), Mth::floor(z)); + if (t > 0) { + friction = Tile::tiles[t]->friction * 0.91f; + } + } + //@todo: make it easier to climb ladders + if (onLadder()) { + this->fallDistance = 0; + if (yd < -0.15) yd = -0.15f; + if (isSneaking() && yd < 0) yd = 0; + } + + move(xd, yd, zd); + + //@todo: make it easier to climb ladders + if (horizontalCollision && onLadder()) { + yd = 0.2f; + } + + yd -= 0.08f; + yd *= 0.98f; + xd *= friction; + zd *= friction; + } + +} + +void Mob::updateWalkAnim() +{ + walkAnimSpeedO = walkAnimSpeed; + float xxd = x - xo; + float zzd = z - zo; + float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4; + if (wst > 1) wst = 1; + walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; + walkAnimPos += walkAnimSpeed; +} + +bool Mob::onLadder() +{ + int xt = Mth::floor(x); + int yt = Mth::floor(bb.y0); + int zt = Mth::floor(z); + return level->getTile(xt, yt, zt) == Tile::ladder->id || level->getTile(xt, yt + 1, zt) == Tile::ladder->id; +} + +bool Mob::isShootable() +{ + return true; +} + +void Mob::addAdditonalSaveData( CompoundTag* entityTag ) +{ + entityTag->putShort("Health", (short) health); + entityTag->putShort("HurtTime", (short) hurtTime); + entityTag->putShort("DeathTime", (short) deathTime); + entityTag->putShort("AttackTime", (short) attackTime); + + //if (isPlayer()) LOGI("Saving %d, %d, %d, %d\n", health, hurtTime, deathTime, attackTime); +} + +void Mob::readAdditionalSaveData( CompoundTag* tag ) +{ + health = tag->getShort("Health"); + hurtTime = tag->getShort("HurtTime"); + deathTime = tag->getShort("DeathTime"); + attackTime = tag->getShort("AttackTime"); + + //if (isPlayer()) LOGI("Reading %d, %d, %d, %d\n", health, hurtTime, deathTime, attackTime); +} + +void Mob::animateHurt() +{ + hurtTime = hurtDuration = 10; + hurtDir = 0; +} + +bool Mob::isAlive() +{ + return !removed && health > 0; +} + +bool Mob::isWaterMob() +{ + return false; +} + +void Mob::aiStep() +{ + //@todo? 30 lines of code here in java version + + TIMER_PUSH("ai"); + if (isImmobile()) { + jumping = false; + xxa = 0; + yya = 0; + yRotA = 0; + } else { + if (!interpolateOnly()) { + if (useNewAi()) { + TIMER_PUSH("newAi"); + newServerAiStep(); + TIMER_POP(); + } + else { + TIMER_PUSH("oldAi"); + updateAi(); + TIMER_POP(); + } + } + } + TIMER_POP_PUSH("move"); + + bool inWater = isInWater(); + bool inLava = isInLava(); + + if (jumping) { + if (inWater) { + yd += 0.04f; + } else if (inLava) { + yd += 0.04f; + } else if (onGround) { + jumpFromGround(); + } + } + + xxa *= 0.98f; + yya *= 0.98f; + yRotA *= 0.9f; + + float normalSpeed = walkingSpeed; + float normalAirControllSpeed = flyingSpeed; + walkingSpeed *= getWalkingSpeedModifier(); + flyingSpeed *= getWalkingSpeedModifier(); + travel(xxa, yya); + walkingSpeed = normalSpeed; + flyingSpeed = normalAirControllSpeed; + + TIMER_POP_PUSH("push"); + Player* player = NULL; + if(isPlayer()) { + player = (Player*)this; + } + if(player == NULL || !player->isSleeping()) { + EntityList& entities = level->getEntities(this, this->bb.grow(0.2f, 0, 0.2f)); + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + if(e->isPlayer()) { + Player* p = (Player*)e; + if(p->isSleeping()) + continue; + } + if (e->isPushable()) e->push(this); + } + } + TIMER_POP(); +} + +/*protected*/ +void Mob::updateAi() { + noActionTime++; + + Player* player = level->getNearestPlayer(this, -1); + checkDespawn(player); + + xxa = 0; + yya = 0; + + float lookDistance = 8; + if (random.nextFloat() < 0.02f) { + player = level->getNearestPlayer(this, lookDistance); + if (player != NULL) { + lookingAtId = player->entityId; + lookTime = 10 + random.nextInt(20); + } else { + yRotA = (random.nextFloat() - 0.5f) * 20; + } + } + + if (lookingAtId != 0) { + Entity* lookingAt = level->getEntity(lookingAtId); + lookingAtId = 0; + if (lookingAt != NULL) { + lookAt(lookingAt, 10, (float)getMaxHeadXRot()); + if (lookTime-- <= 0 || lookingAt->removed || lookingAt->distanceToSqr(this) > lookDistance * lookDistance) { + lookingAtId = 0; + } else { + lookingAtId = lookingAt->entityId; + } + } + } else { + if (random.nextFloat() < 0.05f) { + yRotA = (random.nextFloat() - 0.5f) * 20; + } + yRot += yRotA; + xRot = defaultLookAngle; + } + + bool inWater = isInWater(); + bool inLava = isInLava(); + if (inWater || inLava) jumping = random.nextFloat() < 0.8f; +} + +void Mob::newServerAiStep() { + noActionTime++; + + TIMER_PUSH("checkDespawn"); + checkDespawn(); + jumping = false; + + TIMER_POP_PUSH("sensing"); + if (sensing) sensing->tick(); + + if (random.nextInt(5) == 0) { + TIMER_POP_PUSH("targetSelector"); + //LOGI("tg1\n"); + if (targetSelector) targetSelector->tick(); + //LOGI("tg2\n"); + + TIMER_POP_PUSH("goalSelector"); + //LOGI("gs1\n"); + if (goalSelector) goalSelector->tick(); + //LOGI("gs2\n"); + } + + TIMER_POP_PUSH("navigation"); + if (navigation) navigation->tick(); + + //TIMER_POP_PUSH("mob tick"); + //serverAiMobStep(); + + TIMER_POP_PUSH("controls"); + if (moveControl) moveControl->tick(); //@todo; we shouldn't be here if not + if (jumpControl) jumpControl->tick(); + + TIMER_POP(); +} + +bool Mob::isImmobile() +{ + return health <= 0; +} + +void Mob::jumpFromGround() +{ + yd = 0.42f; +} + +bool Mob::removeWhenFarAway() +{ + return true; +} + +int Mob::getMaxHeadXRot() +{ + return 10; +} + +void Mob::lookAt( Entity* e, float yMax, float xMax ) +{ + float xd = e->x - x; + float yd; + float zd = e->z - z; + + if (false) { //if (e->isMob()) { //@todo? + Mob* mob = (Mob*) e; + yd = (y + getHeadHeight()) - (mob->y + mob->getHeadHeight()); + } else { + yd = (e->bb.y0 + e->bb.y1) / 2 - (y + getHeadHeight()); + } + + float sd = Mth::sqrt(xd * xd + zd * zd); + + float yRotD = (float) (atan2(zd, xd) * 180 / Mth::PI) - 90; + float xRotD = (float) (atan2(yd, sd) * 180 / Mth::PI); + xRot = -rotlerp(xRot, xRotD, xMax); + yRot = rotlerp(yRot, yRotD, yMax); +} + +bool Mob::isLookingAtAnEntity() +{ + return lookingAtId != 0; +} + +//Entity* Mob::getLookingAt() +//{ +// return lookingAt; +//} + +float Mob::rotlerp( float a, float b, float max ) +{ + float diff = b - a; + while (diff < -180) + diff += 360; + while (diff >= 180) + diff -= 360; + if (diff > max) { + diff = max; + } + if (diff < -max) { + diff = -max; + } + return a + diff; +} + +void Mob::beforeRemove() +{ +} + +bool Mob::canSpawn() +{ + return level->isUnobstructed(bb) && level->getCubes(this, bb).size() == 0 && !level->containsAnyLiquid(bb); +} + +void Mob::outOfWorld() +{ + int oldHealth = health; + hurt(NULL, 4); + if (health >= oldHealth) + actuallyHurt(4); +} + +float Mob::getAttackAnim( float a ) +{ + float diff = attackAnim - oAttackAnim; + if (diff < 0) diff += 1; + return oAttackAnim + diff * a; +} + +Vec3 Mob::getPos( float a ) +{ + if (a == 1) { + return Vec3(x, y, z); + } + float x = xo + (this->x - xo) * a; + float y = yo + (this->y - yo) * a; + float z = zo + (this->z - zo) * a; + + return Vec3(x, y, z); +} + +Vec3 Mob::getLookAngle() +{ + return getViewVector(1); +} + +Vec3 Mob::getViewVector( float a ) +{ + if (a == 1) { + float yCos = (float) Mth::cos(-yRot * Mth::DEGRAD - Mth::PI); + float ySin = (float) Mth::sin(-yRot * Mth::DEGRAD - Mth::PI); + float xCos = (float) -Mth::cos(-xRot * Mth::DEGRAD); + float xSin = (float) Mth::sin(-xRot * Mth::DEGRAD); + + return Vec3(ySin * xCos, xSin, yCos * xCos); // newTemp + } + float xRot = xRotO + (this->xRot - xRotO) * a; + float yRot = yRotO + (this->yRot - yRotO) * a; + + float yCos = (float) Mth::cos(-yRot * Mth::DEGRAD - Mth::PI); + float ySin = (float) Mth::sin(-yRot * Mth::DEGRAD - Mth::PI); + float xCos = (float) -Mth::cos(-xRot * Mth::DEGRAD); + float xSin = (float) Mth::sin(-xRot * Mth::DEGRAD); + + return Vec3(ySin * xCos, xSin, yCos * xCos); // newTemp +} + +HitResult Mob::pick( float range, float a ) +{ + Vec3 from = getPos(a); + return level->clip(from, from + getViewVector(a) * range); +} + +int Mob::getMaxSpawnClusterSize() +{ + return 4; +} + +bool Mob::interpolateOnly() +{ + return level->isClientSide; +} + +//ItemInstance getCarriedItem() { +// return NULL; +//} + +void Mob::handleEntityEvent(char id) { + if (id == EntityEvent::HURT) { + this->walkAnimSpeed = 1.5f; + + invulnerableTime = invulnerableDuration; + hurtTime = hurtDuration = 10; + hurtDir = 0; + + level->playSound(this, getHurtSound(), getSoundVolume(), getVoicePitch()); + hurt(NULL, 0); + } else if (id == EntityEvent::DEATH) { + level->playSound(this, getDeathSound(), getSoundVolume(), getVoicePitch()); + health = 0; + die(NULL); + } else { + super::handleEntityEvent(id); + } +} + +SynchedEntityData* Mob::getEntityData() { + return &entityData; +} + +const SynchedEntityData* Mob::getEntityData() const { + return &entityData; +} + +MoveControl* Mob::getMoveControl() { + return moveControl; +} + +JumpControl* Mob::getJumpControl() { + return jumpControl; +} + +void Mob::setYya( float yya ) +{ + this->yya = yya; +} + +float Mob::getSpeed() { + return speed; +} + +void Mob::setSpeed( float speed ) { + this->speed = speed; + this->yya = speed; +} + +void Mob::setJumping(bool jump) { + jumping = jump; +} + +bool Mob::useNewAi() { + return false; +} + +void Mob::checkDespawn() { + checkDespawn(level->getNearestPlayer(this, -1)); +} + +void Mob::checkDespawn(Mob* nearestBlocking) { + if (nearestBlocking != NULL) { + const bool removeIfFar = removeWhenFarAway(); + float xd = nearestBlocking->x - x; + float yd = nearestBlocking->y - y; + float zd = nearestBlocking->z - z; + float sd = xd * xd + yd * yd + zd * zd; + + if (removeIfFar && sd > 96 * 96) { + //LOGI("removed some angry mob more than 10 meters away!\n"); + remove(); + } + + if (noActionTime > 30 * SharedConstants::TicksPerSecond && random.nextInt(800) == 0 && removeIfFar && sd > 32 * 32) + remove(); + else + noActionTime = 0; + } +} +bool Mob::getSharedFlag(int flag) { + return entityData.getFlag (SharedFlagsInformation::DATA_SHARED_FLAGS_ID, flag); +} +void Mob::setSharedFlag(int flag, bool value) { + if(value) { + entityData.setFlag(SharedFlagsInformation::DATA_SHARED_FLAGS_ID, flag); + } + else { + entityData.clearFlag(SharedFlagsInformation::DATA_SHARED_FLAGS_ID, flag); + } +} + +void Mob::updateAttackAnim() { + if (swinging) { + if (++swingTime >= SWING_DURATION) { + swingTime = 0; + swinging = false; + //LOGI("Swinging! %d/%d (%f)\n", swingTime, SWING_DURATION, attackAnim); + } + } else { + swingTime = 0; + } + + attackAnim = swingTime / (float) SWING_DURATION; +} + +void Mob::swing() { + if (!swinging || swingTime >= 3 || swingTime < 0) { + swingTime = -1; + swinging = true; + } +} + +bool Mob::isSneaking() { + return getSharedFlag(SharedFlagsInformation::FLAG_SNEAKING); +} + +bool Mob::isSleeping() { + return false; +} + +void Mob::setSneaking(bool value) { + setSharedFlag(SharedFlagsInformation::FLAG_SNEAKING, value); +} + +// +// Armor +// +int Mob::getDamageAfterArmorAbsorb(int damage) { + int absorb = 25 - getArmorValue(); + int v = (damage) * absorb + dmgSpill; + hurtArmor(damage); + damage = v / 25; + dmgSpill = v % 25; + return damage; +} + +static std::vector getEquipmentSlots() { + return std::vector(); +} + +int Mob::getArmorValue() { + int val = 0; + /* + const std::vector items = getEquipmentSlots(); + for (unsigned int i = 0; i < items.size(); ++i) { + ItemInstance* item = items[i]; + if (item != NULL && ItemInstance::isArmorItem(item)) { + int baseProtection = ((ArmorItem*) item->getItem())->defense; + val += baseProtection; + } + } + */ + return val; +} + +void Mob::hurtArmor(int damage) {} diff --git a/src/world/entity/Mob.h b/src/world/entity/Mob.hpp similarity index 98% rename from src/world/entity/Mob.h rename to src/world/entity/Mob.hpp index 5ffecb2..651fde2 100755 --- a/src/world/entity/Mob.h +++ b/src/world/entity/Mob.hpp @@ -3,9 +3,9 @@ //package net.minecraft.world.entity; #include -#include "Entity.h" -#include "EntityTypes.h" -#include "SynchedEntityData.h" +#include "Entity.hpp" +#include "EntityTypes.hpp" +#include "SynchedEntityData.hpp" class CompoundTag; diff --git a/src/world/entity/MobCategory.cpp b/src/world/entity/MobCategory.cpp index 01bc9e4..e6ddec1 100755 --- a/src/world/entity/MobCategory.cpp +++ b/src/world/entity/MobCategory.cpp @@ -1,50 +1,50 @@ -#ifndef NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__ -#define NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__ - -#include "EntityTypes.h" -#include "MobCategory.h" -#include "../level/material/Material.h" - - -const MobCategory MobCategory::monster( - MobTypes::BaseEnemy, - 10, - 20, - false); - - // - -const MobCategory MobCategory::creature( - MobTypes::BaseCreature, - 10, - 15, - true); - - // - -const MobCategory MobCategory::waterCreature( - MobTypes::BaseWaterCreature, - 5, - 10, - true); - -// -// Init an array with all defined MobCategory'ies -// -const MobCategory* const MobCategory::values[] = { - &MobCategory::monster, - &MobCategory::creature, - &MobCategory::waterCreature -}; - -/*static*/ -void MobCategory::initMobCategories() { - monster.setMaterial(Material::air); - creature.setMaterial(Material::air); - waterCreature.setMaterial(Material::water); -} - - -const int MobCategory::numValues = sizeof(values) / sizeof(values[0]); - -#endif /*NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__*/ +#ifndef NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__ +#define NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__ + +#include "EntityTypes.hpp" +#include "MobCategory.hpp" +#include "world/level/material/Material.hpp" + + +const MobCategory MobCategory::monster( + MobTypes::BaseEnemy, + 10, + 20, + false); + + // + +const MobCategory MobCategory::creature( + MobTypes::BaseCreature, + 10, + 15, + true); + + // + +const MobCategory MobCategory::waterCreature( + MobTypes::BaseWaterCreature, + 5, + 10, + true); + +// +// Init an array with all defined MobCategory'ies +// +const MobCategory* const MobCategory::values[] = { + &MobCategory::monster, + &MobCategory::creature, + &MobCategory::waterCreature +}; + +/*static*/ +void MobCategory::initMobCategories() { + monster.setMaterial(Material::air); + creature.setMaterial(Material::air); + waterCreature.setMaterial(Material::water); +} + + +const int MobCategory::numValues = sizeof(values) / sizeof(values[0]); + +#endif /*NET_MINECRAFT_WORLD_ENTITY__MobCategory_H__*/ diff --git a/src/world/entity/MobCategory.h b/src/world/entity/MobCategory.hpp similarity index 93% rename from src/world/entity/MobCategory.h rename to src/world/entity/MobCategory.hpp index 3b4c829..02fdd75 100755 --- a/src/world/entity/MobCategory.h +++ b/src/world/entity/MobCategory.hpp @@ -1,60 +1,60 @@ -//package net.minecraft.world.entity; - -#include "../../platform/log.h" - -class Material; - -class MobCategory -{ -public: - static void initMobCategories(); - - // - static const MobCategory monster; - static const MobCategory creature; - static const MobCategory waterCreature; - //@todo: rewrite to std::vector with [] init - static const MobCategory* const values[]; - static const int numValues; - - int getBaseClassId() const { - return _baseClassId; - } - - int getMaxInstancesPerChunk() const { - return _max; - } - - int getMaxInstancesPerLevel() const { - return _maxPerLevel; - } - - const Material* getSpawnPositionMaterial() const { - return _spawnPositionMaterial; - } - - bool isFriendly() const { - return _isFriendly; - } - -private: - const int _baseClassId; - const int _max; - const int _maxPerLevel; - mutable const Material* _spawnPositionMaterial; - const bool _isFriendly; - - MobCategory(int baseClassId, int max, int maxPerLevel, bool isFriendly) - : _baseClassId(baseClassId), - _max(max), - _maxPerLevel(maxPerLevel), - _spawnPositionMaterial(NULL), - _isFriendly(isFriendly) - { - //LOGI("Creating a Mobcategory: %d, %d, %p, %d ", _baseClassId, _max, _spawnPositionMaterial, _isFriendly); - } - - void setMaterial(const Material* material) const { - _spawnPositionMaterial = material; - } -}; +//package net.minecraft.world.entity; + +#include "platform/log.hpp" + +class Material; + +class MobCategory +{ +public: + static void initMobCategories(); + + // + static const MobCategory monster; + static const MobCategory creature; + static const MobCategory waterCreature; + //@todo: rewrite to std::vector with [] init + static const MobCategory* const values[]; + static const int numValues; + + int getBaseClassId() const { + return _baseClassId; + } + + int getMaxInstancesPerChunk() const { + return _max; + } + + int getMaxInstancesPerLevel() const { + return _maxPerLevel; + } + + const Material* getSpawnPositionMaterial() const { + return _spawnPositionMaterial; + } + + bool isFriendly() const { + return _isFriendly; + } + +private: + const int _baseClassId; + const int _max; + const int _maxPerLevel; + mutable const Material* _spawnPositionMaterial; + const bool _isFriendly; + + MobCategory(int baseClassId, int max, int maxPerLevel, bool isFriendly) + : _baseClassId(baseClassId), + _max(max), + _maxPerLevel(maxPerLevel), + _spawnPositionMaterial(NULL), + _isFriendly(isFriendly) + { + //LOGI("Creating a Mobcategory: %d, %d, %p, %d ", _baseClassId, _max, _spawnPositionMaterial, _isFriendly); + } + + void setMaterial(const Material* material) const { + _spawnPositionMaterial = material; + } +}; diff --git a/src/world/entity/MobFactory.h b/src/world/entity/MobFactory.hpp similarity index 94% rename from src/world/entity/MobFactory.h rename to src/world/entity/MobFactory.hpp index 0cb8b58..a845aee 100755 --- a/src/world/entity/MobFactory.h +++ b/src/world/entity/MobFactory.hpp @@ -1,8 +1,8 @@ #pragma once -#include "EntityTypes.h" -#include "animal/AnimalInclude.h" -#include "monster/MonsterInclude.h" +#include "EntityTypes.hpp" +#include "animal/AnimalInclude.hpp" +#include "monster/MonsterInclude.hpp" class MobFactory { public: diff --git a/src/world/entity/Motive.cpp b/src/world/entity/Motive.cpp index e14aa19..ef2e223 100755 --- a/src/world/entity/Motive.cpp +++ b/src/world/entity/Motive.cpp @@ -1,84 +1,84 @@ -#include "Motive.h" -const Motive Motive::Kebab("Kebab", 16, 16, 0 * 16, 0 * 16); -const Motive Motive::Aztec("Aztec", 16, 16, 1 * 16, 0 * 16); -const Motive Motive::Alban("Alban", 16, 16, 2 * 16, 0 * 16); -const Motive Motive::Aztec2("Aztec2", 16, 16, 3 * 16, 0 * 16); -const Motive Motive::Bomb("Bomb", 16, 16, 4 * 16, 0 * 16); -const Motive Motive::Plant("Plant", 16, 16, 5 * 16, 0 * 16); -const Motive Motive::Wasteland("Wasteland", 16, 16, 6 * 16, 0 * 16); -const Motive Motive::Pool("Pool", 32, 16, 0 * 16, 2 * 16); -const Motive Motive::Courbet("Courbet", 32, 16, 2 * 16, 2 * 16); -const Motive Motive::Sea("Sea", 32, 16, 4 * 16, 2 * 16); -const Motive Motive::Sunset("Sunset", 32, 16, 6 * 16, 2 * 16); -const Motive Motive::Creebet("Creebet", 32, 16, 8 * 16, 2 * 16); -const Motive Motive::Wanderer("Wanderer", 16, 32, 0 * 16, 4 * 16); -const Motive Motive::Graham("Graham", 16, 32, 1 * 16, 4 * 16); -const Motive Motive::Match("Match", 32, 32, 0 * 16, 8 * 16); -const Motive Motive::Bust("Bust", 32, 32, 2 * 16, 8 * 16); -const Motive Motive::Stage("Stage", 32, 32, 4 * 16, 8 * 16); -const Motive Motive::Void("Void", 32, 32, 6 * 16, 8 * 16); -const Motive Motive::SkullAndRoses("SkullAndRoses", 32, 32, 8 * 16, 8 * 16); -const Motive Motive::Fighters("Fighters", 64, 32, 0 * 16, 6 * 16); -const Motive Motive::Pointer("Pointer", 64, 64, 0 * 16, 12 * 16); -const Motive Motive::Pigscene("Pigscene", 64, 64, 4 * 16, 12 * 16); -const Motive Motive::BurningSkull("BurningSkull", 64, 64, 8 * 16, 12 * 16); -const Motive Motive::Skeleton("Skeleton", 64, 48, 12 * 16, 4 * 16); -const Motive Motive::DonkeyKong("DonkeyKong", 64, 48, 12 * 16, 7 * 16); -const Motive Motive::Earth("Earth", 32, 32, 0 * 16, 10 * 16, false); -const Motive Motive::Wind("Wind", 32, 32, 2 * 16, 10 * 16, false); -const Motive Motive::Fire("Fire", 32, 32, 4 * 16, 10 * 16, false); -const Motive Motive::Water("Water", 32, 32, 6 * 16, 10 * 16, false); -const Motive* Motive::DefaultImage = &Motive::Kebab; - -std::vector Motive::getAllMotivesAsList() { - std::vector motives; - motives.push_back(&Kebab); - motives.push_back(&Aztec2); - motives.push_back(&Alban); - motives.push_back(&Bomb); - motives.push_back(&Plant); - motives.push_back(&Wasteland); - motives.push_back(&Pool); - motives.push_back(&Courbet); - motives.push_back(&Sea); - motives.push_back(&Sunset); - motives.push_back(&Creebet); - motives.push_back(&Wanderer); - motives.push_back(&Graham); - motives.push_back(&Match); - motives.push_back(&Bust); - motives.push_back(&Stage); - motives.push_back(&Void); - motives.push_back(&SkullAndRoses); - motives.push_back(&Fighters); - motives.push_back(&Pointer); - motives.push_back(&Pigscene); - motives.push_back(&BurningSkull); - motives.push_back(&Skeleton); - motives.push_back(&DonkeyKong); - - motives.push_back(&Earth); - motives.push_back(&Wind); - motives.push_back(&Fire); - motives.push_back(&Water); - - return motives; -} - -const Motive* Motive::getMotiveByName( const std::string& name ) { - std::vector allMovies = getAllMotivesAsList(); - for(std::vector::iterator i = allMovies.begin(); i != allMovies.end(); ++i) { - if((*i)->name == name) - return *i; - } - return DefaultImage; -} - -Motive::Motive( std::string name, int w, int h, int uo, int vo, bool isPublic /*= true*/ ) -: name(name), - w(w), - h(h), - uo(uo), - vo(vo), - isPublic(isPublic) -{} +#include "Motive.hpp" +const Motive Motive::Kebab("Kebab", 16, 16, 0 * 16, 0 * 16); +const Motive Motive::Aztec("Aztec", 16, 16, 1 * 16, 0 * 16); +const Motive Motive::Alban("Alban", 16, 16, 2 * 16, 0 * 16); +const Motive Motive::Aztec2("Aztec2", 16, 16, 3 * 16, 0 * 16); +const Motive Motive::Bomb("Bomb", 16, 16, 4 * 16, 0 * 16); +const Motive Motive::Plant("Plant", 16, 16, 5 * 16, 0 * 16); +const Motive Motive::Wasteland("Wasteland", 16, 16, 6 * 16, 0 * 16); +const Motive Motive::Pool("Pool", 32, 16, 0 * 16, 2 * 16); +const Motive Motive::Courbet("Courbet", 32, 16, 2 * 16, 2 * 16); +const Motive Motive::Sea("Sea", 32, 16, 4 * 16, 2 * 16); +const Motive Motive::Sunset("Sunset", 32, 16, 6 * 16, 2 * 16); +const Motive Motive::Creebet("Creebet", 32, 16, 8 * 16, 2 * 16); +const Motive Motive::Wanderer("Wanderer", 16, 32, 0 * 16, 4 * 16); +const Motive Motive::Graham("Graham", 16, 32, 1 * 16, 4 * 16); +const Motive Motive::Match("Match", 32, 32, 0 * 16, 8 * 16); +const Motive Motive::Bust("Bust", 32, 32, 2 * 16, 8 * 16); +const Motive Motive::Stage("Stage", 32, 32, 4 * 16, 8 * 16); +const Motive Motive::Void("Void", 32, 32, 6 * 16, 8 * 16); +const Motive Motive::SkullAndRoses("SkullAndRoses", 32, 32, 8 * 16, 8 * 16); +const Motive Motive::Fighters("Fighters", 64, 32, 0 * 16, 6 * 16); +const Motive Motive::Pointer("Pointer", 64, 64, 0 * 16, 12 * 16); +const Motive Motive::Pigscene("Pigscene", 64, 64, 4 * 16, 12 * 16); +const Motive Motive::BurningSkull("BurningSkull", 64, 64, 8 * 16, 12 * 16); +const Motive Motive::Skeleton("Skeleton", 64, 48, 12 * 16, 4 * 16); +const Motive Motive::DonkeyKong("DonkeyKong", 64, 48, 12 * 16, 7 * 16); +const Motive Motive::Earth("Earth", 32, 32, 0 * 16, 10 * 16, false); +const Motive Motive::Wind("Wind", 32, 32, 2 * 16, 10 * 16, false); +const Motive Motive::Fire("Fire", 32, 32, 4 * 16, 10 * 16, false); +const Motive Motive::Water("Water", 32, 32, 6 * 16, 10 * 16, false); +const Motive* Motive::DefaultImage = &Motive::Kebab; + +std::vector Motive::getAllMotivesAsList() { + std::vector motives; + motives.push_back(&Kebab); + motives.push_back(&Aztec2); + motives.push_back(&Alban); + motives.push_back(&Bomb); + motives.push_back(&Plant); + motives.push_back(&Wasteland); + motives.push_back(&Pool); + motives.push_back(&Courbet); + motives.push_back(&Sea); + motives.push_back(&Sunset); + motives.push_back(&Creebet); + motives.push_back(&Wanderer); + motives.push_back(&Graham); + motives.push_back(&Match); + motives.push_back(&Bust); + motives.push_back(&Stage); + motives.push_back(&Void); + motives.push_back(&SkullAndRoses); + motives.push_back(&Fighters); + motives.push_back(&Pointer); + motives.push_back(&Pigscene); + motives.push_back(&BurningSkull); + motives.push_back(&Skeleton); + motives.push_back(&DonkeyKong); + + motives.push_back(&Earth); + motives.push_back(&Wind); + motives.push_back(&Fire); + motives.push_back(&Water); + + return motives; +} + +const Motive* Motive::getMotiveByName( const std::string& name ) { + std::vector allMovies = getAllMotivesAsList(); + for(std::vector::iterator i = allMovies.begin(); i != allMovies.end(); ++i) { + if((*i)->name == name) + return *i; + } + return DefaultImage; +} + +Motive::Motive( std::string name, int w, int h, int uo, int vo, bool isPublic /*= true*/ ) +: name(name), + w(w), + h(h), + uo(uo), + vo(vo), + isPublic(isPublic) +{} diff --git a/src/world/entity/Motive.h b/src/world/entity/Motive.hpp similarity index 100% rename from src/world/entity/Motive.h rename to src/world/entity/Motive.hpp diff --git a/src/world/entity/Painting.cpp b/src/world/entity/Painting.cpp index fec9676..46b1639 100755 --- a/src/world/entity/Painting.cpp +++ b/src/world/entity/Painting.cpp @@ -1,77 +1,77 @@ -#include "Painting.h" -#include "../level/Level.h" -#include "../item/Item.h" -Painting::Painting( Level* level ) : super(level) { - entityRendererId = ER_PAINTING_RENDERER; -} - -Painting::Painting( Level* level, int xTile, int yTile, int zTile, int dir ) -: super(level, xTile, yTile, zTile, dir) { - setRandomMotive(dir); - - entityRendererId = ER_PAINTING_RENDERER; -} - -Painting::Painting( Level* level, int x, int y, int z, int dir, const std::string& motiveName ) - : super(level, x, y, z, dir) { - motive = Motive::getMotiveByName(motiveName); - setDir(dir); - entityRendererId = ER_PAINTING_RENDERER; -} - -void Painting::addAdditonalSaveData( CompoundTag* tag ) { - if(motive != NULL) { - tag->putString("Motive", motive->name); - } - super::addAdditonalSaveData(tag); -} - -void Painting::readAdditionalSaveData( CompoundTag* tag ) { - std::string motiveName = tag->getString("Motive"); - motive = Motive::getMotiveByName(motiveName); - super::readAdditionalSaveData(tag); -} - -int Painting::getWidth() { - return motive->w; -} - -int Painting::getHeight() { - return motive->h; -} - -void Painting::dropItem() { - if(level->getLevelData()->getGameType() != GameType::Creative) - spawnAtLocation(Item::painting->id, 1); -} - -int Painting::getEntityTypeId() const { - return EntityTypes::IdPainting; -} - -void Painting::setRandomMotive( int dir ) { - std::vector allMotives = Motive::getAllMotivesAsList(); - std::vector survivableMotives; - for(std::vector::iterator i = allMotives.begin(); i != allMotives.end(); ++i) { - if (!(*i)->isPublic) - continue; - - motive = *i; - setDir(dir); - if(survives()) { - survivableMotives.push_back(*i); - } - } - if(!survivableMotives.empty()) { - this->motive = survivableMotives[sharedRandom.nextInt(survivableMotives.size())]; - setDir(dir); - } - else { - this->motive = Motive::DefaultImage; - setDir(dir); - } -} - -bool Painting::isPickable() { - return true; -} +#include "Painting.hpp" +#include "world/level/Level.hpp" +#include "world/item/Item.hpp" +Painting::Painting( Level* level ) : super(level) { + entityRendererId = ER_PAINTING_RENDERER; +} + +Painting::Painting( Level* level, int xTile, int yTile, int zTile, int dir ) +: super(level, xTile, yTile, zTile, dir) { + setRandomMotive(dir); + + entityRendererId = ER_PAINTING_RENDERER; +} + +Painting::Painting( Level* level, int x, int y, int z, int dir, const std::string& motiveName ) + : super(level, x, y, z, dir) { + motive = Motive::getMotiveByName(motiveName); + setDir(dir); + entityRendererId = ER_PAINTING_RENDERER; +} + +void Painting::addAdditonalSaveData( CompoundTag* tag ) { + if(motive != NULL) { + tag->putString("Motive", motive->name); + } + super::addAdditonalSaveData(tag); +} + +void Painting::readAdditionalSaveData( CompoundTag* tag ) { + std::string motiveName = tag->getString("Motive"); + motive = Motive::getMotiveByName(motiveName); + super::readAdditionalSaveData(tag); +} + +int Painting::getWidth() { + return motive->w; +} + +int Painting::getHeight() { + return motive->h; +} + +void Painting::dropItem() { + if(level->getLevelData()->getGameType() != GameType::Creative) + spawnAtLocation(Item::painting->id, 1); +} + +int Painting::getEntityTypeId() const { + return EntityTypes::IdPainting; +} + +void Painting::setRandomMotive( int dir ) { + std::vector allMotives = Motive::getAllMotivesAsList(); + std::vector survivableMotives; + for(std::vector::iterator i = allMotives.begin(); i != allMotives.end(); ++i) { + if (!(*i)->isPublic) + continue; + + motive = *i; + setDir(dir); + if(survives()) { + survivableMotives.push_back(*i); + } + } + if(!survivableMotives.empty()) { + this->motive = survivableMotives[sharedRandom.nextInt(survivableMotives.size())]; + setDir(dir); + } + else { + this->motive = Motive::DefaultImage; + setDir(dir); + } +} + +bool Painting::isPickable() { + return true; +} diff --git a/src/world/entity/Painting.h b/src/world/entity/Painting.hpp similarity index 91% rename from src/world/entity/Painting.h rename to src/world/entity/Painting.hpp index d093e3e..ff91eba 100755 --- a/src/world/entity/Painting.h +++ b/src/world/entity/Painting.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Motive.h" -#include "HangingEntity.h" +#include "Motive.hpp" +#include "HangingEntity.hpp" class Painting : public HangingEntity { typedef HangingEntity super; public: diff --git a/src/world/entity/PathfinderMob.cpp b/src/world/entity/PathfinderMob.cpp index 7ab4068..f50e920 100755 --- a/src/world/entity/PathfinderMob.cpp +++ b/src/world/entity/PathfinderMob.cpp @@ -1,248 +1,248 @@ -#include "PathfinderMob.h" -#include "../level/Level.h" -#include "../phys/Vec3.h" -#include "../../util/Mth.h" -#include "../../util/PerfTimer.h" -#include "../../SharedConstants.h" - -#include "ai/Sensing.h" - - -PathfinderMob::PathfinderMob( Level* level ) -: super(level), - //navigation(this, level, 16), - attackTargetId(0), - holdGround(false), - fleeTime(0)//, - //pathfinderMask(0) -{ - sensing = new Sensing(this); - navigation = new PathNavigation(this, level, 16); -} - -PathfinderMob::~PathfinderMob() { - delete navigation; - delete sensing; -} - -bool PathfinderMob::canSpawn() -{ - return super::canSpawn() && getWalkTargetValue(Mth::floor(x), Mth::floor(bb.y0), Mth::floor(z)) >= 0; -} - -bool PathfinderMob::isPathFinding() -{ - return !path.isEmpty(); -} - -void PathfinderMob::setPath( Path& path ) -{ - this->path = path; -} - -Entity* PathfinderMob::getAttackTarget() -{ - if (attackTargetId == 0) return NULL; - return level->getEntity(attackTargetId); -} - -void PathfinderMob::setAttackTarget( Entity* attacker ) -{ - attackTargetId = attacker? attacker->entityId : 0; -} - -bool PathfinderMob::shouldHoldGround() -{ - return false; -} - -void PathfinderMob::updateAi() -{ - TIMER_PUSH("ai"); - - if (fleeTime > 0) fleeTime--; - holdGround = shouldHoldGround(); - float maxDist = 16; - - Entity* attackTarget = NULL; - if (attackTargetId == 0) { - attackTarget = findAttackTarget(); - if (attackTarget != NULL) { - level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0); - attackTargetId = attackTarget->entityId; - //LOGI("path.empty: %d\n", path.isEmpty()); - } - } else { - attackTarget = level->getEntity(attackTargetId); - if (!attackTarget || !attackTarget->isAlive()) { - attackTargetId = 0; - attackTarget = NULL; - } else { - attackTargetId = attackTarget->entityId; - float d = attackTarget->distanceTo(this); - if (canSee(attackTarget)) { - checkHurtTarget(attackTarget, d); - } else { - checkCantSeeTarget(attackTarget, d); - } - } - } - TIMER_POP(); - - /* - * if (holdGround) { xxa = 0; yya = 0; jumping = false; return; } - */ - - bool doStroll = false; - if (!holdGround && (attackTarget != NULL && (path.isEmpty() || random.nextInt(20) == 0))) { - level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0); - } else if (!holdGround) { - if (path.isEmpty() && (random.nextInt(180) == 0)) { - doStroll = true; - } else { - if (random.nextInt(120) == 0) doStroll = true; - else if (fleeTime > 0 && (fleeTime&7) == 1) doStroll = true; - } - } - if (doStroll) { - if (noActionTime < SharedConstants::TicksPerSecond * 5) { - findRandomStrollLocation(); - } - } - - int yFloor = Mth::floor(bb.y0 + .5f); - - bool inWater = isInWater(); - bool inLava = isInLava(); - xRot = 0; - if (path.isEmpty() || random.nextInt(100) == 0) { - //super::serverAiStep(); - super::updateAi(); - return; - } - - TIMER_PUSH("followpath"); - Vec3 target = path.currentPos(this); - float r = bbWidth * 2; - bool looping = true; - while (looping && target.distanceToSqr(x, target.y, z) < r * r) { - path.next(); - if (path.isDone()) { - looping = false; - path.destroy(); - } else target = path.currentPos(this); - } - - jumping = false; - if (looping) { - float xd = target.x - x; - float zd = target.z - z; - float yd = target.y - yFloor; - // float yRotOld = yRot; - float yRotD = (float) (Mth::atan2(zd, xd) * 180 / Mth::PI) - 90; - float rotDiff = yRotD - yRot; - yya = runSpeed; - while (rotDiff < -180) - rotDiff += 360; - while (rotDiff >= 180) - rotDiff -= 360; - if (rotDiff > MAX_TURN) { - rotDiff = MAX_TURN; - // yya *= 0.2; - } - if (rotDiff < -MAX_TURN) { - rotDiff = -MAX_TURN; - // yya *= 0.2; - } - yRot += rotDiff; - - if (holdGround) { - if (attackTarget != NULL) { - float xd2 = attackTarget->x - x; - float zd2 = attackTarget->z - z; - - float oldyRot = yRot; - yRot = (float) (Mth::atan2(zd2, xd2) * 180 / Mth::PI) - 90; - - rotDiff = ((oldyRot - yRot) + 90) * Mth::PI / 180; - xxa = -Mth::sin(rotDiff) * yya * 1.0f; - yya = Mth::cos(rotDiff) * yya * 1.0f; - } - } - if (yd > 0) { - jumping = true; - } - } - - if (attackTarget != NULL) { - lookAt(attackTarget, 30, 30); - } - - if (this->horizontalCollision && !isPathFinding()) jumping = true; - if (random.nextFloat() < 0.8f && (inWater || inLava)) jumping = true; - - TIMER_POP(); -} - -void PathfinderMob::findRandomStrollLocation() -{ - TIMER_PUSH("stroll"); - bool hasBest = false; - int xBest = -1; - int yBest = -1; - int zBest = -1; - float best = -99999; - for (int i = 0; i < 10; i++) { - int xt = Mth::floor(x + random.nextInt(13) - 6); - int yt = Mth::floor(y + random.nextInt(7) - 3); - int zt = Mth::floor(z + random.nextInt(13) - 6); - float value = getWalkTargetValue(xt, yt, zt); - if (value > best) { - best = value; - xBest = xt; - yBest = yt; - zBest = zt; - hasBest = true; - } - - } - if (hasBest) { - //LOGI("Finding a new strolling location! %d, %d, %d (%d, %d, %d) for %p\n", xBest, yBest, zBest, (int)x, (int)y, (int)z, this); - level->findPath(&path, this, xBest, yBest, zBest, 10, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0); - } - TIMER_POP(); -} - -void PathfinderMob::checkHurtTarget( Entity* target, float d ) -{ -} - -void PathfinderMob::checkCantSeeTarget( Entity* target, float d ) -{ - if (d > 32) - attackTargetId = 0; -} - -float PathfinderMob::getWalkTargetValue( int x, int y, int z ) -{ - return 0; -} - -Entity* PathfinderMob::findAttackTarget() -{ - return NULL; -} - -float PathfinderMob::getWalkingSpeedModifier() { - float speed = super::getWalkingSpeedModifier(); - if (fleeTime > 0) speed *= 2; - return speed; -} - -int PathfinderMob::getNoActionTime() { - return noActionTime; -} - -PathNavigation* PathfinderMob::getNavigation() { - return navigation; -} +#include "PathfinderMob.hpp" +#include "world/level/Level.hpp" +#include "world/phys/Vec3.hpp" +#include "util/Mth.hpp" +#include "util/PerfTimer.hpp" +#include "SharedConstants.hpp" + +#include "ai/Sensing.hpp" + + +PathfinderMob::PathfinderMob( Level* level ) +: super(level), + //navigation(this, level, 16), + attackTargetId(0), + holdGround(false), + fleeTime(0)//, + //pathfinderMask(0) +{ + sensing = new Sensing(this); + navigation = new PathNavigation(this, level, 16); +} + +PathfinderMob::~PathfinderMob() { + delete navigation; + delete sensing; +} + +bool PathfinderMob::canSpawn() +{ + return super::canSpawn() && getWalkTargetValue(Mth::floor(x), Mth::floor(bb.y0), Mth::floor(z)) >= 0; +} + +bool PathfinderMob::isPathFinding() +{ + return !path.isEmpty(); +} + +void PathfinderMob::setPath( Path& path ) +{ + this->path = path; +} + +Entity* PathfinderMob::getAttackTarget() +{ + if (attackTargetId == 0) return NULL; + return level->getEntity(attackTargetId); +} + +void PathfinderMob::setAttackTarget( Entity* attacker ) +{ + attackTargetId = attacker? attacker->entityId : 0; +} + +bool PathfinderMob::shouldHoldGround() +{ + return false; +} + +void PathfinderMob::updateAi() +{ + TIMER_PUSH("ai"); + + if (fleeTime > 0) fleeTime--; + holdGround = shouldHoldGround(); + float maxDist = 16; + + Entity* attackTarget = NULL; + if (attackTargetId == 0) { + attackTarget = findAttackTarget(); + if (attackTarget != NULL) { + level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0); + attackTargetId = attackTarget->entityId; + //LOGI("path.empty: %d\n", path.isEmpty()); + } + } else { + attackTarget = level->getEntity(attackTargetId); + if (!attackTarget || !attackTarget->isAlive()) { + attackTargetId = 0; + attackTarget = NULL; + } else { + attackTargetId = attackTarget->entityId; + float d = attackTarget->distanceTo(this); + if (canSee(attackTarget)) { + checkHurtTarget(attackTarget, d); + } else { + checkCantSeeTarget(attackTarget, d); + } + } + } + TIMER_POP(); + + /* + * if (holdGround) { xxa = 0; yya = 0; jumping = false; return; } + */ + + bool doStroll = false; + if (!holdGround && (attackTarget != NULL && (path.isEmpty() || random.nextInt(20) == 0))) { + level->findPath(&path, this, attackTarget, maxDist, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0); + } else if (!holdGround) { + if (path.isEmpty() && (random.nextInt(180) == 0)) { + doStroll = true; + } else { + if (random.nextInt(120) == 0) doStroll = true; + else if (fleeTime > 0 && (fleeTime&7) == 1) doStroll = true; + } + } + if (doStroll) { + if (noActionTime < SharedConstants::TicksPerSecond * 5) { + findRandomStrollLocation(); + } + } + + int yFloor = Mth::floor(bb.y0 + .5f); + + bool inWater = isInWater(); + bool inLava = isInLava(); + xRot = 0; + if (path.isEmpty() || random.nextInt(100) == 0) { + //super::serverAiStep(); + super::updateAi(); + return; + } + + TIMER_PUSH("followpath"); + Vec3 target = path.currentPos(this); + float r = bbWidth * 2; + bool looping = true; + while (looping && target.distanceToSqr(x, target.y, z) < r * r) { + path.next(); + if (path.isDone()) { + looping = false; + path.destroy(); + } else target = path.currentPos(this); + } + + jumping = false; + if (looping) { + float xd = target.x - x; + float zd = target.z - z; + float yd = target.y - yFloor; + // float yRotOld = yRot; + float yRotD = (float) (Mth::atan2(zd, xd) * 180 / Mth::PI) - 90; + float rotDiff = yRotD - yRot; + yya = runSpeed; + while (rotDiff < -180) + rotDiff += 360; + while (rotDiff >= 180) + rotDiff -= 360; + if (rotDiff > MAX_TURN) { + rotDiff = MAX_TURN; + // yya *= 0.2; + } + if (rotDiff < -MAX_TURN) { + rotDiff = -MAX_TURN; + // yya *= 0.2; + } + yRot += rotDiff; + + if (holdGround) { + if (attackTarget != NULL) { + float xd2 = attackTarget->x - x; + float zd2 = attackTarget->z - z; + + float oldyRot = yRot; + yRot = (float) (Mth::atan2(zd2, xd2) * 180 / Mth::PI) - 90; + + rotDiff = ((oldyRot - yRot) + 90) * Mth::PI / 180; + xxa = -Mth::sin(rotDiff) * yya * 1.0f; + yya = Mth::cos(rotDiff) * yya * 1.0f; + } + } + if (yd > 0) { + jumping = true; + } + } + + if (attackTarget != NULL) { + lookAt(attackTarget, 30, 30); + } + + if (this->horizontalCollision && !isPathFinding()) jumping = true; + if (random.nextFloat() < 0.8f && (inWater || inLava)) jumping = true; + + TIMER_POP(); +} + +void PathfinderMob::findRandomStrollLocation() +{ + TIMER_PUSH("stroll"); + bool hasBest = false; + int xBest = -1; + int yBest = -1; + int zBest = -1; + float best = -99999; + for (int i = 0; i < 10; i++) { + int xt = Mth::floor(x + random.nextInt(13) - 6); + int yt = Mth::floor(y + random.nextInt(7) - 3); + int zt = Mth::floor(z + random.nextInt(13) - 6); + float value = getWalkTargetValue(xt, yt, zt); + if (value > best) { + best = value; + xBest = xt; + yBest = yt; + zBest = zt; + hasBest = true; + } + + } + if (hasBest) { + //LOGI("Finding a new strolling location! %d, %d, %d (%d, %d, %d) for %p\n", xBest, yBest, zBest, (int)x, (int)y, (int)z, this); + level->findPath(&path, this, xBest, yBest, zBest, 10, false, false);//(pathfinderMask&CAN_OPEN_DOORS) != 0, (pathfinderMask&AVOID_WATER) != 0); + } + TIMER_POP(); +} + +void PathfinderMob::checkHurtTarget( Entity* target, float d ) +{ +} + +void PathfinderMob::checkCantSeeTarget( Entity* target, float d ) +{ + if (d > 32) + attackTargetId = 0; +} + +float PathfinderMob::getWalkTargetValue( int x, int y, int z ) +{ + return 0; +} + +Entity* PathfinderMob::findAttackTarget() +{ + return NULL; +} + +float PathfinderMob::getWalkingSpeedModifier() { + float speed = super::getWalkingSpeedModifier(); + if (fleeTime > 0) speed *= 2; + return speed; +} + +int PathfinderMob::getNoActionTime() { + return noActionTime; +} + +PathNavigation* PathfinderMob::getNavigation() { + return navigation; +} diff --git a/src/world/entity/PathfinderMob.h b/src/world/entity/PathfinderMob.hpp similarity index 92% rename from src/world/entity/PathfinderMob.h rename to src/world/entity/PathfinderMob.hpp index d0c5283..877a793 100755 --- a/src/world/entity/PathfinderMob.h +++ b/src/world/entity/PathfinderMob.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.entity; -#include "Mob.h" -#include "ai/PathNavigation.h" -#include "../level/pathfinder/Path.h" +#include "Mob.hpp" +#include "ai/PathNavigation.hpp" +#include "world/level/pathfinder/Path.hpp" class Level; class Sensing; diff --git a/src/world/entity/SharedFlags.h b/src/world/entity/SharedFlags.hpp similarity index 100% rename from src/world/entity/SharedFlags.h rename to src/world/entity/SharedFlags.hpp diff --git a/src/world/entity/SynchedEntityData.cpp b/src/world/entity/SynchedEntityData.cpp index 9369a54..600f0ac 100755 --- a/src/world/entity/SynchedEntityData.cpp +++ b/src/world/entity/SynchedEntityData.cpp @@ -1,250 +1,250 @@ -#include "SynchedEntityData.h" - - -SynchedEntityData::SynchedEntityData() -: _isDirty(false) -{ - -} - -SynchedEntityData::~SynchedEntityData() -{ - for (Map::iterator it = itemsById.begin(); it != itemsById.end(); ++it) { - delete (it->second); - } -} - -void SynchedEntityData::pack( DataList* items, IDataOutput* output ) -{ - if (items != NULL) { - for (DataList::iterator it = items->begin(); it != items->end(); ++it) - writeDataItem(output, *it); - } - // add an eof - output->writeByte(EOF_MARKER); -} - -SynchedEntityData::DataList SynchedEntityData::packDirty() -{ - DataList result; - if (_isDirty) { - for (Map::iterator it = itemsById.begin(); it != itemsById.end(); ++it) { - DataItem* dataItem = it->second; - if (dataItem->isDirty()) { - dataItem->setDirty(false); - result.push_back(dataItem); - } - } - } - _isDirty = false; - - return result; -} - -void SynchedEntityData::packAll( IDataOutput* output ) const -{ - for (Map::const_iterator cit = itemsById.begin(); cit != itemsById.end(); ++cit) - SynchedEntityData::writeDataItem(output, cit->second); - - // add an eof - output->writeByte(EOF_MARKER); -} - -SynchedEntityData::DataList SynchedEntityData::unpack( IDataInput* input ) -{ - DataList result; - - int currentHeader = input->readByte(); - - while (currentHeader != EOF_MARKER) { - // split type and id - int itemType = (currentHeader & TYPE_MASK) >> TYPE_SHIFT; - int itemId = (currentHeader & MAX_ID_VALUE); - - //LOGI("unpacking: %d, %d\n", itemId, itemType); - - DataItem* item = NULL; - switch (itemType) { - case TYPE_BYTE: - item = new DataItem2(itemType, itemId, input->readByte()); - break; - case TYPE_SHORT: - item = new DataItem2(itemType, itemId, input->readShort()); - break; - case TYPE_INT: - item = new DataItem2(itemType, itemId, input->readInt()); - break; - case TYPE_FLOAT: - item = new DataItem2(itemType, itemId, input->readFloat()); - break; - case TYPE_STRING: - item = new DataItem2(itemType, itemId, input->readString()); - break; - case TYPE_ITEMINSTANCE: { - int id = input->readShort(); - int count = input->readByte(); - int auxValue = input->readShort(); - item = new DataItem2(itemType, itemId, ItemInstance(id, count, auxValue)); - } - break; - case TYPE_POS: { - int x = input->readInt(); - int y = input->readInt(); - int z = input->readInt(); - item = new DataItem2(itemType, itemId, Pos(x, y, z)); - } - break; - } - result.push_back(item); - - currentHeader = input->readByte(); - } - - return result; -} - -void SynchedEntityData::assignValues( DataList* items ) -{ - for (DataList::const_iterator it = items->begin(); it != items->end(); ++it) { - - //for (DataItem item : items) { - DataItem* item = *it; - Map::iterator jt = itemsById.find(item->getId()); - //DataItem dataItem = itemsById.get(item.getId()); - if (jt != itemsById.end()) { - switch (item->getType()) { - case TYPE_BYTE : set(jt->second, ((DataItem2*)item)->data); break; - case TYPE_SHORT: set(jt->second, ((DataItem2*)item)->data); break; - case TYPE_INT : set(jt->second, ((DataItem2*)item)->data); break; - case TYPE_FLOAT: set(jt->second, ((DataItem2*)item)->data); break; - case TYPE_STRING:set(jt->second, ((DataItem2*)item)->data); break; - case TYPE_ITEMINSTANCE: set(jt->second, ((DataItem2*)item)->data); break; - case TYPE_POS: set(jt->second, ((DataItem2*)item)->data); break; - default: - LOGE("Incorrect type id: %d\n", item->getType()); - break; - } - //dataItem->setValue(item->getValue()); - } - } -} - -void SynchedEntityData::writeDataItem( IDataOutput* output, const DataItem* dataItem ) -{ - //LOGI("write: %d, %d\n", dataItem->getId(), dataItem->getType()); - - // pack type and id - //LOGI("dataItem: %d\n", dataItem); - int header = ((dataItem->getType() << TYPE_SHIFT) | (dataItem->getId() & MAX_ID_VALUE)) & 0xff; - output->writeByte(header); - - // write value - switch (dataItem->getType()) { - case TYPE_BYTE: - output->writeByte(((DataItem2*)dataItem)->data); - break; - case TYPE_SHORT: - output->writeShort(((DataItem2*)dataItem)->data); - break; - case TYPE_INT: - output->writeInt(((DataItem2*)dataItem)->data); - break; - case TYPE_FLOAT: - output->writeFloat(((DataItem2*)dataItem)->data); - break; - case TYPE_STRING: - output->writeString(((DataItem2*)dataItem)->data); - break; - case TYPE_ITEMINSTANCE: { - const ItemInstance& instance = ((DataItem2*)dataItem)->data; - output->writeShort(instance.getItem()->id); - output->writeByte(instance.count); - output->writeShort(instance.getAuxValue()); - } - break; - case TYPE_POS: { - const Pos& instance = ((DataItem2*)dataItem)->data; - output->writeInt(instance.x); - output->writeInt(instance.y); - output->writeInt(instance.z); - } - break; - } -} - -SynchedEntityData::TypeChar SynchedEntityData::getByte( int id ) const -{ - Map::const_iterator it = itemsById.find(id); - if (it != itemsById.end()) { - if (it->second->getType() == TYPE_BYTE) { - return ((DataItem2*)it->second)->data; - } - } - return 0; -} - -SynchedEntityData::TypeShort SynchedEntityData::getShort( int id ) const -{ - Map::const_iterator it = itemsById.find(id); - if (it != itemsById.end()) { - if (it->second->getType() == TYPE_SHORT) { - return ((DataItem2*)it->second)->data; - } - } - return 0; -} - -SynchedEntityData::TypeInt SynchedEntityData::getInt( int id ) const -{ - Map::const_iterator it = itemsById.find(id); - if (it != itemsById.end()) { - if (it->second->getType() == TYPE_INT) { - return ((DataItem2*)it->second)->data; - } - } - return 0; -} - -SynchedEntityData::TypeFloat SynchedEntityData::getFloat( int id ) const -{ - Map::const_iterator it = itemsById.find(id); - if (it != itemsById.end()) { - if (it->second->getType() == TYPE_FLOAT) { - return ((DataItem2*)it->second)->data; - } - } - return 0; -} - -std::string SynchedEntityData::getString( int id ) const -{ - Map::const_iterator it = itemsById.find(id); - if (it != itemsById.end()) { - if (it->second->getType() == TYPE_STRING) { - return ((DataItem2*)it->second)->data; - } - } - return ""; -} - -ItemInstance SynchedEntityData::getItemInstance( int id ) -{ - Map::const_iterator it = itemsById.find(id); - if (it != itemsById.end()) { - if (it->second->getType() == TYPE_ITEMINSTANCE) { - return ((DataItem2*)it->second)->data; - } - } - return ItemInstance(); -} - -Pos SynchedEntityData::getPos( int id ) const -{ - Map::const_iterator it = itemsById.find(id); - if (it != itemsById.end()) { - if (it->second->getType() == TYPE_POS) { - return ((DataItem2*)it->second)->data; - } - } - return Pos(); -} +#include "SynchedEntityData.hpp" + + +SynchedEntityData::SynchedEntityData() +: _isDirty(false) +{ + +} + +SynchedEntityData::~SynchedEntityData() +{ + for (Map::iterator it = itemsById.begin(); it != itemsById.end(); ++it) { + delete (it->second); + } +} + +void SynchedEntityData::pack( DataList* items, IDataOutput* output ) +{ + if (items != NULL) { + for (DataList::iterator it = items->begin(); it != items->end(); ++it) + writeDataItem(output, *it); + } + // add an eof + output->writeByte(EOF_MARKER); +} + +SynchedEntityData::DataList SynchedEntityData::packDirty() +{ + DataList result; + if (_isDirty) { + for (Map::iterator it = itemsById.begin(); it != itemsById.end(); ++it) { + DataItem* dataItem = it->second; + if (dataItem->isDirty()) { + dataItem->setDirty(false); + result.push_back(dataItem); + } + } + } + _isDirty = false; + + return result; +} + +void SynchedEntityData::packAll( IDataOutput* output ) const +{ + for (Map::const_iterator cit = itemsById.begin(); cit != itemsById.end(); ++cit) + SynchedEntityData::writeDataItem(output, cit->second); + + // add an eof + output->writeByte(EOF_MARKER); +} + +SynchedEntityData::DataList SynchedEntityData::unpack( IDataInput* input ) +{ + DataList result; + + int currentHeader = input->readByte(); + + while (currentHeader != EOF_MARKER) { + // split type and id + int itemType = (currentHeader & TYPE_MASK) >> TYPE_SHIFT; + int itemId = (currentHeader & MAX_ID_VALUE); + + //LOGI("unpacking: %d, %d\n", itemId, itemType); + + DataItem* item = NULL; + switch (itemType) { + case TYPE_BYTE: + item = new DataItem2(itemType, itemId, input->readByte()); + break; + case TYPE_SHORT: + item = new DataItem2(itemType, itemId, input->readShort()); + break; + case TYPE_INT: + item = new DataItem2(itemType, itemId, input->readInt()); + break; + case TYPE_FLOAT: + item = new DataItem2(itemType, itemId, input->readFloat()); + break; + case TYPE_STRING: + item = new DataItem2(itemType, itemId, input->readString()); + break; + case TYPE_ITEMINSTANCE: { + int id = input->readShort(); + int count = input->readByte(); + int auxValue = input->readShort(); + item = new DataItem2(itemType, itemId, ItemInstance(id, count, auxValue)); + } + break; + case TYPE_POS: { + int x = input->readInt(); + int y = input->readInt(); + int z = input->readInt(); + item = new DataItem2(itemType, itemId, Pos(x, y, z)); + } + break; + } + result.push_back(item); + + currentHeader = input->readByte(); + } + + return result; +} + +void SynchedEntityData::assignValues( DataList* items ) +{ + for (DataList::const_iterator it = items->begin(); it != items->end(); ++it) { + + //for (DataItem item : items) { + DataItem* item = *it; + Map::iterator jt = itemsById.find(item->getId()); + //DataItem dataItem = itemsById.get(item.getId()); + if (jt != itemsById.end()) { + switch (item->getType()) { + case TYPE_BYTE : set(jt->second, ((DataItem2*)item)->data); break; + case TYPE_SHORT: set(jt->second, ((DataItem2*)item)->data); break; + case TYPE_INT : set(jt->second, ((DataItem2*)item)->data); break; + case TYPE_FLOAT: set(jt->second, ((DataItem2*)item)->data); break; + case TYPE_STRING:set(jt->second, ((DataItem2*)item)->data); break; + case TYPE_ITEMINSTANCE: set(jt->second, ((DataItem2*)item)->data); break; + case TYPE_POS: set(jt->second, ((DataItem2*)item)->data); break; + default: + LOGE("Incorrect type id: %d\n", item->getType()); + break; + } + //dataItem->setValue(item->getValue()); + } + } +} + +void SynchedEntityData::writeDataItem( IDataOutput* output, const DataItem* dataItem ) +{ + //LOGI("write: %d, %d\n", dataItem->getId(), dataItem->getType()); + + // pack type and id + //LOGI("dataItem: %d\n", dataItem); + int header = ((dataItem->getType() << TYPE_SHIFT) | (dataItem->getId() & MAX_ID_VALUE)) & 0xff; + output->writeByte(header); + + // write value + switch (dataItem->getType()) { + case TYPE_BYTE: + output->writeByte(((DataItem2*)dataItem)->data); + break; + case TYPE_SHORT: + output->writeShort(((DataItem2*)dataItem)->data); + break; + case TYPE_INT: + output->writeInt(((DataItem2*)dataItem)->data); + break; + case TYPE_FLOAT: + output->writeFloat(((DataItem2*)dataItem)->data); + break; + case TYPE_STRING: + output->writeString(((DataItem2*)dataItem)->data); + break; + case TYPE_ITEMINSTANCE: { + const ItemInstance& instance = ((DataItem2*)dataItem)->data; + output->writeShort(instance.getItem()->id); + output->writeByte(instance.count); + output->writeShort(instance.getAuxValue()); + } + break; + case TYPE_POS: { + const Pos& instance = ((DataItem2*)dataItem)->data; + output->writeInt(instance.x); + output->writeInt(instance.y); + output->writeInt(instance.z); + } + break; + } +} + +SynchedEntityData::TypeChar SynchedEntityData::getByte( int id ) const +{ + Map::const_iterator it = itemsById.find(id); + if (it != itemsById.end()) { + if (it->second->getType() == TYPE_BYTE) { + return ((DataItem2*)it->second)->data; + } + } + return 0; +} + +SynchedEntityData::TypeShort SynchedEntityData::getShort( int id ) const +{ + Map::const_iterator it = itemsById.find(id); + if (it != itemsById.end()) { + if (it->second->getType() == TYPE_SHORT) { + return ((DataItem2*)it->second)->data; + } + } + return 0; +} + +SynchedEntityData::TypeInt SynchedEntityData::getInt( int id ) const +{ + Map::const_iterator it = itemsById.find(id); + if (it != itemsById.end()) { + if (it->second->getType() == TYPE_INT) { + return ((DataItem2*)it->second)->data; + } + } + return 0; +} + +SynchedEntityData::TypeFloat SynchedEntityData::getFloat( int id ) const +{ + Map::const_iterator it = itemsById.find(id); + if (it != itemsById.end()) { + if (it->second->getType() == TYPE_FLOAT) { + return ((DataItem2*)it->second)->data; + } + } + return 0; +} + +std::string SynchedEntityData::getString( int id ) const +{ + Map::const_iterator it = itemsById.find(id); + if (it != itemsById.end()) { + if (it->second->getType() == TYPE_STRING) { + return ((DataItem2*)it->second)->data; + } + } + return ""; +} + +ItemInstance SynchedEntityData::getItemInstance( int id ) +{ + Map::const_iterator it = itemsById.find(id); + if (it != itemsById.end()) { + if (it->second->getType() == TYPE_ITEMINSTANCE) { + return ((DataItem2*)it->second)->data; + } + } + return ItemInstance(); +} + +Pos SynchedEntityData::getPos( int id ) const +{ + Map::const_iterator it = itemsById.find(id); + if (it != itemsById.end()) { + if (it->second->getType() == TYPE_POS) { + return ((DataItem2*)it->second)->data; + } + } + return Pos(); +} diff --git a/src/world/entity/SynchedEntityData.h b/src/world/entity/SynchedEntityData.hpp similarity index 97% rename from src/world/entity/SynchedEntityData.h rename to src/world/entity/SynchedEntityData.hpp index 8044280..8ba38aa 100755 --- a/src/world/entity/SynchedEntityData.h +++ b/src/world/entity/SynchedEntityData.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.entity; -#include "../Pos.h" -#include "../../network/Packet.h" -#include "../item/ItemInstance.h" -#include "../item/Item.h" -#include "../../util/DataIO.h" +#include "world/Pos.hpp" +#include "network/Packet.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/item/Item.hpp" +#include "util/DataIO.hpp" class DataItem { public: diff --git a/src/world/entity/ai/PathNavigation.h b/src/world/entity/ai/PathNavigation.hpp similarity index 97% rename from src/world/entity/ai/PathNavigation.h rename to src/world/entity/ai/PathNavigation.hpp index be34fbb..88f82ab 100755 --- a/src/world/entity/ai/PathNavigation.h +++ b/src/world/entity/ai/PathNavigation.hpp @@ -2,16 +2,16 @@ //package net.minecraft.world.entity.ai; -#include "../Mob.h" -#include "../../level/Level.h" -#include "../../level/material/Material.h" -#include "../../level/tile/Tile.h" -#include "../../phys/Vec3.h" +#include "world/entity/Mob.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/phys/Vec3.hpp" #include -#include "../../level/pathfinder/Path.h" -#include "control/MoveControl.h" -#include "../../../util/MemUtils.h" +#include "world/level/pathfinder/Path.hpp" +#include "control/MoveControl.hpp" +#include "util/MemUtils.hpp" class PathNavigation { diff --git a/src/world/entity/ai/Sensing.h b/src/world/entity/ai/Sensing.hpp similarity index 100% rename from src/world/entity/ai/Sensing.h rename to src/world/entity/ai/Sensing.hpp diff --git a/src/world/entity/ai/control/Control.h b/src/world/entity/ai/control/Control.hpp similarity index 100% rename from src/world/entity/ai/control/Control.h rename to src/world/entity/ai/control/Control.hpp diff --git a/src/world/entity/ai/control/JumpControl.h b/src/world/entity/ai/control/JumpControl.hpp similarity index 86% rename from src/world/entity/ai/control/JumpControl.h rename to src/world/entity/ai/control/JumpControl.hpp index a11ba7a..12d2c85 100755 --- a/src/world/entity/ai/control/JumpControl.h +++ b/src/world/entity/ai/control/JumpControl.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.entity.ai.control; -#include "Control.h" -#include "../../Mob.h" +#include "Control.hpp" +#include "world/entity/Mob.hpp" class JumpControl: public Control { diff --git a/src/world/entity/ai/control/MoveControl.cpp b/src/world/entity/ai/control/MoveControl.cpp index 397e042..a3031f7 100755 --- a/src/world/entity/ai/control/MoveControl.cpp +++ b/src/world/entity/ai/control/MoveControl.cpp @@ -1,70 +1,70 @@ -#include "MoveControl.h" -#include "JumpControl.h" - -const float MoveControl::MAX_TURN = 30; - -const float MoveControl::MIN_SPEED = 0.0005f; -const float MoveControl::MIN_SPEED_SQR = MIN_SPEED * MIN_SPEED; - - -MoveControl::MoveControl( Mob* mob ) -: mob(mob), - wantedX(mob->x), - wantedY(mob->y), - wantedZ(mob->z), - _hasWanted(false) -{ -} - -bool MoveControl::hasWanted() { - return _hasWanted; -} - -float MoveControl::getSpeed() { - return speed; -} - -void MoveControl::setWantedPosition( float x, float y, float z, float speed ) { - //LOGI("> %f, %f, %f\n", x, y, z); - wantedX = x; - wantedY = y; - wantedZ = z; - this->speed = speed; - _hasWanted = true; -} - -void MoveControl::tick() { - mob->setYya(0); - if (!_hasWanted) return; - _hasWanted = false; - - int yFloor = Mth::floor(mob->bb.y0 + 0.5f); - - float xd = wantedX - mob->x; - float zd = wantedZ - mob->z; - float yd = wantedY - yFloor; - float dd = xd * xd + yd * yd + zd * zd; - if (dd < MIN_SPEED_SQR) return; - - float yRotD = (float) (std::atan2(zd, xd) * 180 / Mth::PI) - 90; - - mob->yRot = rotlerp(mob->yRot, yRotD, MAX_TURN); - mob->setSpeed(speed); - - if (yd > 0 && xd * xd + zd * zd < 1) mob->getJumpControl()->jump(); -} - -float MoveControl::rotlerp( float a, float b, float max ) { - float diff = b - a; - while (diff < -180) - diff += 360; - while (diff >= 180) - diff -= 360; - if (diff > max) { - diff = max; - } - if (diff < -max) { - diff = -max; - } - return a + diff; -} +#include "MoveControl.hpp" +#include "JumpControl.hpp" + +const float MoveControl::MAX_TURN = 30; + +const float MoveControl::MIN_SPEED = 0.0005f; +const float MoveControl::MIN_SPEED_SQR = MIN_SPEED * MIN_SPEED; + + +MoveControl::MoveControl( Mob* mob ) +: mob(mob), + wantedX(mob->x), + wantedY(mob->y), + wantedZ(mob->z), + _hasWanted(false) +{ +} + +bool MoveControl::hasWanted() { + return _hasWanted; +} + +float MoveControl::getSpeed() { + return speed; +} + +void MoveControl::setWantedPosition( float x, float y, float z, float speed ) { + //LOGI("> %f, %f, %f\n", x, y, z); + wantedX = x; + wantedY = y; + wantedZ = z; + this->speed = speed; + _hasWanted = true; +} + +void MoveControl::tick() { + mob->setYya(0); + if (!_hasWanted) return; + _hasWanted = false; + + int yFloor = Mth::floor(mob->bb.y0 + 0.5f); + + float xd = wantedX - mob->x; + float zd = wantedZ - mob->z; + float yd = wantedY - yFloor; + float dd = xd * xd + yd * yd + zd * zd; + if (dd < MIN_SPEED_SQR) return; + + float yRotD = (float) (std::atan2(zd, xd) * 180 / Mth::PI) - 90; + + mob->yRot = rotlerp(mob->yRot, yRotD, MAX_TURN); + mob->setSpeed(speed); + + if (yd > 0 && xd * xd + zd * zd < 1) mob->getJumpControl()->jump(); +} + +float MoveControl::rotlerp( float a, float b, float max ) { + float diff = b - a; + while (diff < -180) + diff += 360; + while (diff >= 180) + diff -= 360; + if (diff > max) { + diff = max; + } + if (diff < -max) { + diff = -max; + } + return a + diff; +} diff --git a/src/world/entity/ai/control/MoveControl.h b/src/world/entity/ai/control/MoveControl.hpp similarity index 87% rename from src/world/entity/ai/control/MoveControl.h rename to src/world/entity/ai/control/MoveControl.hpp index d719a27..ff54421 100755 --- a/src/world/entity/ai/control/MoveControl.h +++ b/src/world/entity/ai/control/MoveControl.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.entity.ai.control; -#include "Control.h" +#include "Control.hpp" -#include "../../Mob.h" -#include "../../../../util/Mth.h" +#include "world/entity/Mob.hpp" +#include "util/Mth.hpp" class MoveControl: public Control { diff --git a/src/world/entity/ai/goal/BreakDoorGoal.h b/src/world/entity/ai/goal/BreakDoorGoal.hpp similarity index 86% rename from src/world/entity/ai/goal/BreakDoorGoal.h rename to src/world/entity/ai/goal/BreakDoorGoal.hpp index 39d6e65..fa5a4b6 100755 --- a/src/world/entity/ai/goal/BreakDoorGoal.h +++ b/src/world/entity/ai/goal/BreakDoorGoal.hpp @@ -2,13 +2,13 @@ //package net.minecraft.world.entity->ai.goal; -#include "DoorInteractGoal.h" +#include "DoorInteractGoal.hpp" -#include "../../Entity.h" -#include "../../../level/tile/LevelEvent.h" -#include "../../../level/Level.h" -#include "../../../level/tile/DoorTile.h" -#include "../../../../SharedConstants.h" +#include "world/entity/Entity.hpp" +#include "world/level/tile/LevelEvent.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/DoorTile.hpp" +#include "SharedConstants.hpp" class BreakDoorGoal: public DoorInteractGoal { diff --git a/src/world/entity/ai/goal/DoorInteractGoal.h b/src/world/entity/ai/goal/DoorInteractGoal.hpp similarity index 90% rename from src/world/entity/ai/goal/DoorInteractGoal.h rename to src/world/entity/ai/goal/DoorInteractGoal.hpp index 1aa3ac1..91d632a 100755 --- a/src/world/entity/ai/goal/DoorInteractGoal.h +++ b/src/world/entity/ai/goal/DoorInteractGoal.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.entity.ai.goal; -#include "Goal.h" +#include "Goal.hpp" -#include "../PathNavigation.h" -#include "../../monster/Monster.h" -#include "../../../level/pathfinder/Path.h" -#include "../../../level/tile/DoorTile.h" +#include "world/entity/ai/PathNavigation.hpp" +#include "world/entity/monster/Monster.hpp" +#include "world/level/pathfinder/Path.hpp" +#include "world/level/tile/DoorTile.hpp" class DoorInteractGoal: public Goal { diff --git a/src/world/entity/ai/goal/Goal.h b/src/world/entity/ai/goal/Goal.hpp similarity index 100% rename from src/world/entity/ai/goal/Goal.h rename to src/world/entity/ai/goal/Goal.hpp diff --git a/src/world/entity/ai/goal/GoalSelector.h b/src/world/entity/ai/goal/GoalSelector.hpp similarity index 99% rename from src/world/entity/ai/goal/GoalSelector.h rename to src/world/entity/ai/goal/GoalSelector.hpp index 85842b1..b81c778 100755 --- a/src/world/entity/ai/goal/GoalSelector.h +++ b/src/world/entity/ai/goal/GoalSelector.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.ai.goal; -#include "Goal.h" +#include "Goal.hpp" #include diff --git a/src/world/entity/ai/goal/MeleeAttackGoal.h b/src/world/entity/ai/goal/MeleeAttackGoal.hpp similarity index 91% rename from src/world/entity/ai/goal/MeleeAttackGoal.h rename to src/world/entity/ai/goal/MeleeAttackGoal.hpp index 2ded76a..c9b7b40 100755 --- a/src/world/entity/ai/goal/MeleeAttackGoal.h +++ b/src/world/entity/ai/goal/MeleeAttackGoal.hpp @@ -2,13 +2,13 @@ //package net.minecraft.world.entity.ai.goal; -#include "Goal.h" +#include "Goal.hpp" -#include "../control/Control.h" -#include "../../monster/Monster.h" -#include "../../../level/Level.h" -#include "../../../level/pathfinder/Path.h" -#include "../Sensing.h" +#include "world/entity/ai/control/Control.hpp" +#include "world/entity/monster/Monster.hpp" +#include "world/level/Level.hpp" +#include "world/level/pathfinder/Path.hpp" +#include "world/entity/ai/Sensing.hpp" class MeleeAttackGoal: public Goal { diff --git a/src/world/entity/ai/goal/RandomStrollGoal.h b/src/world/entity/ai/goal/RandomStrollGoal.hpp similarity index 78% rename from src/world/entity/ai/goal/RandomStrollGoal.h rename to src/world/entity/ai/goal/RandomStrollGoal.hpp index c0055dd..3ecdb1a 100755 --- a/src/world/entity/ai/goal/RandomStrollGoal.h +++ b/src/world/entity/ai/goal/RandomStrollGoal.hpp @@ -2,14 +2,14 @@ //package net.minecraft.world.entity.ai.goal; -#include "Goal.h" +#include "Goal.hpp" -#include "../../../../SharedConstants.h" -#include "../../PathfinderMob.h" -#include "../control/Control.h" -#include "../util/RandomPos.h" -#include "../../../phys/Vec3.h" -#include "../util/RandomPos.h" +#include "SharedConstants.hpp" +#include "world/entity/PathfinderMob.hpp" +#include "world/entity/ai/control/Control.hpp" +#include "world/entity/ai/util/RandomPos.hpp" +#include "world/phys/Vec3.hpp" +#include "world/entity/ai/util/RandomPos.hpp" class RandomStrollGoal: public Goal { diff --git a/src/world/entity/ai/goal/target/HurtByTargetGoal.h b/src/world/entity/ai/goal/target/HurtByTargetGoal.hpp similarity index 94% rename from src/world/entity/ai/goal/target/HurtByTargetGoal.h rename to src/world/entity/ai/goal/target/HurtByTargetGoal.hpp index d02fefd..bce5796 100755 --- a/src/world/entity/ai/goal/target/HurtByTargetGoal.h +++ b/src/world/entity/ai/goal/target/HurtByTargetGoal.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.entity->ai.goal.target; -#include "TargetGoal.h" -#include "../../../../phys/AABB.h" +#include "TargetGoal.hpp" +#include "world/phys/AABB.hpp" class HurtByTargetGoal: public TargetGoal { diff --git a/src/world/entity/ai/goal/target/NearestAttackableTargetGoal.h b/src/world/entity/ai/goal/target/NearestAttackableTargetGoal.hpp similarity index 94% rename from src/world/entity/ai/goal/target/NearestAttackableTargetGoal.h rename to src/world/entity/ai/goal/target/NearestAttackableTargetGoal.hpp index 51586b6..cafe605 100755 --- a/src/world/entity/ai/goal/target/NearestAttackableTargetGoal.h +++ b/src/world/entity/ai/goal/target/NearestAttackableTargetGoal.hpp @@ -3,8 +3,8 @@ //package net.minecraft.world.entity->ai.goal.target; /* import net.minecraft.world.entity->* */ -#include "TargetGoal.h" -#include "../../../player/Player.h" +#include "TargetGoal.hpp" +#include "world/entity/player/Player.hpp" class NearestAttackableTargetGoal: public TargetGoal diff --git a/src/world/entity/ai/goal/target/TargetGoal.h b/src/world/entity/ai/goal/target/TargetGoal.hpp similarity index 94% rename from src/world/entity/ai/goal/target/TargetGoal.h rename to src/world/entity/ai/goal/target/TargetGoal.hpp index 4acab8a..b5fb1a6 100755 --- a/src/world/entity/ai/goal/target/TargetGoal.h +++ b/src/world/entity/ai/goal/target/TargetGoal.hpp @@ -3,9 +3,9 @@ //package net.minecraft.world.entity->ai.goal.target; /* import net.minecraft.world.entity->* */ -#include "../Goal.h" +#include "world/entity/ai/goal/Goal.hpp" /* import net.minecraft.world.entity->monster.* */ -#include "../../../player/Player.h" +#include "world/entity/player/Player.hpp" class Monster; diff --git a/src/world/entity/ai/util/RandomPos.h b/src/world/entity/ai/util/RandomPos.hpp similarity index 96% rename from src/world/entity/ai/util/RandomPos.h rename to src/world/entity/ai/util/RandomPos.hpp index d424719..09d88bf 100755 --- a/src/world/entity/ai/util/RandomPos.h +++ b/src/world/entity/ai/util/RandomPos.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.entity.ai.util; -#include "../../PathfinderMob.h" -#include "../../../phys/Vec3.h" +#include "world/entity/PathfinderMob.hpp" +#include "world/phys/Vec3.hpp" class RandomPos { diff --git a/src/world/entity/animal/Animal.cpp b/src/world/entity/animal/Animal.cpp index d8583e2..fe19a90 100755 --- a/src/world/entity/animal/Animal.cpp +++ b/src/world/entity/animal/Animal.cpp @@ -1,92 +1,92 @@ -#include "Animal.h" -#include "../../level/Level.h" -#include "../../level/tile/Tile.h" - -#include "../../../nbt/CompoundTag.h" - - -Animal::Animal( Level* level ) -: super(level), - inLove(0) -{ - //entityData.define(DATA_AGE_ID, (SynchedEntityData::TypeInt)0); -} - -bool Animal::hurt( Entity* source, int dmg ) -{ - fleeTime = 3 * SharedConstants::TicksPerSecond; - attackTargetId = 0; - inLove = 0; - return super::hurt(source, dmg); -} - -bool Animal::canSpawn() -{ - int xt = Mth::floor(x); - int yt = Mth::floor(bb.y0); - int zt = Mth::floor(z); - return level->getTile(xt, yt - 1, zt) == ((Tile*)Tile::grass)->id && level->getRawBrightness(xt, yt, zt) > 8 && super::canSpawn(); -} - -int Animal::getAmbientSoundInterval() -{ - return 12 * SharedConstants::TicksPerSecond; -} - -float Animal::getWalkTargetValue( int x, int y, int z ) -{ - if (level->getTile(x, y - 1, z) == ((Tile*)Tile::grass)->id) return 10; - return level->getBrightness(x, y, z) - 0.5f; -} - -Entity* Animal::findAttackTarget() -{ - return NULL; - - //if (fleeTime > 0) - // return NULL; - - //int inLove = -1; - - //float r = 8; - //if (inLove > 0) { - // EntityList others; - // level->getEntitiesOfType(getEntityTypeId(), bb.expand(r, r, r), others); - // for (unsigned int i = 0; i < others.size(); i++) { - // Animal* p = (Animal*) others[i]; - // if (p != this && p->inLove > 0) { - // return p; - // } - // } - //} else { - // /* if (getAge() == 0) { - // List players = level.getEntitiesOfClass(Player.class, bb.expand(r, r, r)); - // for (int i = 0; i < players.size(); i++) { - // Player p = (Player) players.get(i); - // if (p.getSelectedItem() != null && this.isFood(p.getSelectedItem())) { - // return p; - // } - // } - // } else if (getAge() > 0) { - // EntityList others; - // level->getEntitiesOfType(getEntityTypeId(), bb.expand(r, r, r), others); - // for (unsigned int i = 0; i < others.size(); i++) { - // Animal* p = (Animal*) others[i]; - // if (p != this && p->getAge() < 0) { - // return p; - // } - // } - // } - // */ - //} - //return NULL; -} - -bool Animal::removeWhenFarAway() -{ - return false; -} - -int Animal::getCreatureBaseType() const { - return MobTypes::BaseCreature; -} +#include "Animal.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" + +#include "nbt/CompoundTag.hpp" + + +Animal::Animal( Level* level ) +: super(level), + inLove(0) +{ + //entityData.define(DATA_AGE_ID, (SynchedEntityData::TypeInt)0); +} + +bool Animal::hurt( Entity* source, int dmg ) +{ + fleeTime = 3 * SharedConstants::TicksPerSecond; + attackTargetId = 0; + inLove = 0; + return super::hurt(source, dmg); +} + +bool Animal::canSpawn() +{ + int xt = Mth::floor(x); + int yt = Mth::floor(bb.y0); + int zt = Mth::floor(z); + return level->getTile(xt, yt - 1, zt) == ((Tile*)Tile::grass)->id && level->getRawBrightness(xt, yt, zt) > 8 && super::canSpawn(); +} + +int Animal::getAmbientSoundInterval() +{ + return 12 * SharedConstants::TicksPerSecond; +} + +float Animal::getWalkTargetValue( int x, int y, int z ) +{ + if (level->getTile(x, y - 1, z) == ((Tile*)Tile::grass)->id) return 10; + return level->getBrightness(x, y, z) - 0.5f; +} + +Entity* Animal::findAttackTarget() +{ + return NULL; + + //if (fleeTime > 0) + // return NULL; + + //int inLove = -1; + + //float r = 8; + //if (inLove > 0) { + // EntityList others; + // level->getEntitiesOfType(getEntityTypeId(), bb.expand(r, r, r), others); + // for (unsigned int i = 0; i < others.size(); i++) { + // Animal* p = (Animal*) others[i]; + // if (p != this && p->inLove > 0) { + // return p; + // } + // } + //} else { + // /* if (getAge() == 0) { + // List players = level.getEntitiesOfClass(Player.class, bb.expand(r, r, r)); + // for (int i = 0; i < players.size(); i++) { + // Player p = (Player) players.get(i); + // if (p.getSelectedItem() != null && this.isFood(p.getSelectedItem())) { + // return p; + // } + // } + // } else if (getAge() > 0) { + // EntityList others; + // level->getEntitiesOfType(getEntityTypeId(), bb.expand(r, r, r), others); + // for (unsigned int i = 0; i < others.size(); i++) { + // Animal* p = (Animal*) others[i]; + // if (p != this && p->getAge() < 0) { + // return p; + // } + // } + // } + // */ + //} + //return NULL; +} + +bool Animal::removeWhenFarAway() +{ + return false; +} + +int Animal::getCreatureBaseType() const { + return MobTypes::BaseCreature; +} diff --git a/src/world/entity/animal/Animal.h b/src/world/entity/animal/Animal.hpp similarity index 87% rename from src/world/entity/animal/Animal.h rename to src/world/entity/animal/Animal.hpp index e13f819..8b92b56 100755 --- a/src/world/entity/animal/Animal.h +++ b/src/world/entity/animal/Animal.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.entity.animal; -#include "../AgableMob.h" -#include "../Creature.h" +#include "world/entity/AgableMob.hpp" +#include "world/entity/Creature.hpp" class Level; class Entity; diff --git a/src/world/entity/animal/AnimalInclude.h b/src/world/entity/animal/AnimalInclude.h deleted file mode 100755 index 082ecf1..0000000 --- a/src/world/entity/animal/AnimalInclude.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "Animal.h" -#include "Chicken.h" -#include "Cow.h" -#include "Pig.h" -#include "Sheep.h" - diff --git a/src/world/entity/animal/AnimalInclude.hpp b/src/world/entity/animal/AnimalInclude.hpp new file mode 100755 index 0000000..7393748 --- /dev/null +++ b/src/world/entity/animal/AnimalInclude.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "Animal.hpp" +#include "Chicken.hpp" +#include "Cow.hpp" +#include "Pig.hpp" +#include "Sheep.hpp" + diff --git a/src/world/entity/animal/Chicken.cpp b/src/world/entity/animal/Chicken.cpp index df331e3..3b6137b 100755 --- a/src/world/entity/animal/Chicken.cpp +++ b/src/world/entity/animal/Chicken.cpp @@ -1,113 +1,113 @@ -#include "Chicken.h" -#include "../../item/Item.h" -#include "../../level/Level.h" - -Chicken::Chicken( Level* level ) -: super(level), - sheared(false), - flap(0), - oFlap(0), - flapSpeed(0), - oFlapSpeed(0), - flapping(1), - eggTime(0) -{ - entityRendererId = ER_CHICKEN_RENDERER; - - textureName = "mob/chicken.png"; - setSize(0.3f, 0.7f); - eggTime = random.nextInt(SharedConstants::TicksPerSecond * 60 * 5) + SharedConstants::TicksPerSecond * 60 * 5; -} - -int Chicken::getEntityTypeId() const -{ - return MobTypes::Chicken; -} - - -int Chicken::getMaxHealth() -{ - return 4; -} - -void Chicken::aiStep() -{ - super::aiStep(); - - oFlap = flap; - oFlapSpeed = flapSpeed; - - flapSpeed += (onGround ? -1 : 4) * 0.3f; - if (flapSpeed < 0) flapSpeed = 0; - if (flapSpeed > 1) flapSpeed = 1; - - if (!onGround && flapping < 1) flapping = 1; - flapping *= 0.9f; - - if (!onGround && yd < 0) { - yd *= 0.6f; - } - - flap += flapping * 2; - - //@todo - //if (!isBaby()) { - // if (!level->isClientSide && --eggTime <= 0) { - // level->playSound(this, "mob.chickenplop", 1.0f, (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); - // spawnAtLocation(Item::egg->id, 1); - // eggTime = random.nextInt(SharedConstants::TicksPerSecond * 60 * 5) + SharedConstants::TicksPerSecond * 60 * 5; - // } - //} -} - -void Chicken::addAdditonalSaveData( CompoundTag* tag ) -{ - super::addAdditonalSaveData(tag); -} - -void Chicken::readAdditionalSaveData( CompoundTag* tag ) -{ - super::readAdditionalSaveData(tag); -} - -void Chicken::causeFallDamage( float distance ) -{ -} - -const char* Chicken::getAmbientSound() -{ - return "mob.chicken"; -} - -std::string Chicken::getHurtSound() -{ - return "mob.chickenhurt"; -} - -std::string Chicken::getDeathSound() -{ - return "mob.chickenhurt"; -} - -//int Chicken::getDeathLoot() -//{ -// return Item::feather->id; -//} - -void Chicken::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) -{ - //// drop some feathers - int count = random.nextInt(3);// + random.nextInt(1 + playerBonusLevel); - for (int i = 0; i < count; i++) { - spawnAtLocation(Item::feather->id, 1); - } - //// and some meat - //if (isOnFire()) spawnAtLocation(Item::chicken_cooked->id, 1); //@fire - //else - spawnAtLocation(Item::chicken_raw->id, 1); -} - -Animal* Chicken::getBreedOffspring( Animal* target ) -{ - return new Chicken(level); -} +#include "Chicken.hpp" +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" + +Chicken::Chicken( Level* level ) +: super(level), + sheared(false), + flap(0), + oFlap(0), + flapSpeed(0), + oFlapSpeed(0), + flapping(1), + eggTime(0) +{ + entityRendererId = ER_CHICKEN_RENDERER; + + textureName = "mob/chicken.png"; + setSize(0.3f, 0.7f); + eggTime = random.nextInt(SharedConstants::TicksPerSecond * 60 * 5) + SharedConstants::TicksPerSecond * 60 * 5; +} + +int Chicken::getEntityTypeId() const +{ + return MobTypes::Chicken; +} + + +int Chicken::getMaxHealth() +{ + return 4; +} + +void Chicken::aiStep() +{ + super::aiStep(); + + oFlap = flap; + oFlapSpeed = flapSpeed; + + flapSpeed += (onGround ? -1 : 4) * 0.3f; + if (flapSpeed < 0) flapSpeed = 0; + if (flapSpeed > 1) flapSpeed = 1; + + if (!onGround && flapping < 1) flapping = 1; + flapping *= 0.9f; + + if (!onGround && yd < 0) { + yd *= 0.6f; + } + + flap += flapping * 2; + + //@todo + //if (!isBaby()) { + // if (!level->isClientSide && --eggTime <= 0) { + // level->playSound(this, "mob.chickenplop", 1.0f, (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); + // spawnAtLocation(Item::egg->id, 1); + // eggTime = random.nextInt(SharedConstants::TicksPerSecond * 60 * 5) + SharedConstants::TicksPerSecond * 60 * 5; + // } + //} +} + +void Chicken::addAdditonalSaveData( CompoundTag* tag ) +{ + super::addAdditonalSaveData(tag); +} + +void Chicken::readAdditionalSaveData( CompoundTag* tag ) +{ + super::readAdditionalSaveData(tag); +} + +void Chicken::causeFallDamage( float distance ) +{ +} + +const char* Chicken::getAmbientSound() +{ + return "mob.chicken"; +} + +std::string Chicken::getHurtSound() +{ + return "mob.chickenhurt"; +} + +std::string Chicken::getDeathSound() +{ + return "mob.chickenhurt"; +} + +//int Chicken::getDeathLoot() +//{ +// return Item::feather->id; +//} + +void Chicken::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) +{ + //// drop some feathers + int count = random.nextInt(3);// + random.nextInt(1 + playerBonusLevel); + for (int i = 0; i < count; i++) { + spawnAtLocation(Item::feather->id, 1); + } + //// and some meat + //if (isOnFire()) spawnAtLocation(Item::chicken_cooked->id, 1); //@fire + //else + spawnAtLocation(Item::chicken_raw->id, 1); +} + +Animal* Chicken::getBreedOffspring( Animal* target ) +{ + return new Chicken(level); +} diff --git a/src/world/entity/animal/Chicken.h b/src/world/entity/animal/Chicken.hpp similarity index 97% rename from src/world/entity/animal/Chicken.h rename to src/world/entity/animal/Chicken.hpp index ce4f199..84f2c47 100755 --- a/src/world/entity/animal/Chicken.h +++ b/src/world/entity/animal/Chicken.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.animal; -#include "Animal.h" +#include "Animal.hpp" class CompoundTag; class Level; diff --git a/src/world/entity/animal/Cow.cpp b/src/world/entity/animal/Cow.cpp index 49df047..be63fd0 100755 --- a/src/world/entity/animal/Cow.cpp +++ b/src/world/entity/animal/Cow.cpp @@ -1,79 +1,79 @@ -#include "Cow.h" -#include "../player/Player.h" -#include "../../level/Level.h" -#include "../../item/Item.h" - -Cow::Cow( Level* level ) -: super(level) -{ - entityRendererId = ER_COW_RENDERER; - - textureName = "mob/cow.png"; - setSize(0.9f, 1.3f); -} - -int Cow::getEntityTypeId() const { - return MobTypes::Cow; -} - -int Cow::getMaxHealth() { - return 10; -} - -void Cow::addAdditonalSaveData( CompoundTag* tag ) { - super::addAdditonalSaveData(tag); -} - -void Cow::readAdditionalSaveData( CompoundTag* tag ) { - super::readAdditionalSaveData(tag); -} - -bool Cow::interact( Player* player ) { - //ItemInstance item = player->inventory.getSelected(); - //if (item != NULL && item.id == Item::bucket_empty->id) { - // player->inventory.setItem(player->inventory.selected, /*new*/ ItemInstance(Item::milk)); - // return true; - //} - return super::interact(player); -} - -const char* Cow::getAmbientSound() { - return "mob.cow"; -} - -std::string Cow::getHurtSound() { - return "mob.cowhurt"; -} - -std::string Cow::getDeathSound() { - return "mob.cowhurt"; -} - -float Cow::getSoundVolume() { - return 0.4f; -} - -int Cow::getDeathLoot() { - return Item::leather->id; -} - -void Cow::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) { - // drop some leather - int count = random.nextInt(3);// + random.nextInt(1 + playerBonusLevel); - for (int i = 0; i < count; i++) { - spawnAtLocation(Item::leather->id, 1); - } - // and some meat - count = random.nextInt(3) + 1; - for (int i = 0; i < count; i++) { - // if (isOnFire()) { //@fire - // spawnAtLocation(Item::beef_cooked->id, 1); - // } else { - spawnAtLocation(Item::beef_raw->id, 1); - // } - } -} - -Animal* Cow::getBreedOffspring( Animal* target ) { - return new Cow(level); -} +#include "Cow.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/item/Item.hpp" + +Cow::Cow( Level* level ) +: super(level) +{ + entityRendererId = ER_COW_RENDERER; + + textureName = "mob/cow.png"; + setSize(0.9f, 1.3f); +} + +int Cow::getEntityTypeId() const { + return MobTypes::Cow; +} + +int Cow::getMaxHealth() { + return 10; +} + +void Cow::addAdditonalSaveData( CompoundTag* tag ) { + super::addAdditonalSaveData(tag); +} + +void Cow::readAdditionalSaveData( CompoundTag* tag ) { + super::readAdditionalSaveData(tag); +} + +bool Cow::interact( Player* player ) { + //ItemInstance item = player->inventory.getSelected(); + //if (item != NULL && item.id == Item::bucket_empty->id) { + // player->inventory.setItem(player->inventory.selected, /*new*/ ItemInstance(Item::milk)); + // return true; + //} + return super::interact(player); +} + +const char* Cow::getAmbientSound() { + return "mob.cow"; +} + +std::string Cow::getHurtSound() { + return "mob.cowhurt"; +} + +std::string Cow::getDeathSound() { + return "mob.cowhurt"; +} + +float Cow::getSoundVolume() { + return 0.4f; +} + +int Cow::getDeathLoot() { + return Item::leather->id; +} + +void Cow::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) { + // drop some leather + int count = random.nextInt(3);// + random.nextInt(1 + playerBonusLevel); + for (int i = 0; i < count; i++) { + spawnAtLocation(Item::leather->id, 1); + } + // and some meat + count = random.nextInt(3) + 1; + for (int i = 0; i < count; i++) { + // if (isOnFire()) { //@fire + // spawnAtLocation(Item::beef_cooked->id, 1); + // } else { + spawnAtLocation(Item::beef_raw->id, 1); + // } + } +} + +Animal* Cow::getBreedOffspring( Animal* target ) { + return new Cow(level); +} diff --git a/src/world/entity/animal/Cow.h b/src/world/entity/animal/Cow.hpp similarity index 97% rename from src/world/entity/animal/Cow.h rename to src/world/entity/animal/Cow.hpp index 8368fbc..cc41fa3 100755 --- a/src/world/entity/animal/Cow.h +++ b/src/world/entity/animal/Cow.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.animal; -#include "Animal.h" +#include "Animal.hpp" class Level; class Player; diff --git a/src/world/entity/animal/Pig.cpp b/src/world/entity/animal/Pig.cpp index b6eb4c0..347e3bf 100755 --- a/src/world/entity/animal/Pig.cpp +++ b/src/world/entity/animal/Pig.cpp @@ -1,70 +1,70 @@ -#include "Pig.h" -#include "../player/Player.h" - -Pig::Pig( Level* level ) : super(level) -{ - entityRendererId = ER_PIG_RENDERER; - - textureName = "mob/pig.png"; - setSize(0.9f, 0.9f); - - //entityData.define(DATA_SADDLE_ID, (SynchedEntityData::TypeChar) 0); -} - -int Pig::getEntityTypeId() const -{ - return MobTypes::Pig; -} - -bool Pig::interact( Player* player ) -{ - return false; -} - -bool Pig::hasSaddle() -{ - return false; - //return (entityData.getByte(DATA_SADDLE_ID) & 1) != 0; -} - -void Pig::setSaddle( bool value ) -{ - //if (value) { - // entityData.set(DATA_SADDLE_ID, (char) 1); - //} else { - // entityData.set(DATA_SADDLE_ID, (char) 0); - //} -} - -const char* Pig::getAmbientSound() -{ - return "mob.pig"; -} - -std::string Pig::getHurtSound() -{ - return "mob.pig"; -} - -std::string Pig::getDeathSound() -{ - return "mob.pigdeath"; -} - -int Pig::getDeathLoot() -{ - //@fire - //if (isOnFire()) - // return Item::porkChop_cooked->id; - return Item::porkChop_raw->id; -} - -Animal* Pig::getBreedOffspring( Animal* target ) -{ - return new Pig(level); -} - -int Pig::getMaxHealth() -{ - return 10; -} +#include "Pig.hpp" +#include "world/entity/player/Player.hpp" + +Pig::Pig( Level* level ) : super(level) +{ + entityRendererId = ER_PIG_RENDERER; + + textureName = "mob/pig.png"; + setSize(0.9f, 0.9f); + + //entityData.define(DATA_SADDLE_ID, (SynchedEntityData::TypeChar) 0); +} + +int Pig::getEntityTypeId() const +{ + return MobTypes::Pig; +} + +bool Pig::interact( Player* player ) +{ + return false; +} + +bool Pig::hasSaddle() +{ + return false; + //return (entityData.getByte(DATA_SADDLE_ID) & 1) != 0; +} + +void Pig::setSaddle( bool value ) +{ + //if (value) { + // entityData.set(DATA_SADDLE_ID, (char) 1); + //} else { + // entityData.set(DATA_SADDLE_ID, (char) 0); + //} +} + +const char* Pig::getAmbientSound() +{ + return "mob.pig"; +} + +std::string Pig::getHurtSound() +{ + return "mob.pig"; +} + +std::string Pig::getDeathSound() +{ + return "mob.pigdeath"; +} + +int Pig::getDeathLoot() +{ + //@fire + //if (isOnFire()) + // return Item::porkChop_cooked->id; + return Item::porkChop_raw->id; +} + +Animal* Pig::getBreedOffspring( Animal* target ) +{ + return new Pig(level); +} + +int Pig::getMaxHealth() +{ + return 10; +} diff --git a/src/world/entity/animal/Pig.h b/src/world/entity/animal/Pig.hpp similarity index 97% rename from src/world/entity/animal/Pig.h rename to src/world/entity/animal/Pig.hpp index 8dba8c3..aa3d997 100755 --- a/src/world/entity/animal/Pig.h +++ b/src/world/entity/animal/Pig.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.animal; -#include "Animal.h" +#include "Animal.hpp" class Player; diff --git a/src/world/entity/animal/Sheep.cpp b/src/world/entity/animal/Sheep.cpp index 9039fa1..aaa3590 100755 --- a/src/world/entity/animal/Sheep.cpp +++ b/src/world/entity/animal/Sheep.cpp @@ -1,252 +1,252 @@ -#include "Sheep.h" -#include "../../item/DyePowderItem.h" -#include "../../level/tile/LevelEvent.h" - -const float Sheep::COLOR[][3] = { - { 1.0f, 1.0f, 1.0f }, // white - { 0.95f, 0.7f, 0.2f }, // orange - { 0.9f, 0.5f, 0.85f }, // magenta - { 0.6f, 0.7f, 0.95f }, // light blue - { 0.9f, 0.9f, 0.2f }, // yellow - { 0.5f, 0.8f, 0.1f }, // light green - { 0.95f, 0.7f, 0.8f }, // pink - { 0.3f, 0.3f, 0.3f }, // gray - { 0.6f, 0.6f, 0.6f }, // silver - { 0.3f, 0.6f, 0.7f }, // cyan - { 0.7f, 0.4f, 0.9f }, // purple - { 0.2f, 0.4f, 0.8f }, // blue - { 0.5f, 0.4f, 0.3f }, // brown - { 0.4f, 0.5f, 0.2f }, // green - { 0.8f, 0.3f, 0.3f }, // red - { 0.1f, 0.1f, 0.1f }, // black -}; -const int Sheep::NumColors = sizeof(Sheep::COLOR) / sizeof(Sheep*); - - -Sheep::Sheep( Level* level ) -: super(level), - eatAnimationTick(0) -{ - entityRendererId = ER_SHEEP_RENDERER; - - this->textureName = "mob/sheep.png"; - this->setSize(0.9f, 1.3f); - - // sheared and color share a char - entityData.define(DATA_WOOL_ID, (SynchedEntityData::TypeChar) 0); -} - -int Sheep::getMaxHealth() -{ - return 8; -} - -void Sheep::aiStep() -{ - super::aiStep(); - - if (eatAnimationTick > 0) { - eatAnimationTick--; - } -} - -void Sheep::handleEntityEvent( char id ) -{ - if (id == EntityEvent::EAT_GRASS) { - eatAnimationTick = EAT_ANIMATION_TICKS; - } else { - super::handleEntityEvent(id); - } -} - -float Sheep::getHeadEatPositionScale( float a ) -{ - if (eatAnimationTick <= 0) { - return 0; - } - if (eatAnimationTick >= 4 && eatAnimationTick <= (EAT_ANIMATION_TICKS - 4)) { - return 1; - } - if (eatAnimationTick < 4) { - return ((float) eatAnimationTick - a) / 4.f; - } - return -((float) (eatAnimationTick - EAT_ANIMATION_TICKS) - a) / 4.f; -} - -float Sheep::getHeadEatAngleScale( float a ) -{ - if (eatAnimationTick > 4 && eatAnimationTick <= (EAT_ANIMATION_TICKS - 4)) { - float scale = ((float) (eatAnimationTick - 4) - a) / (float) (EAT_ANIMATION_TICKS - 8); - return Mth::PI * .20f + Mth::PI * .07f * Mth::sin(scale * 28.7f); - } - if (eatAnimationTick > 0) { - return Mth::PI * .20f; - } - return ((xRot / (float) (180 / Mth::PI))); -} - -bool Sheep::interact( Player* player ) -{ - ItemInstance* item = player->inventory->getSelected(); - if (item && item->id == ((Item*)Item::shears)->id && !isSheared() && !isBaby()) { - if (!level->isClientSide) { - setSheared(true); - int count = 1 + random.nextInt(3); - for (int i = 0; i < count; i++) { - ItemEntity* ie = spawnAtLocation(new ItemInstance(Tile::cloth->id, 1, getColor()), 1); - ie->yd += random.nextFloat() * 0.05f; - ie->xd += (random.nextFloat() - random.nextFloat()) * 0.1f; - ie->zd += (random.nextFloat() - random.nextFloat()) * 0.1f; - } - } - item->hurt(1); - } - - return super::interact(player); -} - -void Sheep::addAdditonalSaveData( CompoundTag* tag ) -{ - super::addAdditonalSaveData(tag); - tag->putBoolean("Sheared", isSheared()); - tag->putByte("Color", (char) getColor()); -} - -void Sheep::readAdditionalSaveData( CompoundTag* tag ) -{ - super::readAdditionalSaveData(tag); - setSheared(tag->getBoolean("Sheared")); - setColor((int) tag->getByte("Color")); -} - -int Sheep::getColor() const -{ - return (int) (entityData.getByte(DATA_WOOL_ID) & 0x0f); -} - -void Sheep::setColor( int color ) -{ - char current = entityData.getByte(DATA_WOOL_ID); - entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) ((current & 0xf0) | (color & 0x0f))); -} - -bool Sheep::isSheared() const -{ - return (entityData.getByte(DATA_WOOL_ID) & 0x10) != 0; -} - -void Sheep::setSheared( bool value ) -{ - char current = entityData.getByte(DATA_WOOL_ID); - if (value) { - entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) (current | 0x10)); - } else { - entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) (current & ~0x10)); - } -} - -int Sheep::getSheepColor( Random* random ) -{ - int nextInt = random->nextInt(100); - if (nextInt < 5) - return 15 - DyePowderItem::BLACK; - if (nextInt < 10) - return 15 - DyePowderItem::GRAY; - if (nextInt < 15) - return 15 - DyePowderItem::SILVER; - if (nextInt < 18) - return 15 - DyePowderItem::BROWN; - - if (random->nextInt(500) == 0) - return 15 - DyePowderItem::PINK; - - return 0; // white -} - -int Sheep::getEntityTypeId() const -{ - return MobTypes::Sheep; -} - -void Sheep::dropDeathLoot(/* bool wasKilledByPlayer, int playerBonusLevel*/ ) -{ - if (!isSheared()) { - // killing a non-sheared sheep will drop a single block of cloth - spawnAtLocation(new ItemInstance(Tile::cloth->id, 1, getColor()), 0); - } -} - -int Sheep::getDeathLoot() -{ - return Tile::cloth->id; -} - -void Sheep::jumpFromGround() -{ - if (eatAnimationTick <= 0) { - super::jumpFromGround(); - } -} - -void Sheep::updateAi() -{ - super::updateAi(); - - if (!isPathFinding() && eatAnimationTick <= 0 && ((isBaby() && random.nextInt(50) == 0) || random.nextInt(1000) == 0)) { - - int xx = Mth::floor(x); - int yy = Mth::floor(y); - int zz = Mth::floor(z); - - if (/*(level->getTile(xx, yy, zz) == Tile::tallgrass->id && level->getData(xx, yy, zz) == TallGrass::TALL_GRASS) || */ level->getTile(xx, yy - 1, zz) == ((Tile*)Tile::grass)->id) { - eatAnimationTick = EAT_ANIMATION_TICKS; - level->broadcastEntityEvent(this, EntityEvent::EAT_GRASS); - } - } else if (eatAnimationTick == 4) { - int xx = Mth::floor(x); - int yy = Mth::floor(y); - int zz = Mth::floor(z); - - bool ate = false; - /* if (level->getTile(xx, yy, zz) == Tile::tallgrass->id) { - level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy, zz, Tile::tallgrass->id + TallGrass::TALL_GRASS * 256); - level->setTile(xx, yy, zz, 0); - ate = true; - } else */if (level->getTile(xx, yy - 1, zz) == ((Tile*)Tile::grass)->id) { - level->levelEvent(NULL, LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy - 1, zz, ((Tile*)Tile::grass)->id); - level->setTile(xx, yy - 1, zz, Tile::dirt->id); - ate = true; - } - if (ate) { - setSheared(false); - if (isBaby()) { - // remove a minute from aging - int age = getAge() + SharedConstants::TicksPerSecond * 60; - if (age > 0) { - age = 0; - } - setAge(age); - } - } - } -} - -bool Sheep::shouldHoldGround() -{ - return eatAnimationTick > 0; -} - -const char* Sheep::getAmbientSound() -{ - return "mob.sheep"; -} - -std::string Sheep::getHurtSound() -{ - return "mob.sheep"; -} - -std::string Sheep::getDeathSound() -{ - return "mob.sheep"; -} +#include "Sheep.hpp" +#include "world/item/DyePowderItem.hpp" +#include "world/level/tile/LevelEvent.hpp" + +const float Sheep::COLOR[][3] = { + { 1.0f, 1.0f, 1.0f }, // white + { 0.95f, 0.7f, 0.2f }, // orange + { 0.9f, 0.5f, 0.85f }, // magenta + { 0.6f, 0.7f, 0.95f }, // light blue + { 0.9f, 0.9f, 0.2f }, // yellow + { 0.5f, 0.8f, 0.1f }, // light green + { 0.95f, 0.7f, 0.8f }, // pink + { 0.3f, 0.3f, 0.3f }, // gray + { 0.6f, 0.6f, 0.6f }, // silver + { 0.3f, 0.6f, 0.7f }, // cyan + { 0.7f, 0.4f, 0.9f }, // purple + { 0.2f, 0.4f, 0.8f }, // blue + { 0.5f, 0.4f, 0.3f }, // brown + { 0.4f, 0.5f, 0.2f }, // green + { 0.8f, 0.3f, 0.3f }, // red + { 0.1f, 0.1f, 0.1f }, // black +}; +const int Sheep::NumColors = sizeof(Sheep::COLOR) / sizeof(Sheep*); + + +Sheep::Sheep( Level* level ) +: super(level), + eatAnimationTick(0) +{ + entityRendererId = ER_SHEEP_RENDERER; + + this->textureName = "mob/sheep.png"; + this->setSize(0.9f, 1.3f); + + // sheared and color share a char + entityData.define(DATA_WOOL_ID, (SynchedEntityData::TypeChar) 0); +} + +int Sheep::getMaxHealth() +{ + return 8; +} + +void Sheep::aiStep() +{ + super::aiStep(); + + if (eatAnimationTick > 0) { + eatAnimationTick--; + } +} + +void Sheep::handleEntityEvent( char id ) +{ + if (id == EntityEvent::EAT_GRASS) { + eatAnimationTick = EAT_ANIMATION_TICKS; + } else { + super::handleEntityEvent(id); + } +} + +float Sheep::getHeadEatPositionScale( float a ) +{ + if (eatAnimationTick <= 0) { + return 0; + } + if (eatAnimationTick >= 4 && eatAnimationTick <= (EAT_ANIMATION_TICKS - 4)) { + return 1; + } + if (eatAnimationTick < 4) { + return ((float) eatAnimationTick - a) / 4.f; + } + return -((float) (eatAnimationTick - EAT_ANIMATION_TICKS) - a) / 4.f; +} + +float Sheep::getHeadEatAngleScale( float a ) +{ + if (eatAnimationTick > 4 && eatAnimationTick <= (EAT_ANIMATION_TICKS - 4)) { + float scale = ((float) (eatAnimationTick - 4) - a) / (float) (EAT_ANIMATION_TICKS - 8); + return Mth::PI * .20f + Mth::PI * .07f * Mth::sin(scale * 28.7f); + } + if (eatAnimationTick > 0) { + return Mth::PI * .20f; + } + return ((xRot / (float) (180 / Mth::PI))); +} + +bool Sheep::interact( Player* player ) +{ + ItemInstance* item = player->inventory->getSelected(); + if (item && item->id == ((Item*)Item::shears)->id && !isSheared() && !isBaby()) { + if (!level->isClientSide) { + setSheared(true); + int count = 1 + random.nextInt(3); + for (int i = 0; i < count; i++) { + ItemEntity* ie = spawnAtLocation(new ItemInstance(Tile::cloth->id, 1, getColor()), 1); + ie->yd += random.nextFloat() * 0.05f; + ie->xd += (random.nextFloat() - random.nextFloat()) * 0.1f; + ie->zd += (random.nextFloat() - random.nextFloat()) * 0.1f; + } + } + item->hurt(1); + } + + return super::interact(player); +} + +void Sheep::addAdditonalSaveData( CompoundTag* tag ) +{ + super::addAdditonalSaveData(tag); + tag->putBoolean("Sheared", isSheared()); + tag->putByte("Color", (char) getColor()); +} + +void Sheep::readAdditionalSaveData( CompoundTag* tag ) +{ + super::readAdditionalSaveData(tag); + setSheared(tag->getBoolean("Sheared")); + setColor((int) tag->getByte("Color")); +} + +int Sheep::getColor() const +{ + return (int) (entityData.getByte(DATA_WOOL_ID) & 0x0f); +} + +void Sheep::setColor( int color ) +{ + char current = entityData.getByte(DATA_WOOL_ID); + entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) ((current & 0xf0) | (color & 0x0f))); +} + +bool Sheep::isSheared() const +{ + return (entityData.getByte(DATA_WOOL_ID) & 0x10) != 0; +} + +void Sheep::setSheared( bool value ) +{ + char current = entityData.getByte(DATA_WOOL_ID); + if (value) { + entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) (current | 0x10)); + } else { + entityData.set(DATA_WOOL_ID, (SynchedEntityData::TypeChar) (current & ~0x10)); + } +} + +int Sheep::getSheepColor( Random* random ) +{ + int nextInt = random->nextInt(100); + if (nextInt < 5) + return 15 - DyePowderItem::BLACK; + if (nextInt < 10) + return 15 - DyePowderItem::GRAY; + if (nextInt < 15) + return 15 - DyePowderItem::SILVER; + if (nextInt < 18) + return 15 - DyePowderItem::BROWN; + + if (random->nextInt(500) == 0) + return 15 - DyePowderItem::PINK; + + return 0; // white +} + +int Sheep::getEntityTypeId() const +{ + return MobTypes::Sheep; +} + +void Sheep::dropDeathLoot(/* bool wasKilledByPlayer, int playerBonusLevel*/ ) +{ + if (!isSheared()) { + // killing a non-sheared sheep will drop a single block of cloth + spawnAtLocation(new ItemInstance(Tile::cloth->id, 1, getColor()), 0); + } +} + +int Sheep::getDeathLoot() +{ + return Tile::cloth->id; +} + +void Sheep::jumpFromGround() +{ + if (eatAnimationTick <= 0) { + super::jumpFromGround(); + } +} + +void Sheep::updateAi() +{ + super::updateAi(); + + if (!isPathFinding() && eatAnimationTick <= 0 && ((isBaby() && random.nextInt(50) == 0) || random.nextInt(1000) == 0)) { + + int xx = Mth::floor(x); + int yy = Mth::floor(y); + int zz = Mth::floor(z); + + if (/*(level->getTile(xx, yy, zz) == Tile::tallgrass->id && level->getData(xx, yy, zz) == TallGrass::TALL_GRASS) || */ level->getTile(xx, yy - 1, zz) == ((Tile*)Tile::grass)->id) { + eatAnimationTick = EAT_ANIMATION_TICKS; + level->broadcastEntityEvent(this, EntityEvent::EAT_GRASS); + } + } else if (eatAnimationTick == 4) { + int xx = Mth::floor(x); + int yy = Mth::floor(y); + int zz = Mth::floor(z); + + bool ate = false; + /* if (level->getTile(xx, yy, zz) == Tile::tallgrass->id) { + level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy, zz, Tile::tallgrass->id + TallGrass::TALL_GRASS * 256); + level->setTile(xx, yy, zz, 0); + ate = true; + } else */if (level->getTile(xx, yy - 1, zz) == ((Tile*)Tile::grass)->id) { + level->levelEvent(NULL, LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy - 1, zz, ((Tile*)Tile::grass)->id); + level->setTile(xx, yy - 1, zz, Tile::dirt->id); + ate = true; + } + if (ate) { + setSheared(false); + if (isBaby()) { + // remove a minute from aging + int age = getAge() + SharedConstants::TicksPerSecond * 60; + if (age > 0) { + age = 0; + } + setAge(age); + } + } + } +} + +bool Sheep::shouldHoldGround() +{ + return eatAnimationTick > 0; +} + +const char* Sheep::getAmbientSound() +{ + return "mob.sheep"; +} + +std::string Sheep::getHurtSound() +{ + return "mob.sheep"; +} + +std::string Sheep::getDeathSound() +{ + return "mob.sheep"; +} diff --git a/src/world/entity/animal/Sheep.h b/src/world/entity/animal/Sheep.hpp similarity index 82% rename from src/world/entity/animal/Sheep.h rename to src/world/entity/animal/Sheep.hpp index 76230f5..3ee15c0 100755 --- a/src/world/entity/animal/Sheep.h +++ b/src/world/entity/animal/Sheep.hpp @@ -2,19 +2,19 @@ //package net.minecraft.world.entity.animal; -#include "Animal.h" +#include "Animal.hpp" -#include "../EntityEvent.h" -#include "../item/ItemEntity.h" -#include "../player/Player.h" -#include "../../item/ItemInstance.h" -#include "../../level/Level.h" -#include "../../../SharedConstants.h" -#include "../../../util/Mth.h" +#include "world/entity/EntityEvent.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/Level.hpp" +#include "SharedConstants.hpp" +#include "util/Mth.hpp" -#include "../../item/Item.h" +#include "world/item/Item.hpp" -#include "../../../nbt/CompoundTag.h" +#include "nbt/CompoundTag.hpp" class Sheep: public Animal { diff --git a/src/world/entity/animal/WaterAnimal.cpp b/src/world/entity/animal/WaterAnimal.cpp index 03c9ae5..15355eb 100755 --- a/src/world/entity/animal/WaterAnimal.cpp +++ b/src/world/entity/animal/WaterAnimal.cpp @@ -1,48 +1,48 @@ -#include "WaterAnimal.h" -#include "../../level/Level.h" - - -WaterAnimal::WaterAnimal( Level* level ) -: super(level) -{ -} - -bool WaterAnimal::isWaterMob() -{ - // prevent drowning - return true; -} - -void WaterAnimal::addAdditonalSaveData( CompoundTag* entityTag ) -{ - super::addAdditonalSaveData(entityTag); -} - -void WaterAnimal::readAdditionalSaveData( CompoundTag* tag ) -{ - super::readAdditionalSaveData(tag); -} - -bool WaterAnimal::canSpawn() -{ - return level->isUnobstructed(bb); -} - -int WaterAnimal::getAmbientSoundInterval() -{ - return SharedConstants::TicksPerSecond * 6; -} - -bool WaterAnimal::removeWhenFarAway() -{ - return true; -} - -int WaterAnimal::getExperienceReward( Player* killedBy ) -{ - return 1 + level->random.nextInt(3); -} - -int WaterAnimal::getCreatureBaseType() const { - return MobTypes::BaseWaterCreature; -} +#include "WaterAnimal.hpp" +#include "world/level/Level.hpp" + + +WaterAnimal::WaterAnimal( Level* level ) +: super(level) +{ +} + +bool WaterAnimal::isWaterMob() +{ + // prevent drowning + return true; +} + +void WaterAnimal::addAdditonalSaveData( CompoundTag* entityTag ) +{ + super::addAdditonalSaveData(entityTag); +} + +void WaterAnimal::readAdditionalSaveData( CompoundTag* tag ) +{ + super::readAdditionalSaveData(tag); +} + +bool WaterAnimal::canSpawn() +{ + return level->isUnobstructed(bb); +} + +int WaterAnimal::getAmbientSoundInterval() +{ + return SharedConstants::TicksPerSecond * 6; +} + +bool WaterAnimal::removeWhenFarAway() +{ + return true; +} + +int WaterAnimal::getExperienceReward( Player* killedBy ) +{ + return 1 + level->random.nextInt(3); +} + +int WaterAnimal::getCreatureBaseType() const { + return MobTypes::BaseWaterCreature; +} diff --git a/src/world/entity/animal/WaterAnimal.h b/src/world/entity/animal/WaterAnimal.hpp similarity index 91% rename from src/world/entity/animal/WaterAnimal.h rename to src/world/entity/animal/WaterAnimal.hpp index 4d541b9..b8b29fe 100755 --- a/src/world/entity/animal/WaterAnimal.h +++ b/src/world/entity/animal/WaterAnimal.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.entity.animal; -#include "../PathfinderMob.h" -#include "../Creature.h" +#include "world/entity/PathfinderMob.hpp" +#include "world/entity/Creature.hpp" class Level; class Player; diff --git a/src/world/entity/item/FallingTile.cpp b/src/world/entity/item/FallingTile.cpp index 6045167..8b94aec 100755 --- a/src/world/entity/item/FallingTile.cpp +++ b/src/world/entity/item/FallingTile.cpp @@ -1,117 +1,117 @@ -#include "FallingTile.h" -#include "../../level/Level.h" -#include "../../../util/Random.h" -#include "../../../nbt/CompoundTag.h" - - -FallingTile::FallingTile( Level* level ) -: Entity(level), - tile(0), - data(0) -{ - init(); -} - -FallingTile::FallingTile( Level* level, float x, float y, float z, int tile, int data) -: Entity(level), - tile(tile), - data(data) -{ - init(); - - setPos(x, y, z); - xo = xOld = x; - yo = yOld = y; - zo = zOld = z; -} - -void FallingTile::init() { - entityRendererId = ER_FALLINGTILE_RENDERER; - - time = 0; - blocksBuilding = true; - setSize(0.98f, 0.98f); - heightOffset = bbHeight / 2.0f; - - makeStepSound = false; - - xd = 0; - yd = 0; - zd = 0; -} - -bool FallingTile::isPickable() { - return !removed; -} - -void FallingTile::tick() { - if (tile == 0) { - remove(); - return; - } - - xo = x; - yo = y; - zo = z; - time++; - - yd -= 0.04f; - move(xd, yd, zd); - xd *= 0.98f; - yd *= 0.98f; - zd *= 0.98f; - - if (!level->isClientSide) { - int xt = Mth::floor(x); - int yt = Mth::floor(y); - int zt = Mth::floor(z); - - if (time == 1) { - if (level->getTile(xt, yt, zt) == tile) { - level->setTile(xt, yt, zt, 0); - } else { - remove(); - return; - } - } - - if (onGround) { - xd *= 0.7f; - zd *= 0.7f; - yd *= -0.5f; - - remove(); - if (level->mayPlace(tile, xt, yt, zt, true, 1) && level->setTileAndData(xt, yt, zt, tile, data)) { - } else if (!level->isClientSide) { - //spawnAtLocation(tile, 1); - } - } else if (time > SharedConstants::TicksPerSecond * 5 && !level->isClientSide) { - //spawnAtLocation(tile, 1); - remove(); - } - } -} - -float FallingTile::getShadowHeightOffs() { - return 0; -} - -Level* FallingTile::getLevel() { - return level; -} - -void FallingTile::addAdditonalSaveData( CompoundTag* tag ) { - tag->putByte("Tile", (char) tile); - tag->putByte("Data", (char) data); - tag->putByte("Time", (char) time); -} - -void FallingTile::readAdditionalSaveData( CompoundTag* tag ) { - tile = tag->getByte("Tile"); - data = tag->getByte("Data"); - time = tag->getByte("Time"); -} - -int FallingTile::getEntityTypeId() const { - return EntityTypes::IdFallingTile; -} +#include "FallingTile.hpp" +#include "world/level/Level.hpp" +#include "util/Random.hpp" +#include "nbt/CompoundTag.hpp" + + +FallingTile::FallingTile( Level* level ) +: Entity(level), + tile(0), + data(0) +{ + init(); +} + +FallingTile::FallingTile( Level* level, float x, float y, float z, int tile, int data) +: Entity(level), + tile(tile), + data(data) +{ + init(); + + setPos(x, y, z); + xo = xOld = x; + yo = yOld = y; + zo = zOld = z; +} + +void FallingTile::init() { + entityRendererId = ER_FALLINGTILE_RENDERER; + + time = 0; + blocksBuilding = true; + setSize(0.98f, 0.98f); + heightOffset = bbHeight / 2.0f; + + makeStepSound = false; + + xd = 0; + yd = 0; + zd = 0; +} + +bool FallingTile::isPickable() { + return !removed; +} + +void FallingTile::tick() { + if (tile == 0) { + remove(); + return; + } + + xo = x; + yo = y; + zo = z; + time++; + + yd -= 0.04f; + move(xd, yd, zd); + xd *= 0.98f; + yd *= 0.98f; + zd *= 0.98f; + + if (!level->isClientSide) { + int xt = Mth::floor(x); + int yt = Mth::floor(y); + int zt = Mth::floor(z); + + if (time == 1) { + if (level->getTile(xt, yt, zt) == tile) { + level->setTile(xt, yt, zt, 0); + } else { + remove(); + return; + } + } + + if (onGround) { + xd *= 0.7f; + zd *= 0.7f; + yd *= -0.5f; + + remove(); + if (level->mayPlace(tile, xt, yt, zt, true, 1) && level->setTileAndData(xt, yt, zt, tile, data)) { + } else if (!level->isClientSide) { + //spawnAtLocation(tile, 1); + } + } else if (time > SharedConstants::TicksPerSecond * 5 && !level->isClientSide) { + //spawnAtLocation(tile, 1); + remove(); + } + } +} + +float FallingTile::getShadowHeightOffs() { + return 0; +} + +Level* FallingTile::getLevel() { + return level; +} + +void FallingTile::addAdditonalSaveData( CompoundTag* tag ) { + tag->putByte("Tile", (char) tile); + tag->putByte("Data", (char) data); + tag->putByte("Time", (char) time); +} + +void FallingTile::readAdditionalSaveData( CompoundTag* tag ) { + tile = tag->getByte("Tile"); + data = tag->getByte("Data"); + time = tag->getByte("Time"); +} + +int FallingTile::getEntityTypeId() const { + return EntityTypes::IdFallingTile; +} diff --git a/src/world/entity/item/FallingTile.h b/src/world/entity/item/FallingTile.hpp similarity index 94% rename from src/world/entity/item/FallingTile.h rename to src/world/entity/item/FallingTile.hpp index 086ee22..e0ed62f 100755 --- a/src/world/entity/item/FallingTile.h +++ b/src/world/entity/item/FallingTile.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.item; -#include "../Entity.h" +#include "world/entity/Entity.hpp" class Level; class CompoundTag; diff --git a/src/world/entity/item/ItemEntity.cpp b/src/world/entity/item/ItemEntity.cpp index 86e698f..4327681 100755 --- a/src/world/entity/item/ItemEntity.cpp +++ b/src/world/entity/item/ItemEntity.cpp @@ -1,11 +1,11 @@ -#include "ItemEntity.h" -#include "../../entity/player/Player.h" -#include "../../item/ItemInstance.h" -#include "../../level/Level.h" -#include "../../level/material/Material.h" -#include "../../level/tile/Tile.h" -#include "../../../util/Mth.h" -#include "../../../nbt/CompoundTag.h" +#include "ItemEntity.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Mth.hpp" +#include "nbt/CompoundTag.hpp" const int ItemEntity::LIFETIME = 5 * 60 * SharedConstants::TicksPerSecond; // Five minutes, changed in 0.3.3! diff --git a/src/world/entity/item/ItemEntity.h b/src/world/entity/item/ItemEntity.hpp similarity index 88% rename from src/world/entity/item/ItemEntity.h rename to src/world/entity/item/ItemEntity.hpp index 3a0d8c0..456d626 100755 --- a/src/world/entity/item/ItemEntity.h +++ b/src/world/entity/item/ItemEntity.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.entity.item; -#include "../../item/ItemInstance.h" -#include "../../entity/Entity.h" -#include "../../../SharedConstants.h" +#include "world/item/ItemInstance.hpp" +#include "world/entity/Entity.hpp" +#include "SharedConstants.hpp" class Level; class ItemInstance; diff --git a/src/world/entity/item/PrimedTnt.cpp b/src/world/entity/item/PrimedTnt.cpp index b8f98a1..5bcd71b 100755 --- a/src/world/entity/item/PrimedTnt.cpp +++ b/src/world/entity/item/PrimedTnt.cpp @@ -1,91 +1,91 @@ -#include "PrimedTnt.h" -#include "../../../nbt/CompoundTag.h" - -PrimedTnt::PrimedTnt( Level* level ) -: super(level), - life(80) -{ - entityRendererId = ER_TNT_RENDERER ; - - blocksBuilding = true; - setSize(0.98f, 0.98f); - heightOffset = bbHeight / 2.0f; -} - -PrimedTnt::PrimedTnt( Level* level, float x, float y, float z ) -: super(level), - life(80) -{ - entityRendererId = ER_TNT_RENDERER ; - - blocksBuilding = true; - setSize(0.98f, 0.98f); - heightOffset = bbHeight / 2.0f; - - setPos(x, y, z); - - float rot = Mth::random() * Mth::PI * 2.0f; - xd = Mth::sin(rot * Mth::DEGRAD) * -0.02f; - yd = +0.2f; - zd = Mth::cos(rot * Mth::DEGRAD) * -0.02f; - - makeStepSound = false; - - xo = x; - yo = y; - zo = z; -} - -bool PrimedTnt::isPickable() -{ - return !removed; -} - -void PrimedTnt::tick() -{ - xo = x; - yo = y; - zo = z; - - yd -= 0.04f; - move(xd, yd, zd); - xd *= 0.98f; - yd *= 0.98f; - zd *= 0.98f; - - if (onGround) { - xd *= 0.7f; - zd *= 0.7f; - yd *= -0.5f; - } - life--; - if (!level->isClientSide && life <= 0) { - remove(); - explode(); - } else { - level->addParticle(PARTICLETYPE(smoke), x, y + 0.5f, z, 0, 0, 0); - } -} - -float PrimedTnt::getShadowHeightOffs() -{ - return 0; -} - -void PrimedTnt::explode() -{ - float r = 3.1f; - level->explode(NULL, x, y, z, r); -} - -void PrimedTnt::addAdditonalSaveData(CompoundTag* entityTag) { - entityTag->putByte("Fuse", life); -} - -void PrimedTnt::readAdditionalSaveData(CompoundTag* tag) { - life = tag->getByte("Fuse"); -} - -int PrimedTnt::getEntityTypeId() const { - return EntityTypes::IdPrimedTnt; -} +#include "PrimedTnt.hpp" +#include "nbt/CompoundTag.hpp" + +PrimedTnt::PrimedTnt( Level* level ) +: super(level), + life(80) +{ + entityRendererId = ER_TNT_RENDERER ; + + blocksBuilding = true; + setSize(0.98f, 0.98f); + heightOffset = bbHeight / 2.0f; +} + +PrimedTnt::PrimedTnt( Level* level, float x, float y, float z ) +: super(level), + life(80) +{ + entityRendererId = ER_TNT_RENDERER ; + + blocksBuilding = true; + setSize(0.98f, 0.98f); + heightOffset = bbHeight / 2.0f; + + setPos(x, y, z); + + float rot = Mth::random() * Mth::PI * 2.0f; + xd = Mth::sin(rot * Mth::DEGRAD) * -0.02f; + yd = +0.2f; + zd = Mth::cos(rot * Mth::DEGRAD) * -0.02f; + + makeStepSound = false; + + xo = x; + yo = y; + zo = z; +} + +bool PrimedTnt::isPickable() +{ + return !removed; +} + +void PrimedTnt::tick() +{ + xo = x; + yo = y; + zo = z; + + yd -= 0.04f; + move(xd, yd, zd); + xd *= 0.98f; + yd *= 0.98f; + zd *= 0.98f; + + if (onGround) { + xd *= 0.7f; + zd *= 0.7f; + yd *= -0.5f; + } + life--; + if (!level->isClientSide && life <= 0) { + remove(); + explode(); + } else { + level->addParticle(PARTICLETYPE(smoke), x, y + 0.5f, z, 0, 0, 0); + } +} + +float PrimedTnt::getShadowHeightOffs() +{ + return 0; +} + +void PrimedTnt::explode() +{ + float r = 3.1f; + level->explode(NULL, x, y, z, r); +} + +void PrimedTnt::addAdditonalSaveData(CompoundTag* entityTag) { + entityTag->putByte("Fuse", life); +} + +void PrimedTnt::readAdditionalSaveData(CompoundTag* tag) { + life = tag->getByte("Fuse"); +} + +int PrimedTnt::getEntityTypeId() const { + return EntityTypes::IdPrimedTnt; +} diff --git a/src/world/entity/item/PrimedTnt.h b/src/world/entity/item/PrimedTnt.hpp similarity index 87% rename from src/world/entity/item/PrimedTnt.h rename to src/world/entity/item/PrimedTnt.hpp index 5ec4736..73a5696 100755 --- a/src/world/entity/item/PrimedTnt.h +++ b/src/world/entity/item/PrimedTnt.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.entity.item; -#include "../Entity.h" -#include "../../level/Level.h" +#include "world/entity/Entity.hpp" +#include "world/level/Level.hpp" class CompoundTag; diff --git a/src/world/entity/item/TripodCamera.cpp b/src/world/entity/item/TripodCamera.cpp index 4861c6c..64e7050 100755 --- a/src/world/entity/item/TripodCamera.cpp +++ b/src/world/entity/item/TripodCamera.cpp @@ -1,88 +1,88 @@ -#include "TripodCamera.h" -#include "../player/Player.h" -#include "../../level/Level.h" - - -TripodCamera::TripodCamera( Level* level, Player* owner, float x, float y, float z ) -: super(level), - owner(owner), - life(80), - activated(false) -{ - entityRendererId = ER_TRIPODCAMERA_RENDERER; - - // Copy rotation from the entity placing the camera - xRot = xRotO = owner->xRot; - yRot = yRotO = owner->yRot; - - blocksBuilding = true; - setSize(1.0f, 1.5f); - heightOffset = bbHeight / 2.0f - 0.25f; - - setPos(x, y, z); - - xo = x; - yo = y; - zo = z; -} - -bool TripodCamera::isPickable() -{ - return !removed; -} - -bool TripodCamera::interactPreventDefault() -{ - return true; -} - -bool TripodCamera::interact( Player* player ) -{ - activated = true; - return true; -} - -void TripodCamera::tick() -{ - xo = x; - yo = y; - zo = z; - - yd -= 0.04f; - move(xd, yd, zd); - xd *= 0.98f; - yd *= 0.98f; - zd *= 0.98f; - - if (onGround) { - xd *= 0.7f; - zd *= 0.7f; - yd *= -0.5f; - } - - if (activated) { - --life; - - if (life == 0) { - remove(); - } else if (life == 8) { - level->takePicture(this, owner); - level->addParticle(PARTICLETYPE(explode), x, y + 0.6f, z, 0, 0, 0); - level->addParticle(PARTICLETYPE(explode), x, y + 0.8f, z, 0, 0, 0); - level->addParticle(PARTICLETYPE(explode), x, y + 1.0f, z, 0, 0, 0); - } else if (life > 8) { - level->addParticle(PARTICLETYPE(smoke), x, y + 1.0f, z, 0, 0, 0); - } - } -} - -float TripodCamera::getShadowHeightOffs() -{ - return 0; -} - -bool TripodCamera::isPushable() -{ - return false; -} - +#include "TripodCamera.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" + + +TripodCamera::TripodCamera( Level* level, Player* owner, float x, float y, float z ) +: super(level), + owner(owner), + life(80), + activated(false) +{ + entityRendererId = ER_TRIPODCAMERA_RENDERER; + + // Copy rotation from the entity placing the camera + xRot = xRotO = owner->xRot; + yRot = yRotO = owner->yRot; + + blocksBuilding = true; + setSize(1.0f, 1.5f); + heightOffset = bbHeight / 2.0f - 0.25f; + + setPos(x, y, z); + + xo = x; + yo = y; + zo = z; +} + +bool TripodCamera::isPickable() +{ + return !removed; +} + +bool TripodCamera::interactPreventDefault() +{ + return true; +} + +bool TripodCamera::interact( Player* player ) +{ + activated = true; + return true; +} + +void TripodCamera::tick() +{ + xo = x; + yo = y; + zo = z; + + yd -= 0.04f; + move(xd, yd, zd); + xd *= 0.98f; + yd *= 0.98f; + zd *= 0.98f; + + if (onGround) { + xd *= 0.7f; + zd *= 0.7f; + yd *= -0.5f; + } + + if (activated) { + --life; + + if (life == 0) { + remove(); + } else if (life == 8) { + level->takePicture(this, owner); + level->addParticle(PARTICLETYPE(explode), x, y + 0.6f, z, 0, 0, 0); + level->addParticle(PARTICLETYPE(explode), x, y + 0.8f, z, 0, 0, 0); + level->addParticle(PARTICLETYPE(explode), x, y + 1.0f, z, 0, 0, 0); + } else if (life > 8) { + level->addParticle(PARTICLETYPE(smoke), x, y + 1.0f, z, 0, 0, 0); + } + } +} + +float TripodCamera::getShadowHeightOffs() +{ + return 0; +} + +bool TripodCamera::isPushable() +{ + return false; +} + diff --git a/src/world/entity/item/TripodCamera.h b/src/world/entity/item/TripodCamera.hpp similarity index 93% rename from src/world/entity/item/TripodCamera.h rename to src/world/entity/item/TripodCamera.hpp index 2a861cc..9a07dc2 100755 --- a/src/world/entity/item/TripodCamera.h +++ b/src/world/entity/item/TripodCamera.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Mob.h" +#include "world/entity/Mob.hpp" class TripodCamera: public Mob { diff --git a/src/world/entity/monster/Creeper.cpp b/src/world/entity/monster/Creeper.cpp index 86783ad..0c323b4 100755 --- a/src/world/entity/monster/Creeper.cpp +++ b/src/world/entity/monster/Creeper.cpp @@ -1,114 +1,114 @@ -#include "Creeper.h" -#include "../Entity.h" -#include "../../item/Item.h" -#include "../../level/Level.h" -#include "../../../nbt/CompoundTag.h" - -Creeper::Creeper( Level* level ) -: super(level), - swell(0), - oldSwell(0), - swellDir(-1) -{ - entityRendererId = ER_CREEPER_RENDERER; - this->textureName = "mob/creeper.png"; - - entityData.define(DATA_SWELL_DIR, (SynchedEntityData::TypeChar) -1); -} - -int Creeper::getMaxHealth() { - return 16; -} - -void Creeper::tick() { - oldSwell = swell; - if (level->isClientSide) { - int swellDir = getSwellDir(); - if (swellDir > 0 && swell == 0) { - level->playSound(this, "random.fuse", 1, 0.5f); - } - swell += swellDir; - if (swell < 0) swell = 0; - if (swell >= MAX_SWELL) swell = MAX_SWELL; - } - super::tick(); - - if (!level->isClientSide && attackTargetId == 0) { - if (swell > 0) { - setSwellDir(-1); - swell--; - if (swell < 0) { - swell = 0; - } - } - } -} - -float Creeper::getSwelling( float a ) { - return (oldSwell + (swell - oldSwell) * a) / (MAX_SWELL - 2); -} - -int Creeper::getEntityTypeId() const { - return MobTypes::Creeper; -} - -int Creeper::getDeathLoot() { - return Item::sulphur->id; -} - -void Creeper::checkCantSeeTarget( Entity* target, float d ) { - if (level->isClientSide) return; - if (swell > 0) { - setSwellDir(-1); - swell--; - if (swell < 0) { - swell = 0; - } - } -} - -std::string Creeper::getHurtSound() { - return "mob.creeper"; -} - -std::string Creeper::getDeathSound() { - return "mob.creeperdeath"; -} - -void Creeper::checkHurtTarget( Entity* target, float d ) { - if (level->isClientSide) return; - const int swellDir = getSwellDir(); - if ((swellDir <= 0 && d < 3) || (swellDir > 0 && d < 7)) { - if (swell == 0) { - level->playSound(this, "random.fuse", 1, 0.5f); - } - setSwellDir(1); - - if (++swell >= MAX_SWELL) { - level->explode(this, x, y, z, 2.4f); - remove(); - } - holdGround = true; - } else { - setSwellDir(-1); - if (--swell < 0) - swell = 0; - } -} - -int Creeper::getSwellDir() { - return (int) entityData.getByte(DATA_SWELL_DIR); -} - -void Creeper::setSwellDir( int dir ) { - entityData.set(DATA_SWELL_DIR, (SynchedEntityData::TypeChar) dir); -} - -//@todo -//void die(DamageSource* source) { -// super::die(source); - -// if (source.getEntity() instanceof Skeleton) { -// spawnAtLocation(Item::record_01->id + random.nextInt(2), 1); -// } -//} +#include "Creeper.hpp" +#include "world/entity/Entity.hpp" +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" +#include "nbt/CompoundTag.hpp" + +Creeper::Creeper( Level* level ) +: super(level), + swell(0), + oldSwell(0), + swellDir(-1) +{ + entityRendererId = ER_CREEPER_RENDERER; + this->textureName = "mob/creeper.png"; + + entityData.define(DATA_SWELL_DIR, (SynchedEntityData::TypeChar) -1); +} + +int Creeper::getMaxHealth() { + return 16; +} + +void Creeper::tick() { + oldSwell = swell; + if (level->isClientSide) { + int swellDir = getSwellDir(); + if (swellDir > 0 && swell == 0) { + level->playSound(this, "random.fuse", 1, 0.5f); + } + swell += swellDir; + if (swell < 0) swell = 0; + if (swell >= MAX_SWELL) swell = MAX_SWELL; + } + super::tick(); + + if (!level->isClientSide && attackTargetId == 0) { + if (swell > 0) { + setSwellDir(-1); + swell--; + if (swell < 0) { + swell = 0; + } + } + } +} + +float Creeper::getSwelling( float a ) { + return (oldSwell + (swell - oldSwell) * a) / (MAX_SWELL - 2); +} + +int Creeper::getEntityTypeId() const { + return MobTypes::Creeper; +} + +int Creeper::getDeathLoot() { + return Item::sulphur->id; +} + +void Creeper::checkCantSeeTarget( Entity* target, float d ) { + if (level->isClientSide) return; + if (swell > 0) { + setSwellDir(-1); + swell--; + if (swell < 0) { + swell = 0; + } + } +} + +std::string Creeper::getHurtSound() { + return "mob.creeper"; +} + +std::string Creeper::getDeathSound() { + return "mob.creeperdeath"; +} + +void Creeper::checkHurtTarget( Entity* target, float d ) { + if (level->isClientSide) return; + const int swellDir = getSwellDir(); + if ((swellDir <= 0 && d < 3) || (swellDir > 0 && d < 7)) { + if (swell == 0) { + level->playSound(this, "random.fuse", 1, 0.5f); + } + setSwellDir(1); + + if (++swell >= MAX_SWELL) { + level->explode(this, x, y, z, 2.4f); + remove(); + } + holdGround = true; + } else { + setSwellDir(-1); + if (--swell < 0) + swell = 0; + } +} + +int Creeper::getSwellDir() { + return (int) entityData.getByte(DATA_SWELL_DIR); +} + +void Creeper::setSwellDir( int dir ) { + entityData.set(DATA_SWELL_DIR, (SynchedEntityData::TypeChar) dir); +} + +//@todo +//void die(DamageSource* source) { +// super::die(source); + +// if (source.getEntity() instanceof Skeleton) { +// spawnAtLocation(Item::record_01->id + random.nextInt(2), 1); +// } +//} diff --git a/src/world/entity/monster/Creeper.h b/src/world/entity/monster/Creeper.hpp similarity index 96% rename from src/world/entity/monster/Creeper.h rename to src/world/entity/monster/Creeper.hpp index 9ef6c02..85d2aa0 100755 --- a/src/world/entity/monster/Creeper.h +++ b/src/world/entity/monster/Creeper.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.monster; -#include "Monster.h" +#include "Monster.hpp" #include class Entity; diff --git a/src/world/entity/monster/Monster.cpp b/src/world/entity/monster/Monster.cpp index fb8d867..9252d78 100755 --- a/src/world/entity/monster/Monster.cpp +++ b/src/world/entity/monster/Monster.cpp @@ -1,144 +1,144 @@ -#include "Monster.h" - -#include "../player/Player.h" -#include "../../level/Level.h" -#include "../../Difficulty.h" -#include "../../../util/Mth.h" -//#include "../../effect/MobEffect.h" - -Monster::Monster(Level* level) -: super(level), - attackDamage(2), - targetId(0), - lastHurtByMobId(0) -{ - entityRendererId = ER_HUMANOID_RENDERER; - //xpReward = Enemy.XP_REWARD_MEDIUM; -} - -void Monster::aiStep() -{ - updateAttackAnim(); - - float br = getBrightness(1); - if (br > 0.5f) { - noActionTime += 2; - } - super::aiStep(); -} - -void Monster::tick() -{ - super::tick(); - if (!level->isClientSide && level->difficulty == Difficulty::PEACEFUL) remove(); -} - -bool Monster::hurt( Entity* sourceEntity, int dmg ) -{ - if (super::hurt(sourceEntity, dmg)) { - if (sourceEntity != this) { - attackTargetId = 0; - if (sourceEntity != NULL) { - attackTargetId = sourceEntity->entityId; - if (sourceEntity->isMob()) - lastHurtByMobId = sourceEntity->entityId; - } - } - return true; - } - return false; -} - -bool Monster::canSpawn() -{ - return isDarkEnoughToSpawn() && super::canSpawn(); -} - -Entity* Monster::findAttackTarget() -{ - //Player* player = level->getNearestAttackablePlayer(this, 16); - Player* player = level->getNearestPlayer(this, 16); - //LOGI("playuer: %p\n", player); - if (player != NULL && canSee(player)) return player; - return NULL; -} - -bool Monster::isDarkEnoughToSpawn() -{ - //static int st = getTimeMs(); - //return getTimeMs() - st > 10000; - - int xt = Mth::floor(x); - int yt = Mth::floor(bb.y0); - int zt = Mth::floor(z); - if (level->getBrightness(LightLayer::Sky, xt, yt, zt) > random.nextInt(32)) return false; - - int br = level->getRawBrightness(xt, yt, zt); - - //if (level->isThundering()) { - // int tmp = level->skyDarken; - // level->skyDarken = 10; - // br = level->getRawBrightness(xt, yt, zt); - // level->skyDarken = tmp; - //} - //LOGI("br: %d\n", br); - return br <= random.nextInt(8); // was 8 -} - -bool Monster::doHurtTarget( Entity* target ) -{ - swing(); - //if (target->isMob()) setLastHurtMob(target); - //@todo - int dmg = attackDamage; - //if (hasEffect(MobEffect.damageBoost)) { - // dmg += (3 << getEffect(MobEffect.damageBoost).getAmplifier()); - //} - //if (hasEffect(MobEffect.weakness)) { - // dmg -= (2 << getEffect(MobEffect.weakness).getAmplifier()); - //} - - return target->hurt(this, dmg); -} - -void Monster::checkHurtTarget( Entity* target, float distance ) { - if (attackTime <= 0 && distance < 2.0f && target->bb.y1 > bb.y0 && target->bb.y0 < bb.y1) { - attackTime = getAttackTime(); - doHurtTarget(target); - } -} - -float Monster::getWalkTargetValue( int x, int y, int z ) -{ - return 0.5f - level->getBrightness(x, y, z); -} - -int Monster::getCreatureBaseType() const { - return MobTypes::BaseEnemy; -} - -Mob* Monster::getTarget() { - if (targetId == 0) return NULL; - return level->getMob(targetId); -} - -void Monster::setTarget(Mob* mob) { - targetId = mob? mob->entityId : 0; -} - -Mob* Monster::getLastHurtByMob() { - if (targetId == 0) return NULL; - return level->getMob(lastHurtByMobId); -} - -void Monster::setLastHurtByMob(Mob* mob) { - lastHurtByMobId = mob? mob->entityId : 0; -} - -int Monster::getAttackDamage( Entity* target ) { - return attackDamage; -} - -int Monster::getAttackTime() { - return 20; -} +#include "Monster.hpp" + +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/Difficulty.hpp" +#include "util/Mth.hpp" +//#include "world/effect/MobEffect.hpp" + +Monster::Monster(Level* level) +: super(level), + attackDamage(2), + targetId(0), + lastHurtByMobId(0) +{ + entityRendererId = ER_HUMANOID_RENDERER; + //xpReward = Enemy.XP_REWARD_MEDIUM; +} + +void Monster::aiStep() +{ + updateAttackAnim(); + + float br = getBrightness(1); + if (br > 0.5f) { + noActionTime += 2; + } + super::aiStep(); +} + +void Monster::tick() +{ + super::tick(); + if (!level->isClientSide && level->difficulty == Difficulty::PEACEFUL) remove(); +} + +bool Monster::hurt( Entity* sourceEntity, int dmg ) +{ + if (super::hurt(sourceEntity, dmg)) { + if (sourceEntity != this) { + attackTargetId = 0; + if (sourceEntity != NULL) { + attackTargetId = sourceEntity->entityId; + if (sourceEntity->isMob()) + lastHurtByMobId = sourceEntity->entityId; + } + } + return true; + } + return false; +} + +bool Monster::canSpawn() +{ + return isDarkEnoughToSpawn() && super::canSpawn(); +} + +Entity* Monster::findAttackTarget() +{ + //Player* player = level->getNearestAttackablePlayer(this, 16); + Player* player = level->getNearestPlayer(this, 16); + //LOGI("playuer: %p\n", player); + if (player != NULL && canSee(player)) return player; + return NULL; +} + +bool Monster::isDarkEnoughToSpawn() +{ + //static int st = getTimeMs(); + //return getTimeMs() - st > 10000; + + int xt = Mth::floor(x); + int yt = Mth::floor(bb.y0); + int zt = Mth::floor(z); + if (level->getBrightness(LightLayer::Sky, xt, yt, zt) > random.nextInt(32)) return false; + + int br = level->getRawBrightness(xt, yt, zt); + + //if (level->isThundering()) { + // int tmp = level->skyDarken; + // level->skyDarken = 10; + // br = level->getRawBrightness(xt, yt, zt); + // level->skyDarken = tmp; + //} + //LOGI("br: %d\n", br); + return br <= random.nextInt(8); // was 8 +} + +bool Monster::doHurtTarget( Entity* target ) +{ + swing(); + //if (target->isMob()) setLastHurtMob(target); + //@todo + int dmg = attackDamage; + //if (hasEffect(MobEffect.damageBoost)) { + // dmg += (3 << getEffect(MobEffect.damageBoost).getAmplifier()); + //} + //if (hasEffect(MobEffect.weakness)) { + // dmg -= (2 << getEffect(MobEffect.weakness).getAmplifier()); + //} + + return target->hurt(this, dmg); +} + +void Monster::checkHurtTarget( Entity* target, float distance ) { + if (attackTime <= 0 && distance < 2.0f && target->bb.y1 > bb.y0 && target->bb.y0 < bb.y1) { + attackTime = getAttackTime(); + doHurtTarget(target); + } +} + +float Monster::getWalkTargetValue( int x, int y, int z ) +{ + return 0.5f - level->getBrightness(x, y, z); +} + +int Monster::getCreatureBaseType() const { + return MobTypes::BaseEnemy; +} + +Mob* Monster::getTarget() { + if (targetId == 0) return NULL; + return level->getMob(targetId); +} + +void Monster::setTarget(Mob* mob) { + targetId = mob? mob->entityId : 0; +} + +Mob* Monster::getLastHurtByMob() { + if (targetId == 0) return NULL; + return level->getMob(lastHurtByMobId); +} + +void Monster::setLastHurtByMob(Mob* mob) { + lastHurtByMobId = mob? mob->entityId : 0; +} + +int Monster::getAttackDamage( Entity* target ) { + return attackDamage; +} + +int Monster::getAttackTime() { + return 20; +} diff --git a/src/world/entity/monster/Monster.h b/src/world/entity/monster/Monster.hpp similarity index 96% rename from src/world/entity/monster/Monster.h rename to src/world/entity/monster/Monster.hpp index 447b578..31f38d9 100755 --- a/src/world/entity/monster/Monster.h +++ b/src/world/entity/monster/Monster.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity->monster; -#include "../PathfinderMob.h" +#include "world/entity/PathfinderMob.hpp" class Level; class Entity; diff --git a/src/world/entity/monster/MonsterInclude.h b/src/world/entity/monster/MonsterInclude.h deleted file mode 100755 index 0b51310..0000000 --- a/src/world/entity/monster/MonsterInclude.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include "Creeper.h" -#include "Monster.h" -#include "Skeleton.h" -#include "Spider.h" -#include "Zombie.h" -#include "PigZombie.h" diff --git a/src/world/entity/monster/MonsterInclude.hpp b/src/world/entity/monster/MonsterInclude.hpp new file mode 100755 index 0000000..2d95092 --- /dev/null +++ b/src/world/entity/monster/MonsterInclude.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "Creeper.hpp" +#include "Monster.hpp" +#include "Skeleton.hpp" +#include "Spider.hpp" +#include "Zombie.hpp" +#include "PigZombie.hpp" diff --git a/src/world/entity/monster/PigZombie.cpp b/src/world/entity/monster/PigZombie.cpp index bb15f09..6845575 100755 --- a/src/world/entity/monster/PigZombie.cpp +++ b/src/world/entity/monster/PigZombie.cpp @@ -1,138 +1,138 @@ -#include "PigZombie.h" -#include "../../item/Item.h" -#include "../../level/Level.h" -#include "../../Difficulty.h" -#include "../Entity.h" -#include "../projectile/Arrow.h" -PigZombie::PigZombie( Level* level ) - : super(level) - , angerTime(0) - , playAngrySoundIn(0) - , weapon(Item::sword_gold) - , stunedTime(SharedConstants::TicksPerSecond * 3){ - textureName = "mob/pigzombie.png"; - runSpeed = 0.7f; - fireImmune = true; - attackDamage = 5; -} - -bool PigZombie::useNewAi() { - return false; -} - -void PigZombie::tick() { - //runSpeed = attackTargetId != 0 ? 0.95f : 0.5f; - if(stunedTime > 0) - stunedTime--; - if(playAngrySoundIn > 0) { - if(--playAngrySoundIn == 0) { - level->playSound(x, y, z, "mob.zombiepig.zpigangry", getSoundVolume() * 2, ((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f) * 1.8f); - } - } - super::tick(); -} - -std::string PigZombie::getTexture() { - return "mob/pigzombie.png"; -} - -bool PigZombie::canSpawn() { - return level->difficulty > Difficulty::PEACEFUL && level->isUnobstructed(bb) && level->getCubes(this, bb).empty(); -} - -void PigZombie::addAdditonalSaveData( CompoundTag* entityTag ) { - super::addAdditonalSaveData(entityTag); - entityTag->putShort("Anger", (short)angerTime); -} - -void PigZombie::readAdditionalSaveData( CompoundTag* tag ) { - super::readAdditionalSaveData(tag); - angerTime = tag->getShort("Anger"); -} - -Entity* PigZombie::findAttackTarget() { - if(stunedTime != 0) - return NULL; - if(angerTime == 0) { - Entity* potentialTarget = super::findAttackTarget(); - if(potentialTarget != NULL && potentialTarget->distanceTo(x, y, z) < 5) { - return potentialTarget; - } - return NULL; - } - return super::findAttackTarget(); -} - -bool PigZombie::hurt( Entity* sourceEntity, int dmg ) { - Entity* attacker = NULL; - if(sourceEntity != NULL) { - if(sourceEntity->isPlayer()) { - attacker = sourceEntity; - } - else if(sourceEntity->isEntityType(EntityTypes::IdArrow)) { - Arrow* arrow = (Arrow*)sourceEntity; - if(arrow->ownerId != 0) { - attacker = level->getEntity(arrow->ownerId); - if(!attacker->isPlayer()) - attacker = NULL; - } - } - } - - if(attacker != NULL) { - EntityList nearby = level->getEntities(this, bb.grow(12, 12, 12)); - for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { - if((*it)->isEntityType(MobTypes::PigZombie)) { - PigZombie* pigZombie = (PigZombie*)(*it); - pigZombie->alert(sourceEntity); - } - } - } - return super::hurt(sourceEntity, dmg); -} - -void PigZombie::alert( Entity* target ) { - attackTargetId = target->entityId; - angerTime = 20 * 20 * random.nextInt(20 * 20); - playAngrySoundIn = random.nextInt(20 * 2); -} - -const char* PigZombie::getAmbientSound() { - return "mob.zombiepig.zpig"; -} - -std::string PigZombie::getHurtSound() { - return "mob.zombiepig.zpighurt"; -} - -std::string PigZombie::getDeathSound() { - return "mob.zombiepig.zpigdeath"; -} - -void PigZombie::dropDeathLoot() { - int count = random.nextInt(2); - for(int i = 0; i < count; ++i) { - // We really should spawn gold nuggets instead of ingots. - spawnAtLocation(Item::goldIngot->id, 1); - } -} - -bool PigZombie::interact( Player* player ) { - return false; -} - -int PigZombie::getDeathLoot() { - return 0; -} - -ItemInstance* PigZombie::getCarriedItem() { - return &weapon; -} - -int PigZombie::getEntityTypeId() const { - return MobTypes::PigZombie; -} - -int PigZombie::getAttackTime() { - return 40; -} +#include "PigZombie.hpp" +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" +#include "world/Difficulty.hpp" +#include "world/entity/Entity.hpp" +#include "world/entity/projectile/Arrow.hpp" +PigZombie::PigZombie( Level* level ) + : super(level) + , angerTime(0) + , playAngrySoundIn(0) + , weapon(Item::sword_gold) + , stunedTime(SharedConstants::TicksPerSecond * 3){ + textureName = "mob/pigzombie.png"; + runSpeed = 0.7f; + fireImmune = true; + attackDamage = 5; +} + +bool PigZombie::useNewAi() { + return false; +} + +void PigZombie::tick() { + //runSpeed = attackTargetId != 0 ? 0.95f : 0.5f; + if(stunedTime > 0) + stunedTime--; + if(playAngrySoundIn > 0) { + if(--playAngrySoundIn == 0) { + level->playSound(x, y, z, "mob.zombiepig.zpigangry", getSoundVolume() * 2, ((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f) * 1.8f); + } + } + super::tick(); +} + +std::string PigZombie::getTexture() { + return "mob/pigzombie.png"; +} + +bool PigZombie::canSpawn() { + return level->difficulty > Difficulty::PEACEFUL && level->isUnobstructed(bb) && level->getCubes(this, bb).empty(); +} + +void PigZombie::addAdditonalSaveData( CompoundTag* entityTag ) { + super::addAdditonalSaveData(entityTag); + entityTag->putShort("Anger", (short)angerTime); +} + +void PigZombie::readAdditionalSaveData( CompoundTag* tag ) { + super::readAdditionalSaveData(tag); + angerTime = tag->getShort("Anger"); +} + +Entity* PigZombie::findAttackTarget() { + if(stunedTime != 0) + return NULL; + if(angerTime == 0) { + Entity* potentialTarget = super::findAttackTarget(); + if(potentialTarget != NULL && potentialTarget->distanceTo(x, y, z) < 5) { + return potentialTarget; + } + return NULL; + } + return super::findAttackTarget(); +} + +bool PigZombie::hurt( Entity* sourceEntity, int dmg ) { + Entity* attacker = NULL; + if(sourceEntity != NULL) { + if(sourceEntity->isPlayer()) { + attacker = sourceEntity; + } + else if(sourceEntity->isEntityType(EntityTypes::IdArrow)) { + Arrow* arrow = (Arrow*)sourceEntity; + if(arrow->ownerId != 0) { + attacker = level->getEntity(arrow->ownerId); + if(!attacker->isPlayer()) + attacker = NULL; + } + } + } + + if(attacker != NULL) { + EntityList nearby = level->getEntities(this, bb.grow(12, 12, 12)); + for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { + if((*it)->isEntityType(MobTypes::PigZombie)) { + PigZombie* pigZombie = (PigZombie*)(*it); + pigZombie->alert(sourceEntity); + } + } + } + return super::hurt(sourceEntity, dmg); +} + +void PigZombie::alert( Entity* target ) { + attackTargetId = target->entityId; + angerTime = 20 * 20 * random.nextInt(20 * 20); + playAngrySoundIn = random.nextInt(20 * 2); +} + +const char* PigZombie::getAmbientSound() { + return "mob.zombiepig.zpig"; +} + +std::string PigZombie::getHurtSound() { + return "mob.zombiepig.zpighurt"; +} + +std::string PigZombie::getDeathSound() { + return "mob.zombiepig.zpigdeath"; +} + +void PigZombie::dropDeathLoot() { + int count = random.nextInt(2); + for(int i = 0; i < count; ++i) { + // We really should spawn gold nuggets instead of ingots. + spawnAtLocation(Item::goldIngot->id, 1); + } +} + +bool PigZombie::interact( Player* player ) { + return false; +} + +int PigZombie::getDeathLoot() { + return 0; +} + +ItemInstance* PigZombie::getCarriedItem() { + return &weapon; +} + +int PigZombie::getEntityTypeId() const { + return MobTypes::PigZombie; +} + +int PigZombie::getAttackTime() { + return 40; +} diff --git a/src/world/entity/monster/PigZombie.h b/src/world/entity/monster/PigZombie.hpp similarity index 97% rename from src/world/entity/monster/PigZombie.h rename to src/world/entity/monster/PigZombie.hpp index 4748ccd..9b3710e 100755 --- a/src/world/entity/monster/PigZombie.h +++ b/src/world/entity/monster/PigZombie.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Zombie.h" +#include "Zombie.hpp" class ItemInstance; class PigZombie : public Zombie { typedef Zombie super; diff --git a/src/world/entity/monster/Skeleton.cpp b/src/world/entity/monster/Skeleton.cpp index 497944c..a87af68 100755 --- a/src/world/entity/monster/Skeleton.cpp +++ b/src/world/entity/monster/Skeleton.cpp @@ -1,107 +1,107 @@ -#include "Skeleton.h" -#include "../projectile/Arrow.h" - -Skeleton::Skeleton( Level* level ) -: super(level), - bow(Item::bow, 1), - fireCheckTick(0) -{ - entityRendererId = ER_SKELETON_RENDERER; - this->textureName = "mob/skeleton.png"; -} - -int Skeleton::getMaxHealth() { - return 10; // 15 -} - -void Skeleton::aiStep() { - if ((++fireCheckTick & 1) && level->isDay() && !level->isClientSide) { - float br = getBrightness(1); - if (br > 0.5f) { - if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random.nextFloat() * 3.5f < (br - 0.4f)) { - hurt(NULL, 1); - - for (int i = 0; i < 5; ++i) { - float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); - } - //setOnFire(8); //@todo - } - } - } - - super::aiStep(); -} - -int Skeleton::getDeathLoot() { - return Item::arrow->id; -} - -ItemInstance* Skeleton::getCarriedItem() { - return &bow; -} - -int Skeleton::getEntityTypeId() const { - return MobTypes::Skeleton; -} - -const char* Skeleton::getAmbientSound() { - return "mob.skeleton"; -} - -std::string Skeleton::getHurtSound() { - return "mob.skeletonhurt"; -} - -std::string Skeleton::getDeathSound() { - return "mob.skeletonhurt"; -} - -void Skeleton::checkHurtTarget( Entity* target, float d ) { - if (d < 10) { - float xd = target->x - x; - float zd = target->z - z; - - if (attackTime == 0) { - Arrow* arrow = new Arrow(level, this, 1); - // arrow.y += 1.4f; - - float yd = (target->y + target->getHeadHeight() - 0.7f) - arrow->y; - - float yo = Mth::sqrt(xd * xd + zd * zd) * 0.2f; - - level->playSound(this, "random.bow", 1.0f, 1 / (random.nextFloat() * 0.4f + 0.8f)); - level->addEntity(arrow); - - arrow->shoot(xd, yd + yo, zd, 1.60f, 32); - attackTime = SharedConstants::TicksPerSecond * 3; - } - yRot = (float) (std::atan2(zd, xd) * Mth::RADDEG) - 90; - - holdGround = true; - } -} - -void Skeleton::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) { - // drop some arrows - int count = random.nextInt(3 /*+ playerBonusLevel*/); - for (int i = 0; i < count; i++) { - spawnAtLocation(Item::arrow->id, 1); - } - // and some bones - count = random.nextInt(3 /*+ playerBonusLevel*/); - for (int i = 0; i < count; i++) { - spawnAtLocation(Item::bone->id, 1); - } -} - -int Skeleton::getUseDuration() { - return attackTime; -} - -/*@Override*/ -// MobType getMobType() { -// return MobType.UNDEAD; -// } +#include "Skeleton.hpp" +#include "world/entity/projectile/Arrow.hpp" + +Skeleton::Skeleton( Level* level ) +: super(level), + bow(Item::bow, 1), + fireCheckTick(0) +{ + entityRendererId = ER_SKELETON_RENDERER; + this->textureName = "mob/skeleton.png"; +} + +int Skeleton::getMaxHealth() { + return 10; // 15 +} + +void Skeleton::aiStep() { + if ((++fireCheckTick & 1) && level->isDay() && !level->isClientSide) { + float br = getBrightness(1); + if (br > 0.5f) { + if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random.nextFloat() * 3.5f < (br - 0.4f)) { + hurt(NULL, 1); + + for (int i = 0; i < 5; ++i) { + float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); + } + //setOnFire(8); //@todo + } + } + } + + super::aiStep(); +} + +int Skeleton::getDeathLoot() { + return Item::arrow->id; +} + +ItemInstance* Skeleton::getCarriedItem() { + return &bow; +} + +int Skeleton::getEntityTypeId() const { + return MobTypes::Skeleton; +} + +const char* Skeleton::getAmbientSound() { + return "mob.skeleton"; +} + +std::string Skeleton::getHurtSound() { + return "mob.skeletonhurt"; +} + +std::string Skeleton::getDeathSound() { + return "mob.skeletonhurt"; +} + +void Skeleton::checkHurtTarget( Entity* target, float d ) { + if (d < 10) { + float xd = target->x - x; + float zd = target->z - z; + + if (attackTime == 0) { + Arrow* arrow = new Arrow(level, this, 1); + // arrow.y += 1.4f; + + float yd = (target->y + target->getHeadHeight() - 0.7f) - arrow->y; + + float yo = Mth::sqrt(xd * xd + zd * zd) * 0.2f; + + level->playSound(this, "random.bow", 1.0f, 1 / (random.nextFloat() * 0.4f + 0.8f)); + level->addEntity(arrow); + + arrow->shoot(xd, yd + yo, zd, 1.60f, 32); + attackTime = SharedConstants::TicksPerSecond * 3; + } + yRot = (float) (std::atan2(zd, xd) * Mth::RADDEG) - 90; + + holdGround = true; + } +} + +void Skeleton::dropDeathLoot( /*bool wasKilledByPlayer, int playerBonusLevel*/ ) { + // drop some arrows + int count = random.nextInt(3 /*+ playerBonusLevel*/); + for (int i = 0; i < count; i++) { + spawnAtLocation(Item::arrow->id, 1); + } + // and some bones + count = random.nextInt(3 /*+ playerBonusLevel*/); + for (int i = 0; i < count; i++) { + spawnAtLocation(Item::bone->id, 1); + } +} + +int Skeleton::getUseDuration() { + return attackTime; +} + +/*@Override*/ +// MobType getMobType() { +// return MobType.UNDEAD; +// } diff --git a/src/world/entity/monster/Skeleton.h b/src/world/entity/monster/Skeleton.hpp similarity index 91% rename from src/world/entity/monster/Skeleton.h rename to src/world/entity/monster/Skeleton.hpp index f54d54f..1282f21 100755 --- a/src/world/entity/monster/Skeleton.h +++ b/src/world/entity/monster/Skeleton.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.entity->monster; -#include "Monster.h" +#include "Monster.hpp" #include -#include "../../item/ItemInstance.h" +#include "world/item/ItemInstance.hpp" class Level; class Entity; diff --git a/src/world/entity/monster/Spider.cpp b/src/world/entity/monster/Spider.cpp index b9b774c..758e534 100755 --- a/src/world/entity/monster/Spider.cpp +++ b/src/world/entity/monster/Spider.cpp @@ -1,137 +1,137 @@ -#include "Spider.h" -#include "../../item/Item.h" -#include "../../level/Level.h" -#include "../../../util/Mth.h" - -Spider::Spider( Level* level ) -: super(level), - fireCheckTick(0) -{ - entityRendererId = ER_SPIDER_RENDERER; - this->textureName = "mob/spider.png"; - - this->setSize(1.4f, 0.9f); - runSpeed = 0.5f; - - entityData.define(DATA_FLAGS_ID, (DataFlagIdType) 0); -} - -void Spider::aiStep() { - super::aiStep(); -} - -void Spider::tick() { - super::tick(); - - if (!level->isClientSide) { - // this is to synchronize the spiders' climb state - // in multiplayer (to stop them from "flashing") - setClimbing(horizontalCollision); - } -} - -int Spider::getMaxHealth() { - return 8; // 12 -} - -bool Spider::onLadder() { - return isClimbing(); -} - -void Spider::makeStuckInWeb() { - // do nothing - spiders don't get stuck in web -} - -float Spider::getModelScale() { - return 1.0f; -} - -bool Spider::isClimbing() { - return entityData.getFlag(DATA_FLAGS_ID, 0); -} - -void Spider::setClimbing( bool value ) { - if (value) - return entityData.setFlag(DATA_FLAGS_ID, 0); - else - return entityData.clearFlag(DATA_FLAGS_ID, 0); -} - -int Spider::getEntityTypeId() const { - return MobTypes::Spider; -} - -bool Spider::makeStepSound() { - return false; -} - -Entity* Spider::findAttackTarget() { - float br = getBrightness(1); - if (br < 0.5f) { - return level->getNearestPlayer(this, 16); - } - return NULL; -} - -const char* Spider::getAmbientSound() { - return "mob.spider"; -} - -std::string Spider::getHurtSound() { - return "mob.spider"; -} - -std::string Spider::getDeathSound() { - return "mob.spiderdeath"; -} - -void Spider::checkHurtTarget( Entity* target, float d ) { - float br = getBrightness(1); - if (br > 0.5f && random.nextInt(100) == 0) { - attackTargetId = 0; - return; - } - - if (d > 2 && d < 6 && random.nextInt(10) == 0) { - if (onGround) { - float xdd = target->x - x; - float zdd = target->z - z; - float dd = Mth::sqrt(xdd * xdd + zdd * zdd); - xd = (xdd / dd * 0.5f) * 0.8f + xd * 0.2f; - zd = (zdd / dd * 0.5f) * 0.8f + zd * 0.2f; - yd = 0.4f; - } - } else { - super::checkHurtTarget(target, d); - } -} - -int Spider::getDeathLoot() { - return Item::string->id; -} - -//void dropDeathLoot(/*bool wasKilledByPlayer, int playerBonusLevel*/) { -// super::dropDeathLoot(/*wasKilledByPlayer, playerBonusLevel*/); - -//// if (wasKilledByPlayer && (random.nextInt(3) == 0 || random.nextInt(1 + playerBonusLevel) > 0)) { -//// spawnAtLocation(Item::spiderEye->id, 1); -//// } -//} - -//float getRideHeight() { -// return bbHeight * .75f - 0.5f; -//} - -/*@Override*/ -// MobType getMobType() { -// return MobType.ARTHROPOD; -// } - -/*@Override*/ //@todo -// bool canBeAffected(MobEffectInstance newEffect) { -// if (newEffect.getId() == MobEffect.poison.id) { -// return false; -// } -// return super::canBeAffected(newEffect); -// } -// +#include "Spider.hpp" +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" +#include "util/Mth.hpp" + +Spider::Spider( Level* level ) +: super(level), + fireCheckTick(0) +{ + entityRendererId = ER_SPIDER_RENDERER; + this->textureName = "mob/spider.png"; + + this->setSize(1.4f, 0.9f); + runSpeed = 0.5f; + + entityData.define(DATA_FLAGS_ID, (DataFlagIdType) 0); +} + +void Spider::aiStep() { + super::aiStep(); +} + +void Spider::tick() { + super::tick(); + + if (!level->isClientSide) { + // this is to synchronize the spiders' climb state + // in multiplayer (to stop them from "flashing") + setClimbing(horizontalCollision); + } +} + +int Spider::getMaxHealth() { + return 8; // 12 +} + +bool Spider::onLadder() { + return isClimbing(); +} + +void Spider::makeStuckInWeb() { + // do nothing - spiders don't get stuck in web +} + +float Spider::getModelScale() { + return 1.0f; +} + +bool Spider::isClimbing() { + return entityData.getFlag(DATA_FLAGS_ID, 0); +} + +void Spider::setClimbing( bool value ) { + if (value) + return entityData.setFlag(DATA_FLAGS_ID, 0); + else + return entityData.clearFlag(DATA_FLAGS_ID, 0); +} + +int Spider::getEntityTypeId() const { + return MobTypes::Spider; +} + +bool Spider::makeStepSound() { + return false; +} + +Entity* Spider::findAttackTarget() { + float br = getBrightness(1); + if (br < 0.5f) { + return level->getNearestPlayer(this, 16); + } + return NULL; +} + +const char* Spider::getAmbientSound() { + return "mob.spider"; +} + +std::string Spider::getHurtSound() { + return "mob.spider"; +} + +std::string Spider::getDeathSound() { + return "mob.spiderdeath"; +} + +void Spider::checkHurtTarget( Entity* target, float d ) { + float br = getBrightness(1); + if (br > 0.5f && random.nextInt(100) == 0) { + attackTargetId = 0; + return; + } + + if (d > 2 && d < 6 && random.nextInt(10) == 0) { + if (onGround) { + float xdd = target->x - x; + float zdd = target->z - z; + float dd = Mth::sqrt(xdd * xdd + zdd * zdd); + xd = (xdd / dd * 0.5f) * 0.8f + xd * 0.2f; + zd = (zdd / dd * 0.5f) * 0.8f + zd * 0.2f; + yd = 0.4f; + } + } else { + super::checkHurtTarget(target, d); + } +} + +int Spider::getDeathLoot() { + return Item::string->id; +} + +//void dropDeathLoot(/*bool wasKilledByPlayer, int playerBonusLevel*/) { +// super::dropDeathLoot(/*wasKilledByPlayer, playerBonusLevel*/); + +//// if (wasKilledByPlayer && (random.nextInt(3) == 0 || random.nextInt(1 + playerBonusLevel) > 0)) { +//// spawnAtLocation(Item::spiderEye->id, 1); +//// } +//} + +//float getRideHeight() { +// return bbHeight * .75f - 0.5f; +//} + +/*@Override*/ +// MobType getMobType() { +// return MobType.ARTHROPOD; +// } + +/*@Override*/ //@todo +// bool canBeAffected(MobEffectInstance newEffect) { +// if (newEffect.getId() == MobEffect.poison.id) { +// return false; +// } +// return super::canBeAffected(newEffect); +// } +// diff --git a/src/world/entity/monster/Spider.h b/src/world/entity/monster/Spider.hpp similarity index 97% rename from src/world/entity/monster/Spider.h rename to src/world/entity/monster/Spider.hpp index 4a94913..20f6be9 100755 --- a/src/world/entity/monster/Spider.h +++ b/src/world/entity/monster/Spider.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity->monster; -#include "Monster.h" +#include "Monster.hpp" #include class Level; diff --git a/src/world/entity/monster/Zombie.cpp b/src/world/entity/monster/Zombie.cpp index 5846375..83d2458 100755 --- a/src/world/entity/monster/Zombie.cpp +++ b/src/world/entity/monster/Zombie.cpp @@ -1,129 +1,129 @@ -#include "Zombie.h" - -#include "../../item/Item.h" -#include "../../level/Level.h" -#include "../../../util/Mth.h" -//#include "../MobType.h" -#include "../ai/goal/GoalSelector.h" -#include "../ai/control/JumpControl.h" -#include "../ai/goal/RandomStrollGoal.h" -#include "../ai/goal/MeleeAttackGoal.h" -#include "../ai/goal/target/NearestAttackableTargetGoal.h" -#include "../ai/goal/target/HurtByTargetGoal.h" -#include "../ai/goal/BreakDoorGoal.h" - -Zombie::Zombie( Level* level ) -: super(level), - fireCheckTick(0), - _useNewAi(false) -{ - entityRendererId = ER_ZOMBIE_RENDERER; - this->textureName = "mob/zombie.png"; - //pathfinderMask |= CAN_OPEN_DOORS; - //navigation->canOpenDoors = true; - - runSpeed = 0.5f; - attackDamage = 4; - - targetSelector = new GoalSelector(); - targetSelector->addGoal(1, new HurtByTargetGoal(this, false)); - targetSelector->addGoal(2, new NearestAttackableTargetGoal(this, 1, 16, 0, true)); - - goalSelector = new GoalSelector(); - //goalSelector->addGoal(1, new BreakDoorGoal(this)); - goalSelector->addGoal(2, new MeleeAttackGoal(this, runSpeed, false, 0)); - goalSelector->addGoal(7, new RandomStrollGoal(this, runSpeed) ); - - moveControl = new MoveControl(this); - jumpControl = new JumpControl(this); -} - -Zombie::~Zombie() { - delete goalSelector; - delete targetSelector; - - delete moveControl; - delete jumpControl; -} - -int Zombie::getMaxHealth() { - return 12; // 16 -} - -void Zombie::aiStep() { - if ((++fireCheckTick & 1) && level->isDay() && !level->isClientSide) { - float br = getBrightness(1); - if (br > 0.5f) { - if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random.nextFloat() * 3.5f < (br - 0.4f)) { - hurt(NULL, 1); - - for (int i = 0; i < 5; ++i) { - float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; - level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); - } - //setOnFire(8); //@todo - } - } - } - - super::aiStep(); -} - -int Zombie::getEntityTypeId() const { - return MobTypes::Zombie; -} - -void Zombie::setUseNewAi( bool use ) { - _useNewAi = use; -} - -int Zombie::getArmorValue() { - int armor = super::getArmorValue() + 2; - if (armor > 20) armor = 20; - return armor; -} - -const char* Zombie::getAmbientSound() { - return "mob.zombie"; -} - -std::string Zombie::getHurtSound() { - return "mob.zombiehurt"; -} - -std::string Zombie::getDeathSound() { - return "mob.zombiedeath"; -} - -int Zombie::getDeathLoot() { - return 0; //@todo - //return Item::rotten_flesh->id; -} - -bool Zombie::useNewAi() { - return _useNewAi; -} - -void Zombie::die( Entity* source ) { - super::die(source); - if(!level->isClientSide) { - if(random.nextInt(4) == 0) { - spawnAtLocation(Item::feather->id, random.nextInt(1) + 1); - } - } -} - -int Zombie::getAttackDamage( Entity* target ) { - ItemInstance* weapon = getCarriedItem(); - int damage = attackDamage; - if(weapon != NULL) damage += weapon->getAttackDamage(this); - return damage; -} - -/*@Override*/ //@todo? -//MobType getMobType() { -// return MobType::UNDEAD; -//} - +#include "Zombie.hpp" + +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" +#include "util/Mth.hpp" +//#include "world/entity/MobType.hpp" +#include "world/entity/ai/goal/GoalSelector.hpp" +#include "world/entity/ai/control/JumpControl.hpp" +#include "world/entity/ai/goal/RandomStrollGoal.hpp" +#include "world/entity/ai/goal/MeleeAttackGoal.hpp" +#include "world/entity/ai/goal/target/NearestAttackableTargetGoal.hpp" +#include "world/entity/ai/goal/target/HurtByTargetGoal.hpp" +#include "world/entity/ai/goal/BreakDoorGoal.hpp" + +Zombie::Zombie( Level* level ) +: super(level), + fireCheckTick(0), + _useNewAi(false) +{ + entityRendererId = ER_ZOMBIE_RENDERER; + this->textureName = "mob/zombie.png"; + //pathfinderMask |= CAN_OPEN_DOORS; + //navigation->canOpenDoors = true; + + runSpeed = 0.5f; + attackDamage = 4; + + targetSelector = new GoalSelector(); + targetSelector->addGoal(1, new HurtByTargetGoal(this, false)); + targetSelector->addGoal(2, new NearestAttackableTargetGoal(this, 1, 16, 0, true)); + + goalSelector = new GoalSelector(); + //goalSelector->addGoal(1, new BreakDoorGoal(this)); + goalSelector->addGoal(2, new MeleeAttackGoal(this, runSpeed, false, 0)); + goalSelector->addGoal(7, new RandomStrollGoal(this, runSpeed) ); + + moveControl = new MoveControl(this); + jumpControl = new JumpControl(this); +} + +Zombie::~Zombie() { + delete goalSelector; + delete targetSelector; + + delete moveControl; + delete jumpControl; +} + +int Zombie::getMaxHealth() { + return 12; // 16 +} + +void Zombie::aiStep() { + if ((++fireCheckTick & 1) && level->isDay() && !level->isClientSide) { + float br = getBrightness(1); + if (br > 0.5f) { + if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random.nextFloat() * 3.5f < (br - 0.4f)) { + hurt(NULL, 1); + + for (int i = 0; i < 5; ++i) { + float xa = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + float ya = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + float za = (2.0f * random.nextFloat() - 1.0f) * (2.0f * random.nextFloat() - 1.0f) * 0.02f; + level->addParticle(PARTICLETYPE(explode), x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); + } + //setOnFire(8); //@todo + } + } + } + + super::aiStep(); +} + +int Zombie::getEntityTypeId() const { + return MobTypes::Zombie; +} + +void Zombie::setUseNewAi( bool use ) { + _useNewAi = use; +} + +int Zombie::getArmorValue() { + int armor = super::getArmorValue() + 2; + if (armor > 20) armor = 20; + return armor; +} + +const char* Zombie::getAmbientSound() { + return "mob.zombie"; +} + +std::string Zombie::getHurtSound() { + return "mob.zombiehurt"; +} + +std::string Zombie::getDeathSound() { + return "mob.zombiedeath"; +} + +int Zombie::getDeathLoot() { + return 0; //@todo + //return Item::rotten_flesh->id; +} + +bool Zombie::useNewAi() { + return _useNewAi; +} + +void Zombie::die( Entity* source ) { + super::die(source); + if(!level->isClientSide) { + if(random.nextInt(4) == 0) { + spawnAtLocation(Item::feather->id, random.nextInt(1) + 1); + } + } +} + +int Zombie::getAttackDamage( Entity* target ) { + ItemInstance* weapon = getCarriedItem(); + int damage = attackDamage; + if(weapon != NULL) damage += weapon->getAttackDamage(this); + return damage; +} + +/*@Override*/ //@todo? +//MobType getMobType() { +// return MobType::UNDEAD; +//} + diff --git a/src/world/entity/monster/Zombie.h b/src/world/entity/monster/Zombie.hpp similarity index 96% rename from src/world/entity/monster/Zombie.h rename to src/world/entity/monster/Zombie.hpp index f43b2f2..b46e985 100755 --- a/src/world/entity/monster/Zombie.h +++ b/src/world/entity/monster/Zombie.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity->monster; -#include "Monster.h" +#include "Monster.hpp" #include class Level; diff --git a/src/world/entity/player/Abilities.h b/src/world/entity/player/Abilities.hpp similarity index 96% rename from src/world/entity/player/Abilities.h rename to src/world/entity/player/Abilities.hpp index 13b5c0a..0ff0c1e 100755 --- a/src/world/entity/player/Abilities.h +++ b/src/world/entity/player/Abilities.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.player; -#include "../../../nbt/CompoundTag.h" +#include "nbt/CompoundTag.hpp" class Abilities { diff --git a/src/world/entity/player/Inventory.cpp b/src/world/entity/player/Inventory.cpp index 5a46535..54f8341 100755 --- a/src/world/entity/player/Inventory.cpp +++ b/src/world/entity/player/Inventory.cpp @@ -1,359 +1,359 @@ -#include "Inventory.h" -#include "../../level/material/Material.h" -#include "../../level/tile/QuartzBlockTile.h" -#include "../../level/tile/TreeTile.h" -#include "../../level/tile/StoneSlabTile.h" -#include "../../item/DyePowderItem.h" -#include "../../item/crafting/Recipe.h" -#include "../../item/CoalItem.h" -#include "../../level/tile/SandStoneTile.h" - -Inventory::Inventory( Player* player, bool creativeMode ) -: super( 36 + Inventory::MAX_SELECTION_SIZE, - MAX_SELECTION_SIZE, - ContainerType::INVENTORY, - creativeMode), - player(player), - selected(0) -{ - setupDefault(); - compressLinkedSlotList(0); -} - -Inventory::~Inventory() { -} - -ItemInstance* Inventory::getSelected() { - return getLinked(selected); -} - -void Inventory::selectSlot( int slot ) { - if (slot < MAX_SELECTION_SIZE && slot >= 0) - selected = slot; -} - -bool Inventory::moveToSelectedSlot( int inventorySlot, bool propagate ) { - return linkSlot(selected, inventorySlot, propagate); -} - -int Inventory::getSelectionSize() { - return MAX_SELECTION_SIZE; -} - -void Inventory::setupDefault() { - clearInventory(); - int Sel[MAX_SELECTION_SIZE] = {0}; - -#ifdef DEMO_MODE - if (_isCreative) { - Sel[0] = addItem(new ItemInstance(Item::shovel_stone)); - addItem(new ItemInstance(Item::pickAxe_stone)); - addItem(new ItemInstance(Item::hatchet_stone)); - addItem(new ItemInstance((Item*)Item::shears)); - addItem(new ItemInstance(Tile::ladder)); - Sel[3] = addItem(new ItemInstance(Tile::torch)); - addItem(new ItemInstance(Item::door_wood)); - - Sel[4] = addItem(new ItemInstance(Tile::stoneBrick)); - Sel[5] = addItem(new ItemInstance(Tile::wood)); - Sel[2] = addItem(new ItemInstance(Tile::redBrick)); - Sel[1] = addItem(new ItemInstance(Tile::dirt)); - addItem(new ItemInstance(Tile::sandStone)); - addItem(new ItemInstance(Tile::gravel)); - addItem(new ItemInstance(Tile::rock)); - addItem(new ItemInstance(Tile::sand)); - //addItem(new ItemInstance(Tile::clay)); - - addItem(new ItemInstance(Tile::cloth, 1, 15)); - addItem(new ItemInstance(Tile::cloth, 1, 14)); - addItem(new ItemInstance(Tile::cloth, 1, 13)); - Sel[7] = addItem(new ItemInstance(Tile::cloth, 1, 12)); - addItem(new ItemInstance(Tile::cloth, 1, 11)); - addItem(new ItemInstance(Tile::cloth, 1, 10)); - Sel[8] = addItem(new ItemInstance(Tile::cloth, 1, 9)); - addItem(new ItemInstance(Tile::cloth, 1, 8)); - Sel[6] = addItem(new ItemInstance(Tile::glass)); - addItem(new ItemInstance(Tile::thinGlass)); - addItem(new ItemInstance(Tile::stairs_stone)); - addItem(new ItemInstance(Tile::bookshelf)); - addItem(new ItemInstance(Tile::workBench)); - addItem(new ItemInstance(Tile::chest)); - addItem(new ItemInstance(Tile::furnace)); - - addItem(new ItemInstance(((Tile*)Tile::flower))); - addItem(new ItemInstance(Tile::cactus)); - - // - // Those below are inactive due to demo - // - addItem(new ItemInstance(Item::sword_stone)); - addItem(new ItemInstance(Tile::treeTrunk, 1, 0)); - addItem(new ItemInstance(Tile::treeTrunk, 1, 1)); - addItem(new ItemInstance(Tile::treeTrunk, 1, 2)); - addItem(new ItemInstance(Tile::fence)); - addItem(new ItemInstance(Tile::fenceGate)); - addItem(new ItemInstance(Item::reeds)); - addItem(new ItemInstance(((Tile*)Tile::rose))); - addItem(new ItemInstance(((Tile*)Tile::mushroom2))); - addItem(new ItemInstance(((Tile*)Tile::mushroom1))); - addItem(new ItemInstance(Tile::cloth, 1, 7)); - addItem(new ItemInstance(Tile::cloth, 1, 6)); - addItem(new ItemInstance(Tile::cloth, 1, 5)); - addItem(new ItemInstance(Tile::cloth, 1, 4)); - addItem(new ItemInstance(Tile::cloth, 1, 3)); - addItem(new ItemInstance(Tile::stairs_wood)); - addItem(new ItemInstance(Tile::goldBlock)); - addItem(new ItemInstance(Tile::ironBlock)); - addItem(new ItemInstance(Tile::emeraldBlock)); - addItem(new ItemInstance(Tile::lapisBlock)); - addItem(new ItemInstance(Tile::obsidian)); - addItem(new ItemInstance((Tile*)Tile::leaves, 1, 0)); - addItem(new ItemInstance((Tile*)Tile::leaves, 1, 1)); - addItem(new ItemInstance((Tile*)Tile::leaves, 1, 2)); - addItem(new ItemInstance(Tile::stoneSlabHalf)); - } else { -#if defined(WIN32) - // Survival - addItem(new ItemInstance((Item*)Item::shears)); - addItem(new ItemInstance(Tile::redBrick)); - addItem(new ItemInstance(Tile::glass)); -#endif - } -#else - if (_isCreative) { - // Blocks - Sel[1] = addItem(new ItemInstance(Tile::stoneBrick)); - addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 0)); - addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 1)); - addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 2)); - addItem(new ItemInstance(Tile::mossStone)); - Sel[5] = addItem(new ItemInstance(Tile::wood)); - Sel[2] = addItem(new ItemInstance(Tile::redBrick)); - -#ifdef RPI - Sel[3] = addItem(new ItemInstance(Tile::rock)); -#else - Sel[0] = addItem(new ItemInstance(Tile::rock)); -#endif - Sel[4] = addItem(new ItemInstance(Tile::dirt)); - addItem(new ItemInstance(Tile::grass)); - addItem(new ItemInstance(Tile::clay)); - addItem(new ItemInstance(Tile::sandStone, 1, 0)); - addItem(new ItemInstance(Tile::sandStone, 1, 1)); - addItem(new ItemInstance(Tile::sandStone, 1, 2)); - addItem(new ItemInstance(Tile::sand)); - addItem(new ItemInstance(Tile::gravel)); - - Sel[7] = addItem(new ItemInstance(Tile::treeTrunk, 1, 0)); - addItem(new ItemInstance(Tile::treeTrunk, 1, 1)); - addItem(new ItemInstance(Tile::treeTrunk, 1, 2)); - addItem(new ItemInstance(Tile::netherBrick)); - addItem(new ItemInstance(Tile::netherrack)); - addItem(new ItemInstance(Tile::stairs_stone)); - addItem(new ItemInstance(Tile::stairs_wood)); - Sel[6] = addItem(new ItemInstance(Tile::stairs_brick)); - addItem(new ItemInstance(Tile::stairs_sandStone)); - addItem(new ItemInstance(Tile::stairs_stoneBrickSmooth)); - addItem(new ItemInstance(Tile::stairs_netherBricks)); - addItem(new ItemInstance(Tile::stairs_quartz)); - addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::STONE_SLAB)); - addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::COBBLESTONE_SLAB)); - addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::WOOD_SLAB)); - addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::BRICK_SLAB)); - addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::SAND_SLAB)); - addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::SMOOTHBRICK_SLAB)); - - addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_DEFAULT)); - addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_LINES)); - addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_CHISELED)); - - - - // Ores - addItem(new ItemInstance(Tile::coalOre)); - addItem(new ItemInstance(Tile::ironOre)); - addItem(new ItemInstance(Tile::goldOre)); - addItem(new ItemInstance(Tile::emeraldOre)); - addItem(new ItemInstance(Tile::lapisOre)); - addItem(new ItemInstance(Tile::redStoneOre)); - - addItem(new ItemInstance(Tile::goldBlock)); - addItem(new ItemInstance(Tile::ironBlock)); - addItem(new ItemInstance(Tile::emeraldBlock)); - addItem(new ItemInstance(Tile::lapisBlock)); - addItem(new ItemInstance(Tile::obsidian)); - addItem(new ItemInstance(Tile::snow)); - addItem(new ItemInstance(Tile::glass)); - addItem(new ItemInstance(Tile::lightGem)); - - addItem(new ItemInstance(Tile::netherReactor)); - - addItem(new ItemInstance(Tile::cloth, 1, 0)); - addItem(new ItemInstance(Tile::cloth, 1, 7)); - addItem(new ItemInstance(Tile::cloth, 1, 6)); - addItem(new ItemInstance(Tile::cloth, 1, 5)); - addItem(new ItemInstance(Tile::cloth, 1, 4)); - addItem(new ItemInstance(Tile::cloth, 1, 3)); - addItem(new ItemInstance(Tile::cloth, 1, 2)); - addItem(new ItemInstance(Tile::cloth, 1, 1)); - - addItem(new ItemInstance(Tile::cloth, 1, 15)); - addItem(new ItemInstance(Tile::cloth, 1, 14)); - addItem(new ItemInstance(Tile::cloth, 1, 13)); - addItem(new ItemInstance(Tile::cloth, 1, 12)); - addItem(new ItemInstance(Tile::cloth, 1, 11)); - addItem(new ItemInstance(Tile::cloth, 1, 10)); - addItem(new ItemInstance(Tile::cloth, 1, 9)); - addItem(new ItemInstance(Tile::cloth, 1, 8)); - addItem(new ItemInstance(Tile::ladder)); -#ifdef RPI - addItem(new ItemInstance(Tile::torch)); -#else - Sel[3] = addItem(new ItemInstance(Tile::torch)); -#endif - addItem(new ItemInstance(Tile::thinGlass)); - - addItem(new ItemInstance(Item::door_wood)); - addItem(new ItemInstance(Tile::trapdoor)); - addItem(new ItemInstance(Tile::fence)); - addItem(new ItemInstance(Tile::fenceGate)); - - addItem(new ItemInstance(Item::bed)); - addItem(new ItemInstance(Tile::bookshelf)); - addItem(new ItemInstance(Item::painting)); - addItem(new ItemInstance(Tile::workBench)); - addItem(new ItemInstance(Tile::stonecutterBench)); - addItem(new ItemInstance(Tile::chest)); - addItem(new ItemInstance(Tile::furnace)); - addItem(new ItemInstance(Tile::tnt)); - - addItem(new ItemInstance(((Tile*)Tile::flower))); - addItem(new ItemInstance(((Tile*)Tile::rose))); - addItem(new ItemInstance(((Tile*)Tile::mushroom1))); - addItem(new ItemInstance(((Tile*)Tile::mushroom2))); - addItem(new ItemInstance(Tile::cactus)); - addItem(new ItemInstance(Tile::melon)); - addItem(new ItemInstance(Item::reeds)); - Sel[8] = addItem(new ItemInstance(Tile::sapling, 1, 0)); - addItem(new ItemInstance(Tile::sapling, 1, 1)); - addItem(new ItemInstance(Tile::sapling, 1, 2)); - addItem(new ItemInstance((Tile*)Tile::leaves, 1, 0)); - addItem(new ItemInstance((Tile*)Tile::leaves, 1, 1)); - addItem(new ItemInstance((Tile*)Tile::leaves, 1, 2)); - - addItem(new ItemInstance(Item::seeds_wheat)); - addItem(new ItemInstance(Item::seeds_melon)); - addItem(new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE)); - addItem(new ItemInstance(Item::hoe_iron)); -#ifdef RPI - Sel[0] = addItem(new ItemInstance(Item::sword_iron)); -#else - addItem(new ItemInstance(Item::sword_iron)); -#endif - addItem(new ItemInstance(Item::bow)); - addItem(new ItemInstance(Item::sign)); - } else { -#if defined(WIN32) - // Survival - // addItem(new ItemInstance(Item::ironIngot, 64)); - // addItem(new ItemInstance(Item::ironIngot, 34)); - // addItem(new ItemInstance(Tile::stonecutterBench)); - // addItem(new ItemInstance(Tile::workBench)); - // addItem(new ItemInstance(Tile::furnace)); - // addItem(new ItemInstance(Tile::wood, 54)); - // addItem(new ItemInstance(Item::stick, 14)); - // addItem(new ItemInstance(Item::coal, 31)); - // addItem(new ItemInstance(Tile::sand, 6)); - // addItem(new ItemInstance(Item::dye_powder, 23, DyePowderItem::PURPLE)); -#endif - } -#endif - - for (unsigned int i = 0; i < items.size(); ++i) { - ItemInstance* item = items[i]; - - if (i < MAX_SELECTION_SIZE) { - if (item) - LOGE("Error: Should not have items on slot %i\n", i); - - items[i] = NULL; - continue; - } - - if (item && _isCreative) - item->count = 5; - } - - for (int i = 0; i < MAX_SELECTION_SIZE; ++i) { - linkedSlots[i] = LinkedSlot(Sel[i]); - } - - //LOGI("Inventory has %d items\n", (int)items.size()); -} - -void Inventory::clearInventoryWithDefault() -{ - clearInventory(); - setupDefault(); -} - -int Inventory::getAttackDamage( Entity* entity ) -{ - ItemInstance* item = getSelected(); - if (item != NULL) return item->getAttackDamage(entity); - return 1; -} - -bool Inventory::canDestroy( Tile* tile ) -{ - if (tile->material->isAlwaysDestroyable()) return true; - - ItemInstance* item = getSelected(); - if (item != NULL) return item->canDestroySpecial(tile); - return false; -} - -float Inventory::getDestroySpeed( Tile* tile ) -{ - ItemInstance* item = getSelected(); - if (item && item->id >= 256) { - return Item::items[item->id]->getDestroySpeed(NULL, tile); - } - return 1.0f; -} - -bool Inventory::moveToSelectionSlot( int selectionSlot, int inventorySlot, bool propagate ) { - return linkSlot(selectionSlot, inventorySlot, propagate); -} - -bool Inventory::moveToEmptySelectionSlot( int inventorySlot ) { - return linkEmptySlot(inventorySlot); -} - -void Inventory::doDrop( ItemInstance* item, bool randomly ) -{ - player->drop(item, randomly); -} - -bool Inventory::stillValid(Player* player) { - if (this->player->removed) return false; - if (player->distanceToSqr(this->player) > 8 * 8) return false; - return true; -} - -bool Inventory::add( ItemInstance* item ){ - if (_isCreative || player->hasFakeInventory) - return true; - - return super::add(item); -} - -bool Inventory::removeItem( const ItemInstance* samePtr ) { - for (int i = MAX_SELECTION_SIZE; i < (int)items.size(); ++i) { - if (items[i] == samePtr) { - clearSlot(i); - return true; - } - } - return false; -} +#include "Inventory.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/QuartzBlockTile.hpp" +#include "world/level/tile/TreeTile.hpp" +#include "world/level/tile/StoneSlabTile.hpp" +#include "world/item/DyePowderItem.hpp" +#include "world/item/crafting/Recipe.hpp" +#include "world/item/CoalItem.hpp" +#include "world/level/tile/SandStoneTile.hpp" + +Inventory::Inventory( Player* player, bool creativeMode ) +: super( 36 + Inventory::MAX_SELECTION_SIZE, + MAX_SELECTION_SIZE, + ContainerType::INVENTORY, + creativeMode), + player(player), + selected(0) +{ + setupDefault(); + compressLinkedSlotList(0); +} + +Inventory::~Inventory() { +} + +ItemInstance* Inventory::getSelected() { + return getLinked(selected); +} + +void Inventory::selectSlot( int slot ) { + if (slot < MAX_SELECTION_SIZE && slot >= 0) + selected = slot; +} + +bool Inventory::moveToSelectedSlot( int inventorySlot, bool propagate ) { + return linkSlot(selected, inventorySlot, propagate); +} + +int Inventory::getSelectionSize() { + return MAX_SELECTION_SIZE; +} + +void Inventory::setupDefault() { + clearInventory(); + int Sel[MAX_SELECTION_SIZE] = {0}; + +#ifdef DEMO_MODE + if (_isCreative) { + Sel[0] = addItem(new ItemInstance(Item::shovel_stone)); + addItem(new ItemInstance(Item::pickAxe_stone)); + addItem(new ItemInstance(Item::hatchet_stone)); + addItem(new ItemInstance((Item*)Item::shears)); + addItem(new ItemInstance(Tile::ladder)); + Sel[3] = addItem(new ItemInstance(Tile::torch)); + addItem(new ItemInstance(Item::door_wood)); + + Sel[4] = addItem(new ItemInstance(Tile::stoneBrick)); + Sel[5] = addItem(new ItemInstance(Tile::wood)); + Sel[2] = addItem(new ItemInstance(Tile::redBrick)); + Sel[1] = addItem(new ItemInstance(Tile::dirt)); + addItem(new ItemInstance(Tile::sandStone)); + addItem(new ItemInstance(Tile::gravel)); + addItem(new ItemInstance(Tile::rock)); + addItem(new ItemInstance(Tile::sand)); + //addItem(new ItemInstance(Tile::clay)); + + addItem(new ItemInstance(Tile::cloth, 1, 15)); + addItem(new ItemInstance(Tile::cloth, 1, 14)); + addItem(new ItemInstance(Tile::cloth, 1, 13)); + Sel[7] = addItem(new ItemInstance(Tile::cloth, 1, 12)); + addItem(new ItemInstance(Tile::cloth, 1, 11)); + addItem(new ItemInstance(Tile::cloth, 1, 10)); + Sel[8] = addItem(new ItemInstance(Tile::cloth, 1, 9)); + addItem(new ItemInstance(Tile::cloth, 1, 8)); + Sel[6] = addItem(new ItemInstance(Tile::glass)); + addItem(new ItemInstance(Tile::thinGlass)); + addItem(new ItemInstance(Tile::stairs_stone)); + addItem(new ItemInstance(Tile::bookshelf)); + addItem(new ItemInstance(Tile::workBench)); + addItem(new ItemInstance(Tile::chest)); + addItem(new ItemInstance(Tile::furnace)); + + addItem(new ItemInstance(((Tile*)Tile::flower))); + addItem(new ItemInstance(Tile::cactus)); + + // + // Those below are inactive due to demo + // + addItem(new ItemInstance(Item::sword_stone)); + addItem(new ItemInstance(Tile::treeTrunk, 1, 0)); + addItem(new ItemInstance(Tile::treeTrunk, 1, 1)); + addItem(new ItemInstance(Tile::treeTrunk, 1, 2)); + addItem(new ItemInstance(Tile::fence)); + addItem(new ItemInstance(Tile::fenceGate)); + addItem(new ItemInstance(Item::reeds)); + addItem(new ItemInstance(((Tile*)Tile::rose))); + addItem(new ItemInstance(((Tile*)Tile::mushroom2))); + addItem(new ItemInstance(((Tile*)Tile::mushroom1))); + addItem(new ItemInstance(Tile::cloth, 1, 7)); + addItem(new ItemInstance(Tile::cloth, 1, 6)); + addItem(new ItemInstance(Tile::cloth, 1, 5)); + addItem(new ItemInstance(Tile::cloth, 1, 4)); + addItem(new ItemInstance(Tile::cloth, 1, 3)); + addItem(new ItemInstance(Tile::stairs_wood)); + addItem(new ItemInstance(Tile::goldBlock)); + addItem(new ItemInstance(Tile::ironBlock)); + addItem(new ItemInstance(Tile::emeraldBlock)); + addItem(new ItemInstance(Tile::lapisBlock)); + addItem(new ItemInstance(Tile::obsidian)); + addItem(new ItemInstance((Tile*)Tile::leaves, 1, 0)); + addItem(new ItemInstance((Tile*)Tile::leaves, 1, 1)); + addItem(new ItemInstance((Tile*)Tile::leaves, 1, 2)); + addItem(new ItemInstance(Tile::stoneSlabHalf)); + } else { +#if defined(WIN32) + // Survival + addItem(new ItemInstance((Item*)Item::shears)); + addItem(new ItemInstance(Tile::redBrick)); + addItem(new ItemInstance(Tile::glass)); +#endif + } +#else + if (_isCreative) { + // Blocks + Sel[1] = addItem(new ItemInstance(Tile::stoneBrick)); + addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 0)); + addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 1)); + addItem(new ItemInstance(Tile::stoneBrickSmooth, 1, 2)); + addItem(new ItemInstance(Tile::mossStone)); + Sel[5] = addItem(new ItemInstance(Tile::wood)); + Sel[2] = addItem(new ItemInstance(Tile::redBrick)); + +#ifdef RPI + Sel[3] = addItem(new ItemInstance(Tile::rock)); +#else + Sel[0] = addItem(new ItemInstance(Tile::rock)); +#endif + Sel[4] = addItem(new ItemInstance(Tile::dirt)); + addItem(new ItemInstance(Tile::grass)); + addItem(new ItemInstance(Tile::clay)); + addItem(new ItemInstance(Tile::sandStone, 1, 0)); + addItem(new ItemInstance(Tile::sandStone, 1, 1)); + addItem(new ItemInstance(Tile::sandStone, 1, 2)); + addItem(new ItemInstance(Tile::sand)); + addItem(new ItemInstance(Tile::gravel)); + + Sel[7] = addItem(new ItemInstance(Tile::treeTrunk, 1, 0)); + addItem(new ItemInstance(Tile::treeTrunk, 1, 1)); + addItem(new ItemInstance(Tile::treeTrunk, 1, 2)); + addItem(new ItemInstance(Tile::netherBrick)); + addItem(new ItemInstance(Tile::netherrack)); + addItem(new ItemInstance(Tile::stairs_stone)); + addItem(new ItemInstance(Tile::stairs_wood)); + Sel[6] = addItem(new ItemInstance(Tile::stairs_brick)); + addItem(new ItemInstance(Tile::stairs_sandStone)); + addItem(new ItemInstance(Tile::stairs_stoneBrickSmooth)); + addItem(new ItemInstance(Tile::stairs_netherBricks)); + addItem(new ItemInstance(Tile::stairs_quartz)); + addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::STONE_SLAB)); + addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::COBBLESTONE_SLAB)); + addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::WOOD_SLAB)); + addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::BRICK_SLAB)); + addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::SAND_SLAB)); + addItem(new ItemInstance(Tile::stoneSlabHalf, 1, StoneSlabTile::SMOOTHBRICK_SLAB)); + + addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_DEFAULT)); + addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_LINES)); + addItem(new ItemInstance(Tile::quartzBlock, 1, QuartzBlockTile::TYPE_CHISELED)); + + + + // Ores + addItem(new ItemInstance(Tile::coalOre)); + addItem(new ItemInstance(Tile::ironOre)); + addItem(new ItemInstance(Tile::goldOre)); + addItem(new ItemInstance(Tile::emeraldOre)); + addItem(new ItemInstance(Tile::lapisOre)); + addItem(new ItemInstance(Tile::redStoneOre)); + + addItem(new ItemInstance(Tile::goldBlock)); + addItem(new ItemInstance(Tile::ironBlock)); + addItem(new ItemInstance(Tile::emeraldBlock)); + addItem(new ItemInstance(Tile::lapisBlock)); + addItem(new ItemInstance(Tile::obsidian)); + addItem(new ItemInstance(Tile::snow)); + addItem(new ItemInstance(Tile::glass)); + addItem(new ItemInstance(Tile::lightGem)); + + addItem(new ItemInstance(Tile::netherReactor)); + + addItem(new ItemInstance(Tile::cloth, 1, 0)); + addItem(new ItemInstance(Tile::cloth, 1, 7)); + addItem(new ItemInstance(Tile::cloth, 1, 6)); + addItem(new ItemInstance(Tile::cloth, 1, 5)); + addItem(new ItemInstance(Tile::cloth, 1, 4)); + addItem(new ItemInstance(Tile::cloth, 1, 3)); + addItem(new ItemInstance(Tile::cloth, 1, 2)); + addItem(new ItemInstance(Tile::cloth, 1, 1)); + + addItem(new ItemInstance(Tile::cloth, 1, 15)); + addItem(new ItemInstance(Tile::cloth, 1, 14)); + addItem(new ItemInstance(Tile::cloth, 1, 13)); + addItem(new ItemInstance(Tile::cloth, 1, 12)); + addItem(new ItemInstance(Tile::cloth, 1, 11)); + addItem(new ItemInstance(Tile::cloth, 1, 10)); + addItem(new ItemInstance(Tile::cloth, 1, 9)); + addItem(new ItemInstance(Tile::cloth, 1, 8)); + addItem(new ItemInstance(Tile::ladder)); +#ifdef RPI + addItem(new ItemInstance(Tile::torch)); +#else + Sel[3] = addItem(new ItemInstance(Tile::torch)); +#endif + addItem(new ItemInstance(Tile::thinGlass)); + + addItem(new ItemInstance(Item::door_wood)); + addItem(new ItemInstance(Tile::trapdoor)); + addItem(new ItemInstance(Tile::fence)); + addItem(new ItemInstance(Tile::fenceGate)); + + addItem(new ItemInstance(Item::bed)); + addItem(new ItemInstance(Tile::bookshelf)); + addItem(new ItemInstance(Item::painting)); + addItem(new ItemInstance(Tile::workBench)); + addItem(new ItemInstance(Tile::stonecutterBench)); + addItem(new ItemInstance(Tile::chest)); + addItem(new ItemInstance(Tile::furnace)); + addItem(new ItemInstance(Tile::tnt)); + + addItem(new ItemInstance(((Tile*)Tile::flower))); + addItem(new ItemInstance(((Tile*)Tile::rose))); + addItem(new ItemInstance(((Tile*)Tile::mushroom1))); + addItem(new ItemInstance(((Tile*)Tile::mushroom2))); + addItem(new ItemInstance(Tile::cactus)); + addItem(new ItemInstance(Tile::melon)); + addItem(new ItemInstance(Item::reeds)); + Sel[8] = addItem(new ItemInstance(Tile::sapling, 1, 0)); + addItem(new ItemInstance(Tile::sapling, 1, 1)); + addItem(new ItemInstance(Tile::sapling, 1, 2)); + addItem(new ItemInstance((Tile*)Tile::leaves, 1, 0)); + addItem(new ItemInstance((Tile*)Tile::leaves, 1, 1)); + addItem(new ItemInstance((Tile*)Tile::leaves, 1, 2)); + + addItem(new ItemInstance(Item::seeds_wheat)); + addItem(new ItemInstance(Item::seeds_melon)); + addItem(new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE)); + addItem(new ItemInstance(Item::hoe_iron)); +#ifdef RPI + Sel[0] = addItem(new ItemInstance(Item::sword_iron)); +#else + addItem(new ItemInstance(Item::sword_iron)); +#endif + addItem(new ItemInstance(Item::bow)); + addItem(new ItemInstance(Item::sign)); + } else { +#if defined(WIN32) + // Survival + // addItem(new ItemInstance(Item::ironIngot, 64)); + // addItem(new ItemInstance(Item::ironIngot, 34)); + // addItem(new ItemInstance(Tile::stonecutterBench)); + // addItem(new ItemInstance(Tile::workBench)); + // addItem(new ItemInstance(Tile::furnace)); + // addItem(new ItemInstance(Tile::wood, 54)); + // addItem(new ItemInstance(Item::stick, 14)); + // addItem(new ItemInstance(Item::coal, 31)); + // addItem(new ItemInstance(Tile::sand, 6)); + // addItem(new ItemInstance(Item::dye_powder, 23, DyePowderItem::PURPLE)); +#endif + } +#endif + + for (unsigned int i = 0; i < items.size(); ++i) { + ItemInstance* item = items[i]; + + if (i < MAX_SELECTION_SIZE) { + if (item) + LOGE("Error: Should not have items on slot %i\n", i); + + items[i] = NULL; + continue; + } + + if (item && _isCreative) + item->count = 5; + } + + for (int i = 0; i < MAX_SELECTION_SIZE; ++i) { + linkedSlots[i] = LinkedSlot(Sel[i]); + } + + //LOGI("Inventory has %d items\n", (int)items.size()); +} + +void Inventory::clearInventoryWithDefault() +{ + clearInventory(); + setupDefault(); +} + +int Inventory::getAttackDamage( Entity* entity ) +{ + ItemInstance* item = getSelected(); + if (item != NULL) return item->getAttackDamage(entity); + return 1; +} + +bool Inventory::canDestroy( Tile* tile ) +{ + if (tile->material->isAlwaysDestroyable()) return true; + + ItemInstance* item = getSelected(); + if (item != NULL) return item->canDestroySpecial(tile); + return false; +} + +float Inventory::getDestroySpeed( Tile* tile ) +{ + ItemInstance* item = getSelected(); + if (item && item->id >= 256) { + return Item::items[item->id]->getDestroySpeed(NULL, tile); + } + return 1.0f; +} + +bool Inventory::moveToSelectionSlot( int selectionSlot, int inventorySlot, bool propagate ) { + return linkSlot(selectionSlot, inventorySlot, propagate); +} + +bool Inventory::moveToEmptySelectionSlot( int inventorySlot ) { + return linkEmptySlot(inventorySlot); +} + +void Inventory::doDrop( ItemInstance* item, bool randomly ) +{ + player->drop(item, randomly); +} + +bool Inventory::stillValid(Player* player) { + if (this->player->removed) return false; + if (player->distanceToSqr(this->player) > 8 * 8) return false; + return true; +} + +bool Inventory::add( ItemInstance* item ){ + if (_isCreative || player->hasFakeInventory) + return true; + + return super::add(item); +} + +bool Inventory::removeItem( const ItemInstance* samePtr ) { + for (int i = MAX_SELECTION_SIZE; i < (int)items.size(); ++i) { + if (items[i] == samePtr) { + clearSlot(i); + return true; + } + } + return false; +} diff --git a/src/world/entity/player/Inventory.h b/src/world/entity/player/Inventory.hpp similarity index 96% rename from src/world/entity/player/Inventory.h rename to src/world/entity/player/Inventory.hpp index 037e5c3..bdabe2d 100755 --- a/src/world/entity/player/Inventory.h +++ b/src/world/entity/player/Inventory.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.player; -#include "../../inventory/FillingContainer.h" +#include "world/inventory/FillingContainer.hpp" #include class Tile; diff --git a/src/world/entity/player/InventorySlotManager.h b/src/world/entity/player/InventorySlotManager.hpp similarity index 100% rename from src/world/entity/player/InventorySlotManager.h rename to src/world/entity/player/InventorySlotManager.hpp diff --git a/src/world/entity/player/OldInventory.h b/src/world/entity/player/OldInventory.hpp similarity index 100% rename from src/world/entity/player/OldInventory.h rename to src/world/entity/player/OldInventory.hpp diff --git a/src/world/entity/player/Player.cpp b/src/world/entity/player/Player.cpp index e287acf..709786c 100755 --- a/src/world/entity/player/Player.cpp +++ b/src/world/entity/player/Player.cpp @@ -1,924 +1,924 @@ -#include "Player.h" -#include "Inventory.h" -#include "../item/ItemEntity.h" -#include "../../level/Level.h" -#include "../../item/ItemInstance.h" -#include "../../item/BowItem.h" -#include "../../inventory/BaseContainerMenu.h" -#include "../../../nbt/CompoundTag.h" - -#include "../../../network/RakNetInstance.h" -#include "../../../network/packet/AnimatePacket.h" -#include "../../inventory/FurnaceMenu.h" -#include "../SharedFlags.h" -#include "../../level/tile/BedTile.h" -#include "../../Direction.h" -#include "../EntityEvent.h" -#include "../../Difficulty.h" -#include "../../item/ArmorItem.h" - -const float Player::DEFAULT_WALK_SPEED = 0.1f; -const float Player::DEFAULT_FLY_SPEED = 0.02f; - -// @todo: Move out to ArmorInventory -static ListTag* saveArmor(ItemInstance* armor); -static void loadArmor(ItemInstance* armor, ListTag* listTag); - -Player::Player(Level* level, bool isCreative) -: super(level), - userType(0), - playerHasRespawnPosition(false), - hasFakeInventory(false), - containerMenu(NULL), - useItemDuration(0), - playerIsSleeping(false), - sleepCounter(0), - bedOffsetX(0), - bedOffsetY(0), - bedOffsetZ(0), - respawnPosition(0, -1, 0), - allPlayersSleeping(false) -{ - canRemove = false; - - _init(); - entityRendererId = ER_PLAYER_RENDERER; - - autoSendPosRot = false; - inventory = new Inventory(this, isCreative); - - //inventoryMenu = /*new*/ InventoryMenu(inventory, !level.isOnline); - //containerMenu = inventoryMenu; - - heightOffset = 1.62f; - - Pos spawnPos = level->getSharedSpawnPos(); - this->moveTo((float)spawnPos.x + 0.5f, (float)(spawnPos.y + 1), (float)spawnPos.z + 0.5f, 0, 0); - - health = MAX_HEALTH; - modelName = "humanoid"; - rotOffs = 180; - flameTime = 20; - - textureName = "mob/char.png"; - entityData.define(DATA_PLAYER_FLAGS_ID, (PlayerFlagIDType) 0); - entityData.define(DATA_BED_POSITION_ID, Pos()); - //entityData.define(DATA_PLAYER_RUNNING_ID, (SynchedEntityData::TypeChar) 0); -} - -Player::~Player() { - delete inventory; -} -bool Player::isSleeping() { - return playerIsSleeping; -} -int Player::startSleepInBed( int x, int y, int z ) { - if(!level->isClientSide) { - if(isSleeping() || !isAlive()) { - return BedSleepingResult::OTHER_PROBLEM; - } - if(Mth::abs(this->x - x) > 3 || Mth::abs(this->y - y) > 4 || Mth::abs(this->z - z) > 3) { - return BedSleepingResult::TOO_FAR_AWAY; - } - if(level->dimension->isNaturalDimension()) { - return BedSleepingResult::NOT_POSSIBLE_HERE; - } - if(level->isDay()) { - return BedSleepingResult::NOT_POSSIBLE_NOW; - } - float hRange = 8; - float vRange = 5; - EntityList monsters; - level->getEntitiesOfClass(MobTypes::BaseEnemy, AABB(x- hRange, y - vRange, z - hRange, x + hRange, y + vRange, z + hRange), monsters); - if(!monsters.empty()) { - return BedSleepingResult::NOT_SAFE; - } - } - - setSize(0.2f, 0.2f); - heightOffset = 0.2f; - if(level->hasChunkAt(x, y, z)) { - int data = level->getData(x, y, z); - int direction = BedTile::getDirection(data); - float xo = 0.5f, zo = 0.5f; - switch(direction) { - case Direction::SOUTH: - zo = 0.9f; - break; - case Direction::NORTH: - zo = 0.1f; - break; - case Direction::WEST: - xo = 0.1f; - break; - case Direction::EAST: - xo = 0.9f; - break; - } - setBedOffset(direction); - setPos(x + xo, y + 15.0f / 16.0f, z + zo); - } else { - setPos(x + 0.5f, y + 1.0f / 16.0f, z + 0.5f); - } - playerIsSleeping = true; - sleepCounter = 0; - bedPosition = Pos(x, y, z); - xd = zd = yd = 0; - if(!level->isClientSide) { - level->updateSleepingPlayerList(); - } - entityData.set(DATA_BED_POSITION_ID, bedPosition); - entityData.setFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); - return BedSleepingResult::OK; -} - -void Player::stopSleepInBed( bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint ) { - if(!isSleeping()) - return; - setSize(0.6f, 1.8f); - setDefaultHeadHeight(); - Pos standUp = bedPosition; - if(level->getTile(int(bedPosition.x), int(bedPosition.y), int(bedPosition.z)) == Tile::bed->id) { - BedTile::setOccupied(level, int(bedPosition.x), int(bedPosition.y), int(bedPosition.z), false); - bool foundStandUpPosition = BedTile::findStandUpPosition(level, int(bedPosition.x), int(bedPosition.y), int(bedPosition.z), 0, standUp); - if(!foundStandUpPosition) { - standUp = Pos(bedPosition.x, bedPosition.y, bedPosition.z); - } - setPos(standUp.x + 0.5f, standUp.y + heightOffset + 0.1f, standUp.z + 0.5f); - } - playerIsSleeping = false; - if(!level->isClientSide && updateLevelList) { - level->updateSleepingPlayerList(); - } - if(forcefulWakeUp) { - sleepCounter = 0; - } else { - sleepCounter = SLEEP_DURATION; - } - // Quick fix to make the spawn position always saved, not sure if we always want to save this position but I like it. - if(true || saveRespawnPoint) { - Pos newRespawnPos; - BedTile::findStandUpPosition(level, bedPosition.x, bedPosition.y, bedPosition.z, 0, newRespawnPos); - setRespawnPosition(newRespawnPos); - } - entityData.clearFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); - allPlayersSleeping = false; -} - -int Player::getSleepTimer() { - return allPlayersSleeping ? sleepCounter : 0; -} -void Player::setAllPlayersSleeping() { - sleepCounter = 0; - allPlayersSleeping = true; -} -void Player::setBedOffset( int bedDirection ) { - bedOffsetX = 0; - bedOffsetZ = 0; - switch(bedDirection) { - case Direction::SOUTH: - bedOffsetZ = -1.8f; - break; - case Direction::NORTH: - bedOffsetZ = 1.8f; - break; - case Direction::WEST: - bedOffsetX = 1.8f; - break; - case Direction::EAST: - bedOffsetX = -1.8f; - break; - } -} -bool Player::isSleepingLongEnough() { - return isSleeping() && sleepCounter >= SLEEP_DURATION; -} - -float Player::getSleepRotation() { - if(isSleeping()) { - int data = level->getData(bedPosition.x, bedPosition.y, bedPosition.z); - int direction = BedTile::getDirection(data); - switch(direction) { - case Direction::SOUTH: - return 90; - case Direction::WEST: - return 0; - case Direction::NORTH: - return 270; - case Direction::EAST: - return 180; - } - } - return 0; -} - -bool Player::checkBed() { - return (level->getTile(bedPosition.x, bedPosition.y, bedPosition.z) == Tile::bed->id); -} - -void Player::tick() { - bool shouldSleep = entityData.getFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); - if(shouldSleep != isSleeping()) { - if(isSleeping()) { - stopSleepInBed(true, true, true); - } else { - bedPosition = entityData.getPos(DATA_BED_POSITION_ID); - startSleepInBed(bedPosition.x, bedPosition.y, bedPosition.z); - } - } - if(isSleeping()) { - sleepCounter++; - if(sleepCounter > SLEEP_DURATION) { - sleepCounter = SLEEP_DURATION; - } - if(!level->isClientSide) { - if(!checkBed()) { - stopSleepInBed(true, true, false); - } else if(level->isDay()) { - stopSleepInBed(false, true, true); - } - } - } else if(sleepCounter > 0) { - sleepCounter++; - if(sleepCounter >= (SLEEP_DURATION + WAKE_UP_DURATION)) { - sleepCounter = 0; - } - } - super::tick(); - - if (!level->isClientSide) { - foodData.tick(this); - // if (containerMenu != NULL && !containerMenu->stillValid(this)) { - // closeContainer(); - // } - } -} - -int Player::getMaxHealth() { - return MAX_HEALTH; -} - -// -// Use items -// -bool Player::isUsingItem() { - return !useItem.isNull(); -} - -ItemInstance* Player::getUseItem() { - return &useItem; -} - -void Player::spawnEatParticles(const ItemInstance* useItem, int count) { - if (useItem->getUseAnimation() == UseAnim::drink) { - level->playSound(this, "random.drink", 0.5f, level->random.nextFloat() * 0.1f + 0.9f); - } - else if (useItem->getUseAnimation() == UseAnim::eat) { - for (int i = 0; i < count; i++) { - const float xx = -xRot * Mth::PI / 180; - const float yy = -yRot * Mth::PI / 180; - Vec3 d((random.nextFloat() - 0.5f) * 0.1f, Mth::random() * 0.1f + 0.1f, 0); - d.xRot(xx); - d.yRot(yy); - Vec3 p((random.nextFloat() - 0.5f) * 0.3f, -random.nextFloat() * 0.6f - 0.3f, 0.6f); - p.xRot(xx); - p.yRot(yy); - p = p.add(x, y + getHeadHeight(), z); - level->addParticle(PARTICLETYPE(iconcrack), p.x, p.y, p.z, d.x, d.y + 0.05f, d.z, useItem->getItem()->id); - } - level->playSound(this, "random.eat", .5f + .5f * random.nextInt(2), (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); - } -} - -void Player::startUsingItem(ItemInstance instance, int duration) { - if(instance == useItem) return; - useItem = instance; - useItemDuration = duration; - if(!level->isClientSide) { - setSharedFlag(SharedFlagsInformation::FLAG_USINGITEM, true); - } -} - -void Player::stopUsingItem() { - if(getCarriedItem() != NULL && useItem.id == getCarriedItem()->id) - getCarriedItem()->setAuxValue(useItem.getAuxValue()); - useItem.setNull(); - useItemDuration = 0; - if(!level->isClientSide) { - setSharedFlag(SharedFlagsInformation::FLAG_USINGITEM, false); - } -} - -void Player::releaseUsingItem() { - if(!useItem.isNull()) { - useItem.releaseUsing(level, this, useItemDuration); - } - stopUsingItem(); -} - -void Player::completeUsingItem() { - if(!useItem.isNull()) { - spawnEatParticles(&useItem, 10); - - // Check if the item is valid, and if we should overwrite the - // inventory item afterwards. - ItemInstance* selected = inventory->getSelected(); - bool doOverwrite = selected && ItemInstance::matches(&useItem, selected); - - ItemInstance itemInstance = useItem.useTimeDepleted(level, this); - - if (doOverwrite) { - *selected = useItem; - if (selected->count == 0) - inventory->clearSlot(inventory->selected); - } - - /* - int oldCount = useItem.count; - if (!itemInstance.matches(&useItem)) { - ItemInstance* selected = inventory->getSelected(); - if (ItemInstance::matches(&useItem, selected)) { - if (selected) *selected = itemInstance; - if (itemInstance.count == 0) { - inventory->clearSlot(inventory->selected); - } - } - } - */ - - stopUsingItem(); - } -} - -int Player::getUseItemDuration() { - return useItemDuration; -} - -int Player::getTicksUsingItem() { - if(isUsingItem()) { - return useItem.getUseDuration() - useItemDuration; - } - return 0; -} - -void Player::travel(float xa, float ya) { - if (abilities.flying) { - float ydo = yd; - float ofs = flyingSpeed; - flyingSpeed = 0.05f; - super::travel(xa, ya); - yd = ydo * 0.6f; - flyingSpeed = ofs; - } else { - super::travel(xa, ya); - } -} - -/*protected*/ -bool Player::isImmobile() { - return health <= 0 || isSleeping(); -} - -/*protected*/ -void Player::closeContainer() { - containerMenu = NULL; - //containerMenu = inventoryMenu; -} - -void Player::resetPos(bool clearMore) { - if(!isSleeping()) { - heightOffset = 1.62f; - setSize(0.6f, 1.8f); - super::resetPos(clearMore); - } - invisible = false; - - if (clearMore) { - health = getMaxHealth(); - deathTime = 0; - playerIsSleeping = false; - } -} - -/*protected*/ -void Player::updateAi() { - updateAttackAnim(); -} - -int Player::getItemInHandIcon(ItemInstance* item, int layer) { - int icon = item->getIcon(); - if(useItem.id != 0 && item->id == Item::bow->id) { - int ticksHeld = (item->getUseDuration() - useItemDuration); - if(ticksHeld >= BowItem::MAX_DRAW_DURATION - 2) { - return 5 + 8 * 16; - } - if(ticksHeld > (2 * BowItem::MAX_DRAW_DURATION) / 3) { - return 5 + 7*16; - } - if(ticksHeld > 0) { - return 5 + 6 * 16; - } - } - return icon; -} - -void Player::aiStep() { - if (level->difficulty == Difficulty::PEACEFUL && health < MAX_HEALTH) { - if (tickCount % (12 * SharedConstants::TicksPerSecond) == 0) heal(1); - } - //inventory.tick(); - oBob = bob; - // moved the super::aiStep() part to the local player - - float tBob = (float) Mth::sqrt(xd * xd + zd * zd); - float tTilt = (float) Mth::atan(-yd * 0.2f) * 15.f; - if (tBob > 0.1f) tBob = 0.1f; - if (!onGround || health <= 0) tBob = 0; - if (onGround || health <= 0) tTilt = 0; - bob += (tBob - bob) * 0.4f; - tilt += (tTilt - tilt) * 0.8f; - - if (health > 0) { - EntityList& entities = level->getEntities(this, bb.grow(1, 0, 1)); - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - if (!e->removed) { - touch(e); - } - } - } -} - -/*private*/ -void Player::touch(Entity* entity) { - entity->playerTouch(this); -} - -int Player::getScore() { - return score; -} - -void Player::die(Entity* source) { - super::die(source); - this->setSize(0.2f, 0.2f); - setPos(x, y, z); - yd = 0.1f; - - //inventory->dropAll(level->isClientSide); - - if (source != NULL) { - xd = -(float) Mth::cos((hurtDir + yRot) * Mth::PI / 180) * 0.1f; - zd = -(float) Mth::sin((hurtDir + yRot) * Mth::PI / 180) * 0.1f; - } else { - xd = zd = 0; - } - this->heightOffset = 0.1f; -} - -void Player::reset() { - super::reset(); - this->_init(); -} - -void Player::_init() { - oBob = bob = 0; - swinging = 0; - swingTime = 0; - score = 0; -} - -float Player::getWalkingSpeedModifier() { - return 1.0f; -} - - -void Player::awardKillScore(Entity* victim, int score) { - this->score += score; -} - -bool Player::isShootable() { - return true; -} - -bool Player::isCreativeModeAllowed() { - return true; -} - -//void Player::drop() { -// //drop(inventory.removeItem(inventory.selected, 1), false); -//} - -void Player::drop(ItemInstance* item) { - drop(item, false); -} - -void Player::drop(ItemInstance* item, bool randomly) { - if (item == NULL || item->isNull()) - return; - - ItemEntity* thrownItem = new ItemEntity(level, x, y - 0.3f + getHeadHeight(), z, *item); - { //@todo:itementity - delete item; - item = NULL; - } - thrownItem->throwTime = 20 * 2; - - float pow = 0.1f; - if (randomly) { - float _pow = random.nextFloat() * 0.5f; - float dir = random.nextFloat() * Mth::PI * 2; - thrownItem->xd = -Mth::sin(dir) * _pow; - thrownItem->zd = Mth::cos(dir) * _pow; - thrownItem->yd = 0.2f; - - } else { - pow = 0.3f; - thrownItem->xd = -Mth::sin(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * pow; - thrownItem->zd = Mth::cos(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * pow; - thrownItem->yd = -Mth::sin(xRot / 180 * Mth::PI) * pow + 0.1f; - pow = 0.02f; - - float dir = random.nextFloat() * Mth::PI * 2; - pow *= random.nextFloat(); - thrownItem->xd += Mth::cos(dir) * pow; - thrownItem->yd += (random.nextFloat() - random.nextFloat()) * 0.1f; - thrownItem->zd += Mth::sin(dir) * pow; - } - - reallyDrop(thrownItem); -} - -/*protected*/ -void Player::reallyDrop(ItemEntity* thrownItem) { - level->addEntity(thrownItem); -} - -float Player::getDestroySpeed(Tile* tile) { - float speed = inventory->getDestroySpeed(tile); - //if (isUnderLiquid(Material.water)) speed /= 5; - //if (!onGround) speed /= 5; - return speed; -} - -bool Player::canDestroy(Tile* tile) { - return inventory->canDestroy(tile); -} - -//@SuppressWarnings("unchecked") -void Player::readAdditionalSaveData(CompoundTag* entityTag) { - super::readAdditionalSaveData(entityTag); - - if (entityTag->contains("Inventory", Tag::TAG_List)) { - ListTag* inventoryList = entityTag->getList("Inventory"); - inventory->load(inventoryList); - } - if (entityTag->contains("Armor", Tag::TAG_List)) { - loadArmor(armor, entityTag->getList("Armor")); - } - - dimension = entityTag->getInt("Dimension"); - - //return; - if(entityTag->contains("Sleeping") && entityTag->contains("SleepTimer") - && entityTag->contains("BedPositionX") && entityTag->contains("BedPositionY") && entityTag->contains("BedPositionZ")) { - playerIsSleeping = entityTag->getBoolean("Sleeping"); - sleepCounter = entityTag->getShort("SleepTimer"); - bedPosition = Pos(entityTag->getInt("BedPositionX"), entityTag->getInt("BedPositionY"), entityTag->getInt("BedPositionZ")); - } else { - playerIsSleeping = false; - bedPosition = Pos(0,0,0); - } - - if(!playerIsSleeping) { - stopSleepInBed(true, true, false); - entityData.clearFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); - } else { - playerIsSleeping = false; - startSleepInBed(bedPosition.x, bedPosition.y, bedPosition.z); - entityData.setFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); - } - entityData.set(DATA_BED_POSITION_ID, bedPosition); - if (entityTag->contains("SpawnX") && entityTag->contains("SpawnY") && entityTag->contains("SpawnZ")) { - respawnPosition.set(entityTag->getInt("SpawnX"), entityTag->getInt("SpawnY"), entityTag->getInt("SpawnZ")); - } - playerHasRespawnPosition = respawnPosition.y >= 0; -} - -void Player::addAdditonalSaveData(CompoundTag* entityTag) { - super::addAdditonalSaveData(entityTag); - - ListTag* inventoryTag = inventory->save(new ListTag()); - // if (inventoryTag->size() > 0) - entityTag->put("Inventory", inventoryTag); - //else - // delete inventoryTag; - - ListTag* armorTag = saveArmor(armor); - entityTag->put("Armor", armorTag); - - entityTag->putInt("Dimension", dimension); - //return; - - entityTag->putBoolean("Sleeping", isSleeping()); - entityTag->putShort("SleepTimer", sleepCounter); - entityTag->putInt("BedPositionX", bedPosition.x); - entityTag->putInt("BedPositionY", bedPosition.y); - entityTag->putInt("BedPositionZ", bedPosition.z); - - entityTag->putInt("SpawnX", respawnPosition.x); - entityTag->putInt("SpawnY", respawnPosition.y); - entityTag->putInt("SpawnZ", respawnPosition.z); -} - -//static Pos getRespawnPosition(Level level, CompoundTag entityTag) { -// if (entityTag.contains("SpawnX") && entityTag.contains("SpawnY") && entityTag.contains("SpawnZ")) { -// return /*new*/ Pos(entityTag.getInt("SpawnX"), entityTag.getInt("SpawnY"), entityTag.getInt("SpawnZ")); -// } -// return level.getSharedSpawnPos(); -//} - -void Player::startCrafting(int x, int y, int z, int tableSize) { -} - -void Player::startStonecutting(int x, int y, int z) { -} - -void Player::openFurnace(FurnaceTileEntity* e) { -} - -void Player::take(Entity* e, int orgCount) { -} - -float Player::getHeadHeight() { - return 0.12f; // heightOffset; // 0.12f; -} - -/*protected*/ -void Player::setDefaultHeadHeight() { - heightOffset = 1.62f; -} - -bool Player::isHurt() { - return health > 0 && health < getMaxHealth(); -} - -bool Player::hurt(Entity* source, int dmg) { - if (abilities.invulnerable) return false; - - noActionTime = 0; - if (health <= 0) return false; - if(isSleeping() && !level->isClientSide) { - stopSleepInBed(true, true, false); - } - - if (source != NULL && (source->getCreatureBaseType() == MobTypes::BaseEnemy - || source->getEntityTypeId() == EntityTypes::IdArrow)) { - - if (source->isMob() && level->adventureSettings.noMvP) - return false; - - if (level->difficulty == Difficulty::PEACEFUL) dmg = 0; - else if (level->difficulty == Difficulty::EASY) dmg = dmg / 3 + 1; - else if (level->difficulty == Difficulty::HARD) dmg = dmg * 3 / 2; - } - - if (dmg == 0) return false; - - // Entity* attacker = source; - // //if (attacker instanceof Arrow) { - // // if (((Arrow) attacker).owner != NULL) { - // // attacker = ((Arrow) attacker).owner; - // // } - // //} - return super::hurt(source, dmg); -} - -void Player::interact(Entity* entity) { - if (entity->interact(this)) return; - ItemInstance* item = inventory->getSelected(); - if (item != NULL && entity->isMob()) { - item->interactEnemy((Mob*)entity); - if (item->count <= 0) { - //item.snap(this); - inventory->clearSlot(inventory->selected); - } - } -} - -//void Player::swing() { - //LOGI("swinging: %d\n", swinging); -// if (!swinging || swingTime >= 3 || swingTime < 0) { -// swingTime = -1; -// swinging = true; -// } - - //level->raknetInstance->send(owner, new AnimatePacket(AnimatePacket::Swing, this)); - //} -//} - -void Player::attack(Entity* entity) { - int dmg = inventory->getAttackDamage(entity); - if (dmg > 0) { - entity->hurt(this, dmg); - ItemInstance* item = inventory->getSelected(); - if (item != NULL && entity->isMob() && abilities.instabuild != true) { - item->hurtEnemy((Mob*) entity); - if (item->count <= 0) { - //item->snap(this); - inventory->clearSlot(inventory->selected); - } - } - } -} - -void Player::respawn() { -} - -/*protected static*/ -void Player::animateRespawn(Player* player, Level* level) { - //for (int i = 0; i < 45; i++) { - // float angle = i * Mth::PI * 4.0f / 25.0f; - // float xo = Mth::cos(angle) * .7f; - // float zo = Mth::sin(angle) * .7f; - //} -} - -/*virtual*/ -void Player::animateRespawn() {} - -//void carriedChanged(ItemInstance carried) { -//} -ItemInstance* Player::getCarriedItem() { - return inventory->getSelected(); -} - -void Player::remove() { - invisible = true; - super::remove(); -} - -//@Override -bool Player::isInWall() { - return super::isInWall(); -} - -bool Player::hasResource( int id ) { - return inventory->hasResource(id); -} - -/** - * This method is currently only relevant to client-side players. It will - * try to load the messageId from the language file and display it to the - * client. - */ -void Player::displayClientMessage(const std::string& messageId) { -} - -Pos Player::getRespawnPosition() { - return respawnPosition; -} - -void Player::setRespawnPosition(const Pos& respawnPosition) { // @attn WARNING CHECK THIS THROUGH @fix @todo: rewrite - if (respawnPosition.y < 0) { - playerHasRespawnPosition = false; - } - else { - playerHasRespawnPosition = true; - } - this->respawnPosition = respawnPosition; -} - -bool Player::isPlayer() { return true; } - -/*static*/ -bool Player::isPlayer( Entity* e ) { - return e && e->isPlayer(); -} - -Player* Player::asPlayer( Entity* e ) { - return isPlayer(e)? (Player*) e : NULL; -} - -void Player::openContainer(ChestTileEntity* container) -{ -} - -void Player::tileEntityDestroyed( int tileEntityId ) { - - //LOGI("TileEntityDestroyed, container: %p, %p\n", this, containerMenu); - - if (!containerMenu) return; - - //LOGI("TileEntityDestroyed, id: %d, %p, %d\n", this, tileEntityId, ((FurnaceMenu*)containerMenu)->furnaceTileEntityId); - - if (containerMenu->tileEntityDestroyedIsInvalid(tileEntityId)) - closeContainer(); -} - -bool Player::canUseCarriedItemWhileMoving() { - ItemInstance* item = getCarriedItem(); - return item && - ( item->id == Item::bow->id - || item->getItem()->isFood()); -} - -void Player::handleEntityEvent( char id ) { - if (id == EntityEvent::USE_ITEM_COMPLETE) { - completeUsingItem(); - } else { - super::handleEntityEvent(id); - } -} - -ItemInstance* Player::getSelectedItem() { - return inventory->getSelected(); -} - -bool Player::hasRespawnPosition(){ - return playerHasRespawnPosition; -} - -void Player::openTextEdit( TileEntity* tileEntity ) { - // Do nothing on the server, this is a client thing :) -} - -// -// Armor code. Move this out to an ArmorInventory -// -static ListTag* saveArmor(ItemInstance* armor) { - ListTag* listTag = new ListTag(); - for (int i = 0; i < 4; ++i) { - CompoundTag* tag = new CompoundTag(); - armor[i].save(tag); - listTag->add(tag); - } - return listTag; -} - -static void loadArmor(ItemInstance* armor, ListTag* listTag) { - if (!listTag) - return; - - const int count = Mth::Min(4, listTag->size()); - for (int i = 0; i < count; ++i) { - Tag* tag = listTag->get(i); - if (tag->getId() != Tag::TAG_Compound) continue; - - armor[i].load((CompoundTag*) tag); - } -} - -ItemInstance* Player::getArmor(int slot) { - if (slot < 0 || slot >= NUM_ARMOR) - return NULL; - - if (armor[slot].isNull()) - return NULL; - - return &armor[slot]; -} - -void Player::setArmor(int slot, const ItemInstance* item) { - if (item == NULL) - armor[slot].setNull(); - else { - armor[slot] = *item; - } -} - -void Player::hurtArmor( int dmg ) { - dmg = Mth::Max(1, dmg / 4); - - for (int i = 0; i < NUM_ARMOR; i++) { - ItemInstance& item = armor[i]; - if (!ItemInstance::isArmorItem(&item)) - continue; - - item.hurt(dmg); - if (item.count == 0) { - item.setNull(); - } - } -} - -int Player::getArmorTypeHash() { - return (armor[0].id ) + - (armor[1].id << 8) + - (armor[2].id << 16) + - (armor[3].id << 24); -} - -int Player::getArmorValue() { - int val = 0; - - for (int i = 0; i < NUM_ARMOR; i++) { - ItemInstance& item = armor[i]; - if (!ItemInstance::isArmorItem(&item)) - continue; - - int baseProtection = ((ArmorItem*) item.getItem())->defense; - val += baseProtection; - } - return val; -} - +#include "Player.hpp" +#include "Inventory.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/level/Level.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/item/BowItem.hpp" +#include "world/inventory/BaseContainerMenu.hpp" +#include "nbt/CompoundTag.hpp" + +#include "network/RakNetInstance.hpp" +#include "network/packet/AnimatePacket.hpp" +#include "world/inventory/FurnaceMenu.hpp" +#include "world/entity/SharedFlags.hpp" +#include "world/level/tile/BedTile.hpp" +#include "world/Direction.hpp" +#include "world/entity/EntityEvent.hpp" +#include "world/Difficulty.hpp" +#include "world/item/ArmorItem.hpp" + +const float Player::DEFAULT_WALK_SPEED = 0.1f; +const float Player::DEFAULT_FLY_SPEED = 0.02f; + +// @todo: Move out to ArmorInventory +static ListTag* saveArmor(ItemInstance* armor); +static void loadArmor(ItemInstance* armor, ListTag* listTag); + +Player::Player(Level* level, bool isCreative) +: super(level), + userType(0), + playerHasRespawnPosition(false), + hasFakeInventory(false), + containerMenu(NULL), + useItemDuration(0), + playerIsSleeping(false), + sleepCounter(0), + bedOffsetX(0), + bedOffsetY(0), + bedOffsetZ(0), + respawnPosition(0, -1, 0), + allPlayersSleeping(false) +{ + canRemove = false; + + _init(); + entityRendererId = ER_PLAYER_RENDERER; + + autoSendPosRot = false; + inventory = new Inventory(this, isCreative); + + //inventoryMenu = /*new*/ InventoryMenu(inventory, !level.isOnline); + //containerMenu = inventoryMenu; + + heightOffset = 1.62f; + + Pos spawnPos = level->getSharedSpawnPos(); + this->moveTo((float)spawnPos.x + 0.5f, (float)(spawnPos.y + 1), (float)spawnPos.z + 0.5f, 0, 0); + + health = MAX_HEALTH; + modelName = "humanoid"; + rotOffs = 180; + flameTime = 20; + + textureName = "mob/char.png"; + entityData.define(DATA_PLAYER_FLAGS_ID, (PlayerFlagIDType) 0); + entityData.define(DATA_BED_POSITION_ID, Pos()); + //entityData.define(DATA_PLAYER_RUNNING_ID, (SynchedEntityData::TypeChar) 0); +} + +Player::~Player() { + delete inventory; +} +bool Player::isSleeping() { + return playerIsSleeping; +} +int Player::startSleepInBed( int x, int y, int z ) { + if(!level->isClientSide) { + if(isSleeping() || !isAlive()) { + return BedSleepingResult::OTHER_PROBLEM; + } + if(Mth::abs(this->x - x) > 3 || Mth::abs(this->y - y) > 4 || Mth::abs(this->z - z) > 3) { + return BedSleepingResult::TOO_FAR_AWAY; + } + if(level->dimension->isNaturalDimension()) { + return BedSleepingResult::NOT_POSSIBLE_HERE; + } + if(level->isDay()) { + return BedSleepingResult::NOT_POSSIBLE_NOW; + } + float hRange = 8; + float vRange = 5; + EntityList monsters; + level->getEntitiesOfClass(MobTypes::BaseEnemy, AABB(x- hRange, y - vRange, z - hRange, x + hRange, y + vRange, z + hRange), monsters); + if(!monsters.empty()) { + return BedSleepingResult::NOT_SAFE; + } + } + + setSize(0.2f, 0.2f); + heightOffset = 0.2f; + if(level->hasChunkAt(x, y, z)) { + int data = level->getData(x, y, z); + int direction = BedTile::getDirection(data); + float xo = 0.5f, zo = 0.5f; + switch(direction) { + case Direction::SOUTH: + zo = 0.9f; + break; + case Direction::NORTH: + zo = 0.1f; + break; + case Direction::WEST: + xo = 0.1f; + break; + case Direction::EAST: + xo = 0.9f; + break; + } + setBedOffset(direction); + setPos(x + xo, y + 15.0f / 16.0f, z + zo); + } else { + setPos(x + 0.5f, y + 1.0f / 16.0f, z + 0.5f); + } + playerIsSleeping = true; + sleepCounter = 0; + bedPosition = Pos(x, y, z); + xd = zd = yd = 0; + if(!level->isClientSide) { + level->updateSleepingPlayerList(); + } + entityData.set(DATA_BED_POSITION_ID, bedPosition); + entityData.setFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); + return BedSleepingResult::OK; +} + +void Player::stopSleepInBed( bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint ) { + if(!isSleeping()) + return; + setSize(0.6f, 1.8f); + setDefaultHeadHeight(); + Pos standUp = bedPosition; + if(level->getTile(int(bedPosition.x), int(bedPosition.y), int(bedPosition.z)) == Tile::bed->id) { + BedTile::setOccupied(level, int(bedPosition.x), int(bedPosition.y), int(bedPosition.z), false); + bool foundStandUpPosition = BedTile::findStandUpPosition(level, int(bedPosition.x), int(bedPosition.y), int(bedPosition.z), 0, standUp); + if(!foundStandUpPosition) { + standUp = Pos(bedPosition.x, bedPosition.y, bedPosition.z); + } + setPos(standUp.x + 0.5f, standUp.y + heightOffset + 0.1f, standUp.z + 0.5f); + } + playerIsSleeping = false; + if(!level->isClientSide && updateLevelList) { + level->updateSleepingPlayerList(); + } + if(forcefulWakeUp) { + sleepCounter = 0; + } else { + sleepCounter = SLEEP_DURATION; + } + // Quick fix to make the spawn position always saved, not sure if we always want to save this position but I like it. + if(true || saveRespawnPoint) { + Pos newRespawnPos; + BedTile::findStandUpPosition(level, bedPosition.x, bedPosition.y, bedPosition.z, 0, newRespawnPos); + setRespawnPosition(newRespawnPos); + } + entityData.clearFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); + allPlayersSleeping = false; +} + +int Player::getSleepTimer() { + return allPlayersSleeping ? sleepCounter : 0; +} +void Player::setAllPlayersSleeping() { + sleepCounter = 0; + allPlayersSleeping = true; +} +void Player::setBedOffset( int bedDirection ) { + bedOffsetX = 0; + bedOffsetZ = 0; + switch(bedDirection) { + case Direction::SOUTH: + bedOffsetZ = -1.8f; + break; + case Direction::NORTH: + bedOffsetZ = 1.8f; + break; + case Direction::WEST: + bedOffsetX = 1.8f; + break; + case Direction::EAST: + bedOffsetX = -1.8f; + break; + } +} +bool Player::isSleepingLongEnough() { + return isSleeping() && sleepCounter >= SLEEP_DURATION; +} + +float Player::getSleepRotation() { + if(isSleeping()) { + int data = level->getData(bedPosition.x, bedPosition.y, bedPosition.z); + int direction = BedTile::getDirection(data); + switch(direction) { + case Direction::SOUTH: + return 90; + case Direction::WEST: + return 0; + case Direction::NORTH: + return 270; + case Direction::EAST: + return 180; + } + } + return 0; +} + +bool Player::checkBed() { + return (level->getTile(bedPosition.x, bedPosition.y, bedPosition.z) == Tile::bed->id); +} + +void Player::tick() { + bool shouldSleep = entityData.getFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); + if(shouldSleep != isSleeping()) { + if(isSleeping()) { + stopSleepInBed(true, true, true); + } else { + bedPosition = entityData.getPos(DATA_BED_POSITION_ID); + startSleepInBed(bedPosition.x, bedPosition.y, bedPosition.z); + } + } + if(isSleeping()) { + sleepCounter++; + if(sleepCounter > SLEEP_DURATION) { + sleepCounter = SLEEP_DURATION; + } + if(!level->isClientSide) { + if(!checkBed()) { + stopSleepInBed(true, true, false); + } else if(level->isDay()) { + stopSleepInBed(false, true, true); + } + } + } else if(sleepCounter > 0) { + sleepCounter++; + if(sleepCounter >= (SLEEP_DURATION + WAKE_UP_DURATION)) { + sleepCounter = 0; + } + } + super::tick(); + + if (!level->isClientSide) { + foodData.tick(this); + // if (containerMenu != NULL && !containerMenu->stillValid(this)) { + // closeContainer(); + // } + } +} + +int Player::getMaxHealth() { + return MAX_HEALTH; +} + +// +// Use items +// +bool Player::isUsingItem() { + return !useItem.isNull(); +} + +ItemInstance* Player::getUseItem() { + return &useItem; +} + +void Player::spawnEatParticles(const ItemInstance* useItem, int count) { + if (useItem->getUseAnimation() == UseAnim::drink) { + level->playSound(this, "random.drink", 0.5f, level->random.nextFloat() * 0.1f + 0.9f); + } + else if (useItem->getUseAnimation() == UseAnim::eat) { + for (int i = 0; i < count; i++) { + const float xx = -xRot * Mth::PI / 180; + const float yy = -yRot * Mth::PI / 180; + Vec3 d((random.nextFloat() - 0.5f) * 0.1f, Mth::random() * 0.1f + 0.1f, 0); + d.xRot(xx); + d.yRot(yy); + Vec3 p((random.nextFloat() - 0.5f) * 0.3f, -random.nextFloat() * 0.6f - 0.3f, 0.6f); + p.xRot(xx); + p.yRot(yy); + p = p.add(x, y + getHeadHeight(), z); + level->addParticle(PARTICLETYPE(iconcrack), p.x, p.y, p.z, d.x, d.y + 0.05f, d.z, useItem->getItem()->id); + } + level->playSound(this, "random.eat", .5f + .5f * random.nextInt(2), (random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); + } +} + +void Player::startUsingItem(ItemInstance instance, int duration) { + if(instance == useItem) return; + useItem = instance; + useItemDuration = duration; + if(!level->isClientSide) { + setSharedFlag(SharedFlagsInformation::FLAG_USINGITEM, true); + } +} + +void Player::stopUsingItem() { + if(getCarriedItem() != NULL && useItem.id == getCarriedItem()->id) + getCarriedItem()->setAuxValue(useItem.getAuxValue()); + useItem.setNull(); + useItemDuration = 0; + if(!level->isClientSide) { + setSharedFlag(SharedFlagsInformation::FLAG_USINGITEM, false); + } +} + +void Player::releaseUsingItem() { + if(!useItem.isNull()) { + useItem.releaseUsing(level, this, useItemDuration); + } + stopUsingItem(); +} + +void Player::completeUsingItem() { + if(!useItem.isNull()) { + spawnEatParticles(&useItem, 10); + + // Check if the item is valid, and if we should overwrite the + // inventory item afterwards. + ItemInstance* selected = inventory->getSelected(); + bool doOverwrite = selected && ItemInstance::matches(&useItem, selected); + + ItemInstance itemInstance = useItem.useTimeDepleted(level, this); + + if (doOverwrite) { + *selected = useItem; + if (selected->count == 0) + inventory->clearSlot(inventory->selected); + } + + /* + int oldCount = useItem.count; + if (!itemInstance.matches(&useItem)) { + ItemInstance* selected = inventory->getSelected(); + if (ItemInstance::matches(&useItem, selected)) { + if (selected) *selected = itemInstance; + if (itemInstance.count == 0) { + inventory->clearSlot(inventory->selected); + } + } + } + */ + + stopUsingItem(); + } +} + +int Player::getUseItemDuration() { + return useItemDuration; +} + +int Player::getTicksUsingItem() { + if(isUsingItem()) { + return useItem.getUseDuration() - useItemDuration; + } + return 0; +} + +void Player::travel(float xa, float ya) { + if (abilities.flying) { + float ydo = yd; + float ofs = flyingSpeed; + flyingSpeed = 0.05f; + super::travel(xa, ya); + yd = ydo * 0.6f; + flyingSpeed = ofs; + } else { + super::travel(xa, ya); + } +} + +/*protected*/ +bool Player::isImmobile() { + return health <= 0 || isSleeping(); +} + +/*protected*/ +void Player::closeContainer() { + containerMenu = NULL; + //containerMenu = inventoryMenu; +} + +void Player::resetPos(bool clearMore) { + if(!isSleeping()) { + heightOffset = 1.62f; + setSize(0.6f, 1.8f); + super::resetPos(clearMore); + } + invisible = false; + + if (clearMore) { + health = getMaxHealth(); + deathTime = 0; + playerIsSleeping = false; + } +} + +/*protected*/ +void Player::updateAi() { + updateAttackAnim(); +} + +int Player::getItemInHandIcon(ItemInstance* item, int layer) { + int icon = item->getIcon(); + if(useItem.id != 0 && item->id == Item::bow->id) { + int ticksHeld = (item->getUseDuration() - useItemDuration); + if(ticksHeld >= BowItem::MAX_DRAW_DURATION - 2) { + return 5 + 8 * 16; + } + if(ticksHeld > (2 * BowItem::MAX_DRAW_DURATION) / 3) { + return 5 + 7*16; + } + if(ticksHeld > 0) { + return 5 + 6 * 16; + } + } + return icon; +} + +void Player::aiStep() { + if (level->difficulty == Difficulty::PEACEFUL && health < MAX_HEALTH) { + if (tickCount % (12 * SharedConstants::TicksPerSecond) == 0) heal(1); + } + //inventory.tick(); + oBob = bob; + // moved the super::aiStep() part to the local player + + float tBob = (float) Mth::sqrt(xd * xd + zd * zd); + float tTilt = (float) Mth::atan(-yd * 0.2f) * 15.f; + if (tBob > 0.1f) tBob = 0.1f; + if (!onGround || health <= 0) tBob = 0; + if (onGround || health <= 0) tTilt = 0; + bob += (tBob - bob) * 0.4f; + tilt += (tTilt - tilt) * 0.8f; + + if (health > 0) { + EntityList& entities = level->getEntities(this, bb.grow(1, 0, 1)); + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + if (!e->removed) { + touch(e); + } + } + } +} + +/*private*/ +void Player::touch(Entity* entity) { + entity->playerTouch(this); +} + +int Player::getScore() { + return score; +} + +void Player::die(Entity* source) { + super::die(source); + this->setSize(0.2f, 0.2f); + setPos(x, y, z); + yd = 0.1f; + + //inventory->dropAll(level->isClientSide); + + if (source != NULL) { + xd = -(float) Mth::cos((hurtDir + yRot) * Mth::PI / 180) * 0.1f; + zd = -(float) Mth::sin((hurtDir + yRot) * Mth::PI / 180) * 0.1f; + } else { + xd = zd = 0; + } + this->heightOffset = 0.1f; +} + +void Player::reset() { + super::reset(); + this->_init(); +} + +void Player::_init() { + oBob = bob = 0; + swinging = 0; + swingTime = 0; + score = 0; +} + +float Player::getWalkingSpeedModifier() { + return 1.0f; +} + + +void Player::awardKillScore(Entity* victim, int score) { + this->score += score; +} + +bool Player::isShootable() { + return true; +} + +bool Player::isCreativeModeAllowed() { + return true; +} + +//void Player::drop() { +// //drop(inventory.removeItem(inventory.selected, 1), false); +//} + +void Player::drop(ItemInstance* item) { + drop(item, false); +} + +void Player::drop(ItemInstance* item, bool randomly) { + if (item == NULL || item->isNull()) + return; + + ItemEntity* thrownItem = new ItemEntity(level, x, y - 0.3f + getHeadHeight(), z, *item); + { //@todo:itementity + delete item; + item = NULL; + } + thrownItem->throwTime = 20 * 2; + + float pow = 0.1f; + if (randomly) { + float _pow = random.nextFloat() * 0.5f; + float dir = random.nextFloat() * Mth::PI * 2; + thrownItem->xd = -Mth::sin(dir) * _pow; + thrownItem->zd = Mth::cos(dir) * _pow; + thrownItem->yd = 0.2f; + + } else { + pow = 0.3f; + thrownItem->xd = -Mth::sin(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * pow; + thrownItem->zd = Mth::cos(yRot / 180 * Mth::PI) * Mth::cos(xRot / 180 * Mth::PI) * pow; + thrownItem->yd = -Mth::sin(xRot / 180 * Mth::PI) * pow + 0.1f; + pow = 0.02f; + + float dir = random.nextFloat() * Mth::PI * 2; + pow *= random.nextFloat(); + thrownItem->xd += Mth::cos(dir) * pow; + thrownItem->yd += (random.nextFloat() - random.nextFloat()) * 0.1f; + thrownItem->zd += Mth::sin(dir) * pow; + } + + reallyDrop(thrownItem); +} + +/*protected*/ +void Player::reallyDrop(ItemEntity* thrownItem) { + level->addEntity(thrownItem); +} + +float Player::getDestroySpeed(Tile* tile) { + float speed = inventory->getDestroySpeed(tile); + //if (isUnderLiquid(Material.water)) speed /= 5; + //if (!onGround) speed /= 5; + return speed; +} + +bool Player::canDestroy(Tile* tile) { + return inventory->canDestroy(tile); +} + +//@SuppressWarnings("unchecked") +void Player::readAdditionalSaveData(CompoundTag* entityTag) { + super::readAdditionalSaveData(entityTag); + + if (entityTag->contains("Inventory", Tag::TAG_List)) { + ListTag* inventoryList = entityTag->getList("Inventory"); + inventory->load(inventoryList); + } + if (entityTag->contains("Armor", Tag::TAG_List)) { + loadArmor(armor, entityTag->getList("Armor")); + } + + dimension = entityTag->getInt("Dimension"); + + //return; + if(entityTag->contains("Sleeping") && entityTag->contains("SleepTimer") + && entityTag->contains("BedPositionX") && entityTag->contains("BedPositionY") && entityTag->contains("BedPositionZ")) { + playerIsSleeping = entityTag->getBoolean("Sleeping"); + sleepCounter = entityTag->getShort("SleepTimer"); + bedPosition = Pos(entityTag->getInt("BedPositionX"), entityTag->getInt("BedPositionY"), entityTag->getInt("BedPositionZ")); + } else { + playerIsSleeping = false; + bedPosition = Pos(0,0,0); + } + + if(!playerIsSleeping) { + stopSleepInBed(true, true, false); + entityData.clearFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); + } else { + playerIsSleeping = false; + startSleepInBed(bedPosition.x, bedPosition.y, bedPosition.z); + entityData.setFlag(DATA_PLAYER_FLAGS_ID, PLAYER_SLEEP_FLAG); + } + entityData.set(DATA_BED_POSITION_ID, bedPosition); + if (entityTag->contains("SpawnX") && entityTag->contains("SpawnY") && entityTag->contains("SpawnZ")) { + respawnPosition.set(entityTag->getInt("SpawnX"), entityTag->getInt("SpawnY"), entityTag->getInt("SpawnZ")); + } + playerHasRespawnPosition = respawnPosition.y >= 0; +} + +void Player::addAdditonalSaveData(CompoundTag* entityTag) { + super::addAdditonalSaveData(entityTag); + + ListTag* inventoryTag = inventory->save(new ListTag()); + // if (inventoryTag->size() > 0) + entityTag->put("Inventory", inventoryTag); + //else + // delete inventoryTag; + + ListTag* armorTag = saveArmor(armor); + entityTag->put("Armor", armorTag); + + entityTag->putInt("Dimension", dimension); + //return; + + entityTag->putBoolean("Sleeping", isSleeping()); + entityTag->putShort("SleepTimer", sleepCounter); + entityTag->putInt("BedPositionX", bedPosition.x); + entityTag->putInt("BedPositionY", bedPosition.y); + entityTag->putInt("BedPositionZ", bedPosition.z); + + entityTag->putInt("SpawnX", respawnPosition.x); + entityTag->putInt("SpawnY", respawnPosition.y); + entityTag->putInt("SpawnZ", respawnPosition.z); +} + +//static Pos getRespawnPosition(Level level, CompoundTag entityTag) { +// if (entityTag.contains("SpawnX") && entityTag.contains("SpawnY") && entityTag.contains("SpawnZ")) { +// return /*new*/ Pos(entityTag.getInt("SpawnX"), entityTag.getInt("SpawnY"), entityTag.getInt("SpawnZ")); +// } +// return level.getSharedSpawnPos(); +//} + +void Player::startCrafting(int x, int y, int z, int tableSize) { +} + +void Player::startStonecutting(int x, int y, int z) { +} + +void Player::openFurnace(FurnaceTileEntity* e) { +} + +void Player::take(Entity* e, int orgCount) { +} + +float Player::getHeadHeight() { + return 0.12f; // heightOffset; // 0.12f; +} + +/*protected*/ +void Player::setDefaultHeadHeight() { + heightOffset = 1.62f; +} + +bool Player::isHurt() { + return health > 0 && health < getMaxHealth(); +} + +bool Player::hurt(Entity* source, int dmg) { + if (abilities.invulnerable) return false; + + noActionTime = 0; + if (health <= 0) return false; + if(isSleeping() && !level->isClientSide) { + stopSleepInBed(true, true, false); + } + + if (source != NULL && (source->getCreatureBaseType() == MobTypes::BaseEnemy + || source->getEntityTypeId() == EntityTypes::IdArrow)) { + + if (source->isMob() && level->adventureSettings.noMvP) + return false; + + if (level->difficulty == Difficulty::PEACEFUL) dmg = 0; + else if (level->difficulty == Difficulty::EASY) dmg = dmg / 3 + 1; + else if (level->difficulty == Difficulty::HARD) dmg = dmg * 3 / 2; + } + + if (dmg == 0) return false; + + // Entity* attacker = source; + // //if (attacker instanceof Arrow) { + // // if (((Arrow) attacker).owner != NULL) { + // // attacker = ((Arrow) attacker).owner; + // // } + // //} + return super::hurt(source, dmg); +} + +void Player::interact(Entity* entity) { + if (entity->interact(this)) return; + ItemInstance* item = inventory->getSelected(); + if (item != NULL && entity->isMob()) { + item->interactEnemy((Mob*)entity); + if (item->count <= 0) { + //item.snap(this); + inventory->clearSlot(inventory->selected); + } + } +} + +//void Player::swing() { + //LOGI("swinging: %d\n", swinging); +// if (!swinging || swingTime >= 3 || swingTime < 0) { +// swingTime = -1; +// swinging = true; +// } + + //level->raknetInstance->send(owner, new AnimatePacket(AnimatePacket::Swing, this)); + //} +//} + +void Player::attack(Entity* entity) { + int dmg = inventory->getAttackDamage(entity); + if (dmg > 0) { + entity->hurt(this, dmg); + ItemInstance* item = inventory->getSelected(); + if (item != NULL && entity->isMob() && abilities.instabuild != true) { + item->hurtEnemy((Mob*) entity); + if (item->count <= 0) { + //item->snap(this); + inventory->clearSlot(inventory->selected); + } + } + } +} + +void Player::respawn() { +} + +/*protected static*/ +void Player::animateRespawn(Player* player, Level* level) { + //for (int i = 0; i < 45; i++) { + // float angle = i * Mth::PI * 4.0f / 25.0f; + // float xo = Mth::cos(angle) * .7f; + // float zo = Mth::sin(angle) * .7f; + //} +} + +/*virtual*/ +void Player::animateRespawn() {} + +//void carriedChanged(ItemInstance carried) { +//} +ItemInstance* Player::getCarriedItem() { + return inventory->getSelected(); +} + +void Player::remove() { + invisible = true; + super::remove(); +} + +//@Override +bool Player::isInWall() { + return super::isInWall(); +} + +bool Player::hasResource( int id ) { + return inventory->hasResource(id); +} + +/** + * This method is currently only relevant to client-side players. It will + * try to load the messageId from the language file and display it to the + * client. + */ +void Player::displayClientMessage(const std::string& messageId) { +} + +Pos Player::getRespawnPosition() { + return respawnPosition; +} + +void Player::setRespawnPosition(const Pos& respawnPosition) { // @attn WARNING CHECK THIS THROUGH @fix @todo: rewrite + if (respawnPosition.y < 0) { + playerHasRespawnPosition = false; + } + else { + playerHasRespawnPosition = true; + } + this->respawnPosition = respawnPosition; +} + +bool Player::isPlayer() { return true; } + +/*static*/ +bool Player::isPlayer( Entity* e ) { + return e && e->isPlayer(); +} + +Player* Player::asPlayer( Entity* e ) { + return isPlayer(e)? (Player*) e : NULL; +} + +void Player::openContainer(ChestTileEntity* container) +{ +} + +void Player::tileEntityDestroyed( int tileEntityId ) { + + //LOGI("TileEntityDestroyed, container: %p, %p\n", this, containerMenu); + + if (!containerMenu) return; + + //LOGI("TileEntityDestroyed, id: %d, %p, %d\n", this, tileEntityId, ((FurnaceMenu*)containerMenu)->furnaceTileEntityId); + + if (containerMenu->tileEntityDestroyedIsInvalid(tileEntityId)) + closeContainer(); +} + +bool Player::canUseCarriedItemWhileMoving() { + ItemInstance* item = getCarriedItem(); + return item && + ( item->id == Item::bow->id + || item->getItem()->isFood()); +} + +void Player::handleEntityEvent( char id ) { + if (id == EntityEvent::USE_ITEM_COMPLETE) { + completeUsingItem(); + } else { + super::handleEntityEvent(id); + } +} + +ItemInstance* Player::getSelectedItem() { + return inventory->getSelected(); +} + +bool Player::hasRespawnPosition(){ + return playerHasRespawnPosition; +} + +void Player::openTextEdit( TileEntity* tileEntity ) { + // Do nothing on the server, this is a client thing :) +} + +// +// Armor code. Move this out to an ArmorInventory +// +static ListTag* saveArmor(ItemInstance* armor) { + ListTag* listTag = new ListTag(); + for (int i = 0; i < 4; ++i) { + CompoundTag* tag = new CompoundTag(); + armor[i].save(tag); + listTag->add(tag); + } + return listTag; +} + +static void loadArmor(ItemInstance* armor, ListTag* listTag) { + if (!listTag) + return; + + const int count = Mth::Min(4, listTag->size()); + for (int i = 0; i < count; ++i) { + Tag* tag = listTag->get(i); + if (tag->getId() != Tag::TAG_Compound) continue; + + armor[i].load((CompoundTag*) tag); + } +} + +ItemInstance* Player::getArmor(int slot) { + if (slot < 0 || slot >= NUM_ARMOR) + return NULL; + + if (armor[slot].isNull()) + return NULL; + + return &armor[slot]; +} + +void Player::setArmor(int slot, const ItemInstance* item) { + if (item == NULL) + armor[slot].setNull(); + else { + armor[slot] = *item; + } +} + +void Player::hurtArmor( int dmg ) { + dmg = Mth::Max(1, dmg / 4); + + for (int i = 0; i < NUM_ARMOR; i++) { + ItemInstance& item = armor[i]; + if (!ItemInstance::isArmorItem(&item)) + continue; + + item.hurt(dmg); + if (item.count == 0) { + item.setNull(); + } + } +} + +int Player::getArmorTypeHash() { + return (armor[0].id ) + + (armor[1].id << 8) + + (armor[2].id << 16) + + (armor[3].id << 24); +} + +int Player::getArmorValue() { + int val = 0; + + for (int i = 0; i < NUM_ARMOR; i++) { + ItemInstance& item = armor[i]; + if (!ItemInstance::isArmorItem(&item)) + continue; + + int baseProtection = ((ArmorItem*) item.getItem())->defense; + val += baseProtection; + } + return val; +} + diff --git a/src/world/entity/player/Player.h b/src/world/entity/player/Player.hpp similarity index 96% rename from src/world/entity/player/Player.h rename to src/world/entity/player/Player.hpp index a6f6ce6..3053c26 100755 --- a/src/world/entity/player/Player.h +++ b/src/world/entity/player/Player.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.entity.player; -#include "Abilities.h" -#include "../Mob.h" -#include "../../Pos.h" -#include "../../food/SimpleFoodData.h" -#include "../../item/crafting/Recipe.h" +#include "Abilities.hpp" +#include "world/entity/Mob.hpp" +#include "world/Pos.hpp" +#include "world/food/SimpleFoodData.hpp" +#include "world/item/crafting/Recipe.hpp" class Tile; class ItemEntity; diff --git a/src/world/entity/projectile/Arrow.cpp b/src/world/entity/projectile/Arrow.cpp index 473fb29..b347f10 100755 --- a/src/world/entity/projectile/Arrow.cpp +++ b/src/world/entity/projectile/Arrow.cpp @@ -1,346 +1,346 @@ -#include "Arrow.h" -#include "../Mob.h" -#include "../player/Player.h" -#include "../../item/Item.h" -#include "../../item/ItemInstance.h" -#include "../../level/Level.h" -#include "../../level/tile/Tile.h" -#include "../../../util/Mth.h" - -#include "../../../nbt/CompoundTag.h" - -const float Arrow::ARROW_BASE_DAMAGE = 2.0f; - -Arrow::Arrow( Level* level ) -: super(level), - playerArrow(false), - ownerId(0) -{ - _init(); -} - -Arrow::Arrow( Level* level, float x, float y, float z ) -: super(level), - playerArrow(false), - ownerId(0) -{ - _init(); - - this->setPos(x, y, z); - this->heightOffset = 0; -} - -Arrow::Arrow( Level* level, Mob* mob, float power ) -: super(level), - ownerId(mob->entityId), - playerArrow(mob->isPlayer()) -{ - _init(); - - moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); - - const float dx = Mth::cos(yRot * Mth::DEGRAD); - const float dz = Mth::sin(yRot * Mth::DEGRAD); - x -= dx * 0.16f; - y -= 0.1f; - z -= dz * 0.16f; - this->setPos(x, y, z); - this->heightOffset = 0; - - const float dxx = Mth::cos(xRot / 180 * Mth::PI); - xd = -dz * dxx; - zd = dx * dxx; - yd = -Mth::sin(xRot / 180 * Mth::PI); - - shoot(xd, yd, zd, power * 1.5f, 1); -} - -void Arrow::_init() -{ - entityRendererId = ER_ARROW_RENDERER; - setSize(0.5f, 0.5f); - - shakeTime = 0; - critArrow = false; - - xTile = -1; - yTile = -1; - zTile = -1; - lastTile = 0; - lastData = 0; - inGround = false; - life = 0; - flightTime = 0; -} - -void Arrow::shoot( float xd, float yd, float zd, float pow, float uncertainty ) -{ - float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd); - - xd /= dist; - yd /= dist; - zd /= dist; - - const float radius = 0.0075f * uncertainty; - xd += sharedRandom.nextGaussian() * radius; - yd += sharedRandom.nextGaussian() * radius; - zd += sharedRandom.nextGaussian() * radius; - - xd *= pow; - yd *= pow; - zd *= pow; - - this->xd = xd; - this->yd = yd; - this->zd = zd; - - float sd = (float) Mth::sqrt(xd * xd + zd * zd); - - yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG); - xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG); - life = 0; -} - -void Arrow::lerpMotion( float xd, float yd, float zd ) -{ - this->xd = xd; - this->yd = yd; - this->zd = zd; - if (xRotO == 0 && yRotO == 0) { - float sd = (float) Mth::sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG); - xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG); - moveTo(x, y, z, yRot, xRot); - life = 0; - } -} - -void Arrow::tick() -{ - super::tick(); - - if (xRotO == 0 && yRotO == 0) { - float sd = (float) Mth::sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG); - xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG); - } - - - { - int t = level->getTile(xTile, yTile, zTile); - if (t > 0) { - Tile::tiles[t]->updateShape(level, xTile, yTile, zTile); - AABB* aabb = Tile::tiles[t]->getAABB(level, xTile, yTile, zTile); - if (aabb != NULL && aabb->contains(Vec3(x, y, z))) { - inGround = true; - } - } - } - - if (shakeTime > 0) shakeTime--; - - if (inGround) { - // xd = 0; - // yd = 0; - // zd = 0; - int tile = level->getTile(xTile, yTile, zTile); - int data = level->getData(xTile, yTile, zTile); - if (tile != lastTile || data != lastData) { - inGround = false; - - xd *= sharedRandom.nextFloat() * 0.2f; - yd *= sharedRandom.nextFloat() * 0.2f; - zd *= sharedRandom.nextFloat() * 0.2f; - life = 0; - flightTime = 0; - return; - } else { - if (++life == 60 * SharedConstants::TicksPerSecond) remove(); - return; - } - } else { - flightTime++; - } - - Vec3 from(x, y, z); - Vec3 to(x + xd, y + yd, z + zd); - HitResult res = level->clip(from, to, false, true); - - from.set(x, y, z); - to.set(x + xd, y + yd, z + zd); - if (res.isHit()) { - to.set(res.pos.x, res.pos.y, res.pos.z); - } - Entity* hitEntity = NULL; - EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1)); - float nearest = 0; - for (unsigned int i = 0; i < objects.size(); i++) { - Entity* e = objects[i]; - if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue; - - float rr = 0.3f; - AABB bb = e->bb.grow(rr, rr, rr); - HitResult p = bb.clip(from, to); - if (p.isHit()) { - float dd = from.distanceTo(p.pos); - if (dd < nearest || nearest == 0) { - hitEntity = e; - nearest = dd; - } - } - } - - if (hitEntity != NULL) { - res = HitResult(hitEntity); - } - - if (res.isHit()) { - if (res.type == ENTITY) { - float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd); - int dmg = (int) std::ceil(pow * ARROW_BASE_DAMAGE); - - if (critArrow) dmg += sharedRandom.nextInt(dmg / 2 + 2); - - //@todo - //DamageSource damageSource = NULL; - //if (owner == NULL) { - // damageSource = DamageSource.arrow(this, this); - //} else { - // damageSource = DamageSource.arrow(this, owner); - //} - - //if (res.entity->hurt(damageSource, dmg)) { - // if (res.entity instanceof Mob) { - - if (res.entity->hurt(this, dmg)) { - if (res.entity->isMob()) { - ((Mob*) res.entity)->arrowCount++; - } - level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f)); - remove(); - } else { - xd *= -0.1f; - yd *= -0.1f; - zd *= -0.1f; - yRot += 180; - yRotO += 180; - flightTime = 0; - } - } else { - xTile = res.x; - yTile = res.y; - zTile = res.z; - lastTile = level->getTile(xTile, yTile, zTile); - lastData = level->getData(xTile, yTile, zTile); - xd = (float) (res.pos.x - x); - yd = (float) (res.pos.y - y); - zd = (float) (res.pos.z - z); - float dd = Mth::sqrt(xd * xd + yd * yd + zd * zd); - x -= (xd / dd) * 0.05f; - y -= (yd / dd) * 0.05f; - z -= (zd / dd) * 0.05f; - - level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f)); - inGround = true; - shakeTime = 7; - critArrow = false; - } - } - - - if (critArrow) { - for (int i = 0; i < 4; i++) { - level->addParticle(PARTICLETYPE(crit), x + xd * i / 4.0f, y + yd * i / 4.0f, z + zd * i / 4.0f, -xd, -yd + 0.2f, -zd); - } - } - - x += xd; - y += yd; - z += zd; - - float sd = Mth::sqrt(xd * xd + zd * zd); - yRot = std::atan2(xd, zd) * Mth::RADDEG; - xRot = std::atan2(yd, sd) * Mth::RADDEG; - - while (xRot - xRotO < -180) - xRotO -= 360; - while (xRot - xRotO >= 180) - xRotO += 360; - - while (yRot - yRotO < -180) - yRotO -= 360; - while (yRot - yRotO >= 180) - yRotO += 360; - - xRot = xRotO + (xRot - xRotO) * 0.2f; - yRot = yRotO + (yRot - yRotO) * 0.2f; - - - float inertia = 0.99f; - float gravity = 0.05f; - - if (isInWater()) { - for (int i = 0; i < 4; i++) { - float s = 1 / 4.0f; - level->addParticle(PARTICLETYPE(bubble), x - xd * s, y - yd * s, z - zd * s, xd, yd, zd); - } - inertia = 0.80f; - } - - xd *= inertia; - yd *= inertia; - zd *= inertia; - yd -= gravity; - - setPos(x, y, z); -} - -void Arrow::addAdditonalSaveData( CompoundTag* tag ) -{ - tag->putShort("xTile", (short) xTile); - tag->putShort("yTile", (short) yTile); - tag->putShort("zTile", (short) zTile); - tag->putByte("inTile", (char) lastTile); - tag->putByte("inData", (char) lastData); - tag->putByte("shake", (char) shakeTime); - tag->putByte("inGround", (char) (inGround ? 1 : 0)); - tag->putBoolean("player", playerArrow); -} - -void Arrow::readAdditionalSaveData( CompoundTag* tag ) -{ - xTile = tag->getShort("xTile"); - yTile = tag->getShort("yTile"); - zTile = tag->getShort("zTile"); - lastTile = tag->getByte("inTile") & 0xff; - lastData = tag->getByte("inData") & 0xff; - shakeTime = tag->getByte("shake") & 0xff; - inGround = tag->getByte("inGround") == 1; - playerArrow = tag->getBoolean("player"); -} - -void Arrow::playerTouch( Player* player ) -{ - if (level->isClientSide) return; - - if (inGround && playerArrow && shakeTime <= 0) { - ItemInstance item(Item::arrow, 1); - if (player->inventory->add(&item)) { - level->playSound(this, "random.pop", 0.2f, ((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f + 1.0f) * 2.f); - player->take(this, 1); - remove(); - } - } -} - -float Arrow::getShadowHeightOffs() { - return 0; -} - -int Arrow::getEntityTypeId() const { - return EntityTypes::IdArrow; -} - -int Arrow::getAuxData() { - return ownerId; -} +#include "Arrow.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Mth.hpp" + +#include "nbt/CompoundTag.hpp" + +const float Arrow::ARROW_BASE_DAMAGE = 2.0f; + +Arrow::Arrow( Level* level ) +: super(level), + playerArrow(false), + ownerId(0) +{ + _init(); +} + +Arrow::Arrow( Level* level, float x, float y, float z ) +: super(level), + playerArrow(false), + ownerId(0) +{ + _init(); + + this->setPos(x, y, z); + this->heightOffset = 0; +} + +Arrow::Arrow( Level* level, Mob* mob, float power ) +: super(level), + ownerId(mob->entityId), + playerArrow(mob->isPlayer()) +{ + _init(); + + moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); + + const float dx = Mth::cos(yRot * Mth::DEGRAD); + const float dz = Mth::sin(yRot * Mth::DEGRAD); + x -= dx * 0.16f; + y -= 0.1f; + z -= dz * 0.16f; + this->setPos(x, y, z); + this->heightOffset = 0; + + const float dxx = Mth::cos(xRot / 180 * Mth::PI); + xd = -dz * dxx; + zd = dx * dxx; + yd = -Mth::sin(xRot / 180 * Mth::PI); + + shoot(xd, yd, zd, power * 1.5f, 1); +} + +void Arrow::_init() +{ + entityRendererId = ER_ARROW_RENDERER; + setSize(0.5f, 0.5f); + + shakeTime = 0; + critArrow = false; + + xTile = -1; + yTile = -1; + zTile = -1; + lastTile = 0; + lastData = 0; + inGround = false; + life = 0; + flightTime = 0; +} + +void Arrow::shoot( float xd, float yd, float zd, float pow, float uncertainty ) +{ + float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd); + + xd /= dist; + yd /= dist; + zd /= dist; + + const float radius = 0.0075f * uncertainty; + xd += sharedRandom.nextGaussian() * radius; + yd += sharedRandom.nextGaussian() * radius; + zd += sharedRandom.nextGaussian() * radius; + + xd *= pow; + yd *= pow; + zd *= pow; + + this->xd = xd; + this->yd = yd; + this->zd = zd; + + float sd = (float) Mth::sqrt(xd * xd + zd * zd); + + yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG); + xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG); + life = 0; +} + +void Arrow::lerpMotion( float xd, float yd, float zd ) +{ + this->xd = xd; + this->yd = yd; + this->zd = zd; + if (xRotO == 0 && yRotO == 0) { + float sd = (float) Mth::sqrt(xd * xd + zd * zd); + yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG); + xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG); + moveTo(x, y, z, yRot, xRot); + life = 0; + } +} + +void Arrow::tick() +{ + super::tick(); + + if (xRotO == 0 && yRotO == 0) { + float sd = (float) Mth::sqrt(xd * xd + zd * zd); + yRotO = this->yRot = (float) (std::atan2(xd, zd) * Mth::RADDEG); + xRotO = this->xRot = (float) (std::atan2(yd, sd) * Mth::RADDEG); + } + + + { + int t = level->getTile(xTile, yTile, zTile); + if (t > 0) { + Tile::tiles[t]->updateShape(level, xTile, yTile, zTile); + AABB* aabb = Tile::tiles[t]->getAABB(level, xTile, yTile, zTile); + if (aabb != NULL && aabb->contains(Vec3(x, y, z))) { + inGround = true; + } + } + } + + if (shakeTime > 0) shakeTime--; + + if (inGround) { + // xd = 0; + // yd = 0; + // zd = 0; + int tile = level->getTile(xTile, yTile, zTile); + int data = level->getData(xTile, yTile, zTile); + if (tile != lastTile || data != lastData) { + inGround = false; + + xd *= sharedRandom.nextFloat() * 0.2f; + yd *= sharedRandom.nextFloat() * 0.2f; + zd *= sharedRandom.nextFloat() * 0.2f; + life = 0; + flightTime = 0; + return; + } else { + if (++life == 60 * SharedConstants::TicksPerSecond) remove(); + return; + } + } else { + flightTime++; + } + + Vec3 from(x, y, z); + Vec3 to(x + xd, y + yd, z + zd); + HitResult res = level->clip(from, to, false, true); + + from.set(x, y, z); + to.set(x + xd, y + yd, z + zd); + if (res.isHit()) { + to.set(res.pos.x, res.pos.y, res.pos.z); + } + Entity* hitEntity = NULL; + EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1)); + float nearest = 0; + for (unsigned int i = 0; i < objects.size(); i++) { + Entity* e = objects[i]; + if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue; + + float rr = 0.3f; + AABB bb = e->bb.grow(rr, rr, rr); + HitResult p = bb.clip(from, to); + if (p.isHit()) { + float dd = from.distanceTo(p.pos); + if (dd < nearest || nearest == 0) { + hitEntity = e; + nearest = dd; + } + } + } + + if (hitEntity != NULL) { + res = HitResult(hitEntity); + } + + if (res.isHit()) { + if (res.type == ENTITY) { + float pow = Mth::sqrt(xd * xd + yd * yd + zd * zd); + int dmg = (int) std::ceil(pow * ARROW_BASE_DAMAGE); + + if (critArrow) dmg += sharedRandom.nextInt(dmg / 2 + 2); + + //@todo + //DamageSource damageSource = NULL; + //if (owner == NULL) { + // damageSource = DamageSource.arrow(this, this); + //} else { + // damageSource = DamageSource.arrow(this, owner); + //} + + //if (res.entity->hurt(damageSource, dmg)) { + // if (res.entity instanceof Mob) { + + if (res.entity->hurt(this, dmg)) { + if (res.entity->isMob()) { + ((Mob*) res.entity)->arrowCount++; + } + level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f)); + remove(); + } else { + xd *= -0.1f; + yd *= -0.1f; + zd *= -0.1f; + yRot += 180; + yRotO += 180; + flightTime = 0; + } + } else { + xTile = res.x; + yTile = res.y; + zTile = res.z; + lastTile = level->getTile(xTile, yTile, zTile); + lastData = level->getData(xTile, yTile, zTile); + xd = (float) (res.pos.x - x); + yd = (float) (res.pos.y - y); + zd = (float) (res.pos.z - z); + float dd = Mth::sqrt(xd * xd + yd * yd + zd * zd); + x -= (xd / dd) * 0.05f; + y -= (yd / dd) * 0.05f; + z -= (zd / dd) * 0.05f; + + level->playSound(this, "random.bowhit", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f)); + inGround = true; + shakeTime = 7; + critArrow = false; + } + } + + + if (critArrow) { + for (int i = 0; i < 4; i++) { + level->addParticle(PARTICLETYPE(crit), x + xd * i / 4.0f, y + yd * i / 4.0f, z + zd * i / 4.0f, -xd, -yd + 0.2f, -zd); + } + } + + x += xd; + y += yd; + z += zd; + + float sd = Mth::sqrt(xd * xd + zd * zd); + yRot = std::atan2(xd, zd) * Mth::RADDEG; + xRot = std::atan2(yd, sd) * Mth::RADDEG; + + while (xRot - xRotO < -180) + xRotO -= 360; + while (xRot - xRotO >= 180) + xRotO += 360; + + while (yRot - yRotO < -180) + yRotO -= 360; + while (yRot - yRotO >= 180) + yRotO += 360; + + xRot = xRotO + (xRot - xRotO) * 0.2f; + yRot = yRotO + (yRot - yRotO) * 0.2f; + + + float inertia = 0.99f; + float gravity = 0.05f; + + if (isInWater()) { + for (int i = 0; i < 4; i++) { + float s = 1 / 4.0f; + level->addParticle(PARTICLETYPE(bubble), x - xd * s, y - yd * s, z - zd * s, xd, yd, zd); + } + inertia = 0.80f; + } + + xd *= inertia; + yd *= inertia; + zd *= inertia; + yd -= gravity; + + setPos(x, y, z); +} + +void Arrow::addAdditonalSaveData( CompoundTag* tag ) +{ + tag->putShort("xTile", (short) xTile); + tag->putShort("yTile", (short) yTile); + tag->putShort("zTile", (short) zTile); + tag->putByte("inTile", (char) lastTile); + tag->putByte("inData", (char) lastData); + tag->putByte("shake", (char) shakeTime); + tag->putByte("inGround", (char) (inGround ? 1 : 0)); + tag->putBoolean("player", playerArrow); +} + +void Arrow::readAdditionalSaveData( CompoundTag* tag ) +{ + xTile = tag->getShort("xTile"); + yTile = tag->getShort("yTile"); + zTile = tag->getShort("zTile"); + lastTile = tag->getByte("inTile") & 0xff; + lastData = tag->getByte("inData") & 0xff; + shakeTime = tag->getByte("shake") & 0xff; + inGround = tag->getByte("inGround") == 1; + playerArrow = tag->getBoolean("player"); +} + +void Arrow::playerTouch( Player* player ) +{ + if (level->isClientSide) return; + + if (inGround && playerArrow && shakeTime <= 0) { + ItemInstance item(Item::arrow, 1); + if (player->inventory->add(&item)) { + level->playSound(this, "random.pop", 0.2f, ((sharedRandom.nextFloat() - sharedRandom.nextFloat()) * 0.7f + 1.0f) * 2.f); + player->take(this, 1); + remove(); + } + } +} + +float Arrow::getShadowHeightOffs() { + return 0; +} + +int Arrow::getEntityTypeId() const { + return EntityTypes::IdArrow; +} + +int Arrow::getAuxData() { + return ownerId; +} diff --git a/src/world/entity/projectile/Arrow.h b/src/world/entity/projectile/Arrow.hpp similarity index 96% rename from src/world/entity/projectile/Arrow.h rename to src/world/entity/projectile/Arrow.hpp index b92cab9..0ba72b8 100755 --- a/src/world/entity/projectile/Arrow.h +++ b/src/world/entity/projectile/Arrow.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.entity.projectile; -#include "../Entity.h" +#include "world/entity/Entity.hpp" class Level; class Mob; diff --git a/src/world/entity/projectile/Snowball.h b/src/world/entity/projectile/Snowball.hpp similarity index 87% rename from src/world/entity/projectile/Snowball.h rename to src/world/entity/projectile/Snowball.hpp index b365d36..4c0e309 100755 --- a/src/world/entity/projectile/Snowball.h +++ b/src/world/entity/projectile/Snowball.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.entity->projectile; -#include "Throwable.h" -#include "../Mob.h" -#include "../../level/Level.h" -#include "../../phys/HitResult.h" +#include "Throwable.hpp" +#include "world/entity/Mob.hpp" +#include "world/level/Level.hpp" +#include "world/phys/HitResult.hpp" class Snowball: public Throwable { diff --git a/src/world/entity/projectile/Throwable.cpp b/src/world/entity/projectile/Throwable.cpp index cf8ac73..c419a9c 100755 --- a/src/world/entity/projectile/Throwable.cpp +++ b/src/world/entity/projectile/Throwable.cpp @@ -1,260 +1,260 @@ -#include "Throwable.h" -#include "../player/Player.h" -#include "../../level/Level.h" -#include "../../../util/Mth.h" -#include "../../phys/HitResult.h" - -Throwable::Throwable( Level* level ) -: super(level) -{ - _init(); - setSize(0.25f, 0.25f); -} - -Throwable::Throwable( Level* level, Mob* mob ) -: super(level) -{ - _init(); - setSize(0.25f, 0.25f); - - ownerId = mob->entityId; - - this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); - - const float rcos = Mth::cos(yRot / 180 * Mth::PI); - const float rsin = Mth::sin(yRot / 180 * Mth::PI); - x -= rcos * 0.16f; - y -= 0.1f; - z -= rsin * 0.16f; - this->setPos(x, y, z); - this->heightOffset = 0; - - if (mob->isPlayer()) { - shoot(mob->aimDirection, getThrowPower(), 1); - } else { - float xd = (-rsin * Mth::cos(xRot / 180 * Mth::PI)); - float zd = ( rcos * Mth::cos(xRot / 180 * Mth::PI)); - float yd = (-Mth::sin((xRot + getThrowUpAngleOffset()) / 180 * Mth::PI)); - shoot(xd, yd, zd, getThrowPower(), 1); - } -} - -Throwable::Throwable( Level* level, float x, float y, float z ) -: super(level) -{ - _init(); - setSize(0.25f, 0.25f); - - this->setPos(x, y, z); - this->heightOffset = 0; -} - -void Throwable::_init() { - ownerId = 0; - shakeTime = 0; - inGround = false; - - life = 0; - flightTime = 0; - xTile = -1; - yTile = -1; - zTile = -1; - lastTile = 0; -} - -bool Throwable::shouldRenderAtSqrDistance( float distance ) { - float size = bb.getSize() * 4; - size *= 64.0f; - return distance < size * size; -} - -float Throwable::getThrowPower() { - return 1.5f; -} - -float Throwable::getThrowUpAngleOffset() { - return 0; -} - -float Throwable::getGravity() { - return 0.03f; -} - -void Throwable::shoot(const Vec3& v, float pow, float uncertainty) { - shoot(v.x, v.y, v.z, pow, uncertainty); -} - -void Throwable::shoot( float xd, float yd, float zd, float pow, float uncertainty ) { - float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd); - - if (dist >= 0.001f) { - xd /= dist; - yd /= dist; - zd /= dist; - } else { - xd = yd = zd = 0; - } - - xd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty; - yd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty; - zd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty; - - xd *= pow; - yd *= pow; - zd *= pow; - - this->xd = xd; - this->yd = yd; - this->zd = zd; - - float sd = (float) Mth::sqrt(xd * xd + zd * zd); - - yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI); - xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI); - life = 0; -} - -void Throwable::lerpMotion( float xd, float yd, float zd ) { - this->xd = xd; - this->yd = yd; - this->zd = zd; - if (xRotO == 0 && yRotO == 0) { - float sd = (float) Mth::sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI); - xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI); - } -} - -void Throwable::tick() { - xOld = x; - yOld = y; - zOld = z; - super::tick(); - - if (shakeTime > 0) shakeTime--; - - if (inGround) { - // xd = 0; - // yd = 0; - // zd = 0; - int tile = level->getTile(xTile, yTile, zTile); - if (tile != lastTile) { - inGround = false; - - xd *= sharedRandom.nextFloat() * 0.2f; - yd *= sharedRandom.nextFloat() * 0.2f; - zd *= sharedRandom.nextFloat() * 0.2f; - life = 0; - flightTime = 0; - } else { - life++; - if (life == 20 * 60) - remove(); - return; - } - } else { - flightTime++; - } - - Vec3 from(x, y, z); - Vec3 to(x + xd, y + yd, z + zd); - HitResult res = level->clip(from, to); - - from.set(x, y, z); - to.set(x + xd, y + yd, z + zd); - if (res.isHit()) - to.set(res.pos.x, res.pos.y, res.pos.z); - - if (!level->isClientSide) { - Entity* hitEntity = NULL; - EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1)); - float nearest = 0; - for (unsigned int i = 0; i < objects.size(); i++) { - Entity* e = objects[i]; - if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue; - - float rr = 0.3f; - AABB bb = e->bb.grow(rr, rr, rr); - HitResult p = bb.clip(from, to); - if (p.isHit()) { - float dd = from.distanceTo(p.pos); - if (dd < nearest || nearest == 0) { - hitEntity = e; - nearest = dd; - } - } - } - - if (hitEntity != NULL) - res = HitResult(hitEntity); - } - - if (res.isHit()) - onHit(res); - - x += xd; - y += yd; - z += zd; - - float sd = Mth::sqrt(xd * xd + zd * zd); - yRot = Mth::atan2(xd, zd) * 180 / Mth::PI; - xRot = Mth::atan2(yd, sd) * 180 / Mth::PI; - - while (xRot - xRotO < -180) - xRotO -= 360; - while (xRot - xRotO >= 180) - xRotO += 360; - - while (yRot - yRotO < -180) - yRotO -= 360; - while (yRot - yRotO >= 180) - yRotO += 360; - - xRot = xRotO + (xRot - xRotO) * 0.2f; - yRot = yRotO + (yRot - yRotO) * 0.2f; - - - float inertia = 0.99f; - float gravity = getGravity(); - - if (isInWater()) { - for (int i = 0; i < 4; i++) { - float s = 1 / 4.0f; - level->addParticle("bubble", x - xd * s, y - yd * s, z - zd * s, xd, yd, zd); - } - inertia = 0.80f; - } - - xd *= inertia; - yd *= inertia; - zd *= inertia; - yd -= gravity; - - setPos(x, y, z); -} - -float Throwable::getShadowHeightOffs() { - return 0; -} - -void Throwable::addAdditonalSaveData( CompoundTag* tag ) { - tag->putShort("xTile", (short) xTile); - tag->putShort("yTile", (short) yTile); - tag->putShort("zTile", (short) zTile); - tag->putByte("inTile", (char) lastTile); - tag->putByte("shake", (char) shakeTime); - tag->putByte("inGround", (char) (inGround ? 1 : 0)); -} - -void Throwable::readAdditionalSaveData( CompoundTag* tag ) { - xTile = tag->getShort("xTile"); - yTile = tag->getShort("yTile"); - zTile = tag->getShort("zTile"); - lastTile = tag->getByte("inTile") & 0xff; - shakeTime = tag->getByte("shake") & 0xff; - inGround = tag->getByte("inGround") == 1; -} - -int Throwable::getAuxData() { - return ownerId; -} +#include "Throwable.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "util/Mth.hpp" +#include "world/phys/HitResult.hpp" + +Throwable::Throwable( Level* level ) +: super(level) +{ + _init(); + setSize(0.25f, 0.25f); +} + +Throwable::Throwable( Level* level, Mob* mob ) +: super(level) +{ + _init(); + setSize(0.25f, 0.25f); + + ownerId = mob->entityId; + + this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); + + const float rcos = Mth::cos(yRot / 180 * Mth::PI); + const float rsin = Mth::sin(yRot / 180 * Mth::PI); + x -= rcos * 0.16f; + y -= 0.1f; + z -= rsin * 0.16f; + this->setPos(x, y, z); + this->heightOffset = 0; + + if (mob->isPlayer()) { + shoot(mob->aimDirection, getThrowPower(), 1); + } else { + float xd = (-rsin * Mth::cos(xRot / 180 * Mth::PI)); + float zd = ( rcos * Mth::cos(xRot / 180 * Mth::PI)); + float yd = (-Mth::sin((xRot + getThrowUpAngleOffset()) / 180 * Mth::PI)); + shoot(xd, yd, zd, getThrowPower(), 1); + } +} + +Throwable::Throwable( Level* level, float x, float y, float z ) +: super(level) +{ + _init(); + setSize(0.25f, 0.25f); + + this->setPos(x, y, z); + this->heightOffset = 0; +} + +void Throwable::_init() { + ownerId = 0; + shakeTime = 0; + inGround = false; + + life = 0; + flightTime = 0; + xTile = -1; + yTile = -1; + zTile = -1; + lastTile = 0; +} + +bool Throwable::shouldRenderAtSqrDistance( float distance ) { + float size = bb.getSize() * 4; + size *= 64.0f; + return distance < size * size; +} + +float Throwable::getThrowPower() { + return 1.5f; +} + +float Throwable::getThrowUpAngleOffset() { + return 0; +} + +float Throwable::getGravity() { + return 0.03f; +} + +void Throwable::shoot(const Vec3& v, float pow, float uncertainty) { + shoot(v.x, v.y, v.z, pow, uncertainty); +} + +void Throwable::shoot( float xd, float yd, float zd, float pow, float uncertainty ) { + float dist = Mth::sqrt(xd * xd + yd * yd + zd * zd); + + if (dist >= 0.001f) { + xd /= dist; + yd /= dist; + zd /= dist; + } else { + xd = yd = zd = 0; + } + + xd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty; + yd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty; + zd += (sharedRandom.nextGaussian()) * 0.0075f * uncertainty; + + xd *= pow; + yd *= pow; + zd *= pow; + + this->xd = xd; + this->yd = yd; + this->zd = zd; + + float sd = (float) Mth::sqrt(xd * xd + zd * zd); + + yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI); + xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI); + life = 0; +} + +void Throwable::lerpMotion( float xd, float yd, float zd ) { + this->xd = xd; + this->yd = yd; + this->zd = zd; + if (xRotO == 0 && yRotO == 0) { + float sd = (float) Mth::sqrt(xd * xd + zd * zd); + yRotO = this->yRot = (float) (Mth::atan2(xd, zd) * 180 / Mth::PI); + xRotO = this->xRot = (float) (Mth::atan2(yd, sd) * 180 / Mth::PI); + } +} + +void Throwable::tick() { + xOld = x; + yOld = y; + zOld = z; + super::tick(); + + if (shakeTime > 0) shakeTime--; + + if (inGround) { + // xd = 0; + // yd = 0; + // zd = 0; + int tile = level->getTile(xTile, yTile, zTile); + if (tile != lastTile) { + inGround = false; + + xd *= sharedRandom.nextFloat() * 0.2f; + yd *= sharedRandom.nextFloat() * 0.2f; + zd *= sharedRandom.nextFloat() * 0.2f; + life = 0; + flightTime = 0; + } else { + life++; + if (life == 20 * 60) + remove(); + return; + } + } else { + flightTime++; + } + + Vec3 from(x, y, z); + Vec3 to(x + xd, y + yd, z + zd); + HitResult res = level->clip(from, to); + + from.set(x, y, z); + to.set(x + xd, y + yd, z + zd); + if (res.isHit()) + to.set(res.pos.x, res.pos.y, res.pos.z); + + if (!level->isClientSide) { + Entity* hitEntity = NULL; + EntityList& objects = level->getEntities(this, this->bb.expand(xd, yd, zd).grow(1, 1, 1)); + float nearest = 0; + for (unsigned int i = 0; i < objects.size(); i++) { + Entity* e = objects[i]; + if (!e->isPickable() || (e->entityId == ownerId && flightTime < 5)) continue; + + float rr = 0.3f; + AABB bb = e->bb.grow(rr, rr, rr); + HitResult p = bb.clip(from, to); + if (p.isHit()) { + float dd = from.distanceTo(p.pos); + if (dd < nearest || nearest == 0) { + hitEntity = e; + nearest = dd; + } + } + } + + if (hitEntity != NULL) + res = HitResult(hitEntity); + } + + if (res.isHit()) + onHit(res); + + x += xd; + y += yd; + z += zd; + + float sd = Mth::sqrt(xd * xd + zd * zd); + yRot = Mth::atan2(xd, zd) * 180 / Mth::PI; + xRot = Mth::atan2(yd, sd) * 180 / Mth::PI; + + while (xRot - xRotO < -180) + xRotO -= 360; + while (xRot - xRotO >= 180) + xRotO += 360; + + while (yRot - yRotO < -180) + yRotO -= 360; + while (yRot - yRotO >= 180) + yRotO += 360; + + xRot = xRotO + (xRot - xRotO) * 0.2f; + yRot = yRotO + (yRot - yRotO) * 0.2f; + + + float inertia = 0.99f; + float gravity = getGravity(); + + if (isInWater()) { + for (int i = 0; i < 4; i++) { + float s = 1 / 4.0f; + level->addParticle("bubble", x - xd * s, y - yd * s, z - zd * s, xd, yd, zd); + } + inertia = 0.80f; + } + + xd *= inertia; + yd *= inertia; + zd *= inertia; + yd -= gravity; + + setPos(x, y, z); +} + +float Throwable::getShadowHeightOffs() { + return 0; +} + +void Throwable::addAdditonalSaveData( CompoundTag* tag ) { + tag->putShort("xTile", (short) xTile); + tag->putShort("yTile", (short) yTile); + tag->putShort("zTile", (short) zTile); + tag->putByte("inTile", (char) lastTile); + tag->putByte("shake", (char) shakeTime); + tag->putByte("inGround", (char) (inGround ? 1 : 0)); +} + +void Throwable::readAdditionalSaveData( CompoundTag* tag ) { + xTile = tag->getShort("xTile"); + yTile = tag->getShort("yTile"); + zTile = tag->getShort("zTile"); + lastTile = tag->getByte("inTile") & 0xff; + shakeTime = tag->getByte("shake") & 0xff; + inGround = tag->getByte("inGround") == 1; +} + +int Throwable::getAuxData() { + return ownerId; +} diff --git a/src/world/entity/projectile/Throwable.h b/src/world/entity/projectile/Throwable.hpp similarity index 96% rename from src/world/entity/projectile/Throwable.h rename to src/world/entity/projectile/Throwable.hpp index 0b24726..aa1389c 100755 --- a/src/world/entity/projectile/Throwable.h +++ b/src/world/entity/projectile/Throwable.hpp @@ -7,7 +7,7 @@ class Mob; class Player; class CompoundTag; -#include "../Entity.h" +#include "world/entity/Entity.hpp" class HitResult; diff --git a/src/world/entity/projectile/ThrownEgg.h b/src/world/entity/projectile/ThrownEgg.hpp similarity index 88% rename from src/world/entity/projectile/ThrownEgg.h rename to src/world/entity/projectile/ThrownEgg.hpp index cb9a264..a79b7e4 100755 --- a/src/world/entity/projectile/ThrownEgg.h +++ b/src/world/entity/projectile/ThrownEgg.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.entity->projectile; -#include "Throwable.h" -#include "../Mob.h" -#include "../animal/Chicken.h" -#include "../../level/Level.h" -#include "../../phys/HitResult.h" +#include "Throwable.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/animal/Chicken.hpp" +#include "world/level/Level.hpp" +#include "world/phys/HitResult.hpp" class ThrownEgg: public Throwable { diff --git a/src/world/food/FoodConstants.h b/src/world/food/FoodConstants.hpp similarity index 100% rename from src/world/food/FoodConstants.h rename to src/world/food/FoodConstants.hpp diff --git a/src/world/food/SimpleFoodData.cpp b/src/world/food/SimpleFoodData.cpp index 3a49589..33a1d66 100755 --- a/src/world/food/SimpleFoodData.cpp +++ b/src/world/food/SimpleFoodData.cpp @@ -1,33 +1,33 @@ -#include "SimpleFoodData.h" -#include "FoodConstants.h" -#include "../item/FoodItem.h" -#include "../entity/player/Player.h" - -SimpleFoodData::SimpleFoodData() -: foodLevel(0) -{ -} - -void SimpleFoodData::eat( int food ) { - foodLevel = Mth::Min(food + foodLevel, FoodConstants::MAX_FOOD); -} - -void SimpleFoodData::eat( FoodItem* item ) { - eat(item->getNutrition()); -} - -void SimpleFoodData::tick( Player* player ) { - if (foodLevel > 0 && player->isHurt()) { - const int healAmount = foodLevel;// / 2; - player->heal(healAmount); - foodLevel = 0; - /* - if (!level->isClientSide) { - player->heal(healAmount); - } else { - SetHealthPacket packet(SetHealthPacket::HEALTH_MODIFY_OFFSET - healAmount); - level->raknetInstance->send(packet); - } - */ - } -} +#include "SimpleFoodData.hpp" +#include "FoodConstants.hpp" +#include "world/item/FoodItem.hpp" +#include "world/entity/player/Player.hpp" + +SimpleFoodData::SimpleFoodData() +: foodLevel(0) +{ +} + +void SimpleFoodData::eat( int food ) { + foodLevel = Mth::Min(food + foodLevel, FoodConstants::MAX_FOOD); +} + +void SimpleFoodData::eat( FoodItem* item ) { + eat(item->getNutrition()); +} + +void SimpleFoodData::tick( Player* player ) { + if (foodLevel > 0 && player->isHurt()) { + const int healAmount = foodLevel;// / 2; + player->heal(healAmount); + foodLevel = 0; + /* + if (!level->isClientSide) { + player->heal(healAmount); + } else { + SetHealthPacket packet(SetHealthPacket::HEALTH_MODIFY_OFFSET - healAmount); + level->raknetInstance->send(packet); + } + */ + } +} diff --git a/src/world/food/SimpleFoodData.h b/src/world/food/SimpleFoodData.hpp similarity index 100% rename from src/world/food/SimpleFoodData.h rename to src/world/food/SimpleFoodData.hpp diff --git a/src/world/inventory/BaseContainerMenu.cpp b/src/world/inventory/BaseContainerMenu.cpp index 4fcda48..1b964be 100755 --- a/src/world/inventory/BaseContainerMenu.cpp +++ b/src/world/inventory/BaseContainerMenu.cpp @@ -1,41 +1,41 @@ -#include "BaseContainerMenu.h" -#include "../item/ItemInstance.h" - -BaseContainerMenu::BaseContainerMenu( int containerType ) -: containerId(-1), - containerType(containerType), - listener(NULL) -{ -} - -void BaseContainerMenu::setListener( IContainerListener* listener ) -{ - if (!(this->listener = listener)) - return; - - if (listener) - listener->refreshContainer(this, lastSlots = getItems()); -} - -void BaseContainerMenu::broadcastChanges() -{ - //LOGI("broadcast: Base. Listener: %p\n", listener); - if (!listener) - return; - - ItemList slots = getItems(); - if (slots.size() != lastSlots.size()) { - listener->refreshContainer(this, lastSlots = slots); - return; - } - - for (unsigned int i = 0; i < slots.size(); i++) { - ItemInstance& current = slots[i]; - ItemInstance& expected = lastSlots[i]; - if (!ItemInstance::matches(&expected, ¤t)) { - expected = current; - //LOGI("Broadcasting a change!\n"); - listener->slotChanged(this, i, expected, isResultSlot(i)); - } - } -} +#include "BaseContainerMenu.hpp" +#include "world/item/ItemInstance.hpp" + +BaseContainerMenu::BaseContainerMenu( int containerType ) +: containerId(-1), + containerType(containerType), + listener(NULL) +{ +} + +void BaseContainerMenu::setListener( IContainerListener* listener ) +{ + if (!(this->listener = listener)) + return; + + if (listener) + listener->refreshContainer(this, lastSlots = getItems()); +} + +void BaseContainerMenu::broadcastChanges() +{ + //LOGI("broadcast: Base. Listener: %p\n", listener); + if (!listener) + return; + + ItemList slots = getItems(); + if (slots.size() != lastSlots.size()) { + listener->refreshContainer(this, lastSlots = slots); + return; + } + + for (unsigned int i = 0; i < slots.size(); i++) { + ItemInstance& current = slots[i]; + ItemInstance& expected = lastSlots[i]; + if (!ItemInstance::matches(&expected, ¤t)) { + expected = current; + //LOGI("Broadcasting a change!\n"); + listener->slotChanged(this, i, expected, isResultSlot(i)); + } + } +} diff --git a/src/world/inventory/BaseContainerMenu.h b/src/world/inventory/BaseContainerMenu.hpp similarity index 96% rename from src/world/inventory/BaseContainerMenu.h rename to src/world/inventory/BaseContainerMenu.hpp index c16c6b8..b642d20 100755 --- a/src/world/inventory/BaseContainerMenu.h +++ b/src/world/inventory/BaseContainerMenu.hpp @@ -3,7 +3,7 @@ //package net.minecraft.world.inventory; #include -#include "../item/ItemInstance.h" +#include "world/item/ItemInstance.hpp" class BaseContainerMenu; diff --git a/src/world/inventory/ContainerMenu.cpp b/src/world/inventory/ContainerMenu.cpp index 7031cf1..9259fa2 100755 --- a/src/world/inventory/ContainerMenu.cpp +++ b/src/world/inventory/ContainerMenu.cpp @@ -1,35 +1,35 @@ -#include "ContainerMenu.h" -#include "../Container.h" -#include "../entity/player/Player.h" -#include "../item/ItemInstance.h" - -ContainerMenu::ContainerMenu( Container* container, int tileEntityId /* = -1 */ ) -: super(ContainerType::CONTAINER), - container(container), - tileEntityId(tileEntityId) -{ -} - -void ContainerMenu::setSlot( int slot, ItemInstance* item ) -{ - container->setItem(slot, item); -} - -std::vector ContainerMenu::getItems() -{ - std::vector out; - for (int i = 0; i < container->getContainerSize(); ++i) { - ItemInstance* item = container->getItem(i); - out.push_back(item? *item : ItemInstance()); - } - return out; -} - -bool ContainerMenu::tileEntityDestroyedIsInvalid( int tileEntityId ) -{ - return (this->tileEntityId == tileEntityId); - /* - return (this->tileEntityId >= 0 - && this->tileEntityId == tileEntityId); - */ -} +#include "ContainerMenu.hpp" +#include "world/Container.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/ItemInstance.hpp" + +ContainerMenu::ContainerMenu( Container* container, int tileEntityId /* = -1 */ ) +: super(ContainerType::CONTAINER), + container(container), + tileEntityId(tileEntityId) +{ +} + +void ContainerMenu::setSlot( int slot, ItemInstance* item ) +{ + container->setItem(slot, item); +} + +std::vector ContainerMenu::getItems() +{ + std::vector out; + for (int i = 0; i < container->getContainerSize(); ++i) { + ItemInstance* item = container->getItem(i); + out.push_back(item? *item : ItemInstance()); + } + return out; +} + +bool ContainerMenu::tileEntityDestroyedIsInvalid( int tileEntityId ) +{ + return (this->tileEntityId == tileEntityId); + /* + return (this->tileEntityId >= 0 + && this->tileEntityId == tileEntityId); + */ +} diff --git a/src/world/inventory/ContainerMenu.h b/src/world/inventory/ContainerMenu.hpp similarity index 94% rename from src/world/inventory/ContainerMenu.h rename to src/world/inventory/ContainerMenu.hpp index 2c96a14..724ab92 100755 --- a/src/world/inventory/ContainerMenu.h +++ b/src/world/inventory/ContainerMenu.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.inventory; -#include "BaseContainerMenu.h" +#include "BaseContainerMenu.hpp" #include class Container; diff --git a/src/world/inventory/CraftingContainer.h b/src/world/inventory/CraftingContainer.hpp similarity index 92% rename from src/world/inventory/CraftingContainer.h rename to src/world/inventory/CraftingContainer.hpp index 4baff03..72871b7 100755 --- a/src/world/inventory/CraftingContainer.h +++ b/src/world/inventory/CraftingContainer.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.inventory; -#include "../Container.h" -#include "../entity/player/Player.h" -#include "../item/ItemInstance.h" -//#include "AbstractContainerMenu.h" +#include "world/Container.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/ItemInstance.hpp" +//#include "AbstractContainerMenu.hpp" class CraftingContainer: public Container { diff --git a/src/world/inventory/FillingContainer.cpp b/src/world/inventory/FillingContainer.cpp index 10028b0..af916c0 100755 --- a/src/world/inventory/FillingContainer.cpp +++ b/src/world/inventory/FillingContainer.cpp @@ -1,624 +1,624 @@ -#include "FillingContainer.h" -#include "../level/tile/TreeTile.h" -#include "../item/crafting/Recipe.h" -#include "../../util/Mth.h" -#include "../../nbt/CompoundTag.h" -#include "../level/tile/StoneSlabTile.h" - -#define MAGIX_VAL 255 -#define MAX_SLOTS 96 - -FillingContainer::FillingContainer( - int numTotalSlots, - int numLinkedSlots, - int containerType, - bool isCreative) -: super(containerType), - numTotalSlots(numTotalSlots), - numLinkedSlots(numLinkedSlots), - linkedSlots(NULL), - _isCreative(isCreative) -{ - if (numLinkedSlots > 0) - linkedSlots = new LinkedSlot[numLinkedSlots]; - - items.resize(numTotalSlots); -} - -FillingContainer::~FillingContainer() -{ - clearInventory(); - - if (numLinkedSlots > 0) - delete[] linkedSlots; -} - -void FillingContainer::clearInventory() -{ - for (int i = 0; i < numLinkedSlots; ++i) { - linkedSlots[i] = LinkedSlot(i); - } - - //@todo: i = MAX_ -> get() transforms count=255-ptrs to real - for (unsigned int i = numLinkedSlots; i < items.size(); i++) { - release(i); - } - - items.resize(numTotalSlots); -} - -bool FillingContainer::removeResource( int type ) -{ - if (_isCreative) return true; - - int slot = getSlot(type); - if (slot < 0) return false; - if (--items[slot]->count <= 0) release(slot); - - return true; -} - -bool FillingContainer::removeResource( const ItemInstance& item ) { - return removeResource(item, false) == 0; -} - -int FillingContainer::removeResource( const ItemInstance& item, bool requireExactAux ) -{ - if (_isCreative) return 0; - - int count = item.count; - while (count > 0) { - // If any AUX value, remove any with that id - int slot = -1; - if (!requireExactAux && (Recipe::isAnyAuxValue(&item) || item.getAuxValue() == Recipe::ANY_AUX_VALUE)) - slot = getNonEmptySlot(item.id); - else - slot = getNonEmptySlot(item.id, item.getAuxValue()); - - if (slot < 0) - return count; - - // Try to remove all items, but if it's not enough, - // we continue on another slot next time - ItemInstance* slotItem = items[slot]; - int toRemove = Mth::Min(count, slotItem->count); - slotItem->count -= toRemove; - count -= toRemove; - - if (slotItem->count <= 0) - clearSlot(slot); - //removeItem(slot, item.count); - } - return 0; -} - -bool FillingContainer::hasResource( int type ) const -{ - if (_isCreative) return true; - - int slot = getSlot(type); - if (slot < 0) return false; - - return true; -} - -void FillingContainer::swapSlots( int from, int to ) -{ - ItemInstance* tmp = items[to]; - items[to] = items[from]; - items[from] = tmp; -} - -bool FillingContainer::add( ItemInstance* item ) -{ - if (_isCreative) return true; - - if (!item || item->isNull()) return true; - - if (!item->isDamaged()) { - int lastSize; - do { - lastSize = item->count; - item->count = addResource(*item); - } while (item->count > 0 && item->count < lastSize); - //if (item->count == lastSize && player->abilities.instabuild) { - // // silently destroy the item when having a full inventory - // item->count = 0; - // return true; - //} - return item->count < lastSize; - } - - int slot = getFreeSlot(); - if (slot >= 0) { - items[slot] = ItemInstance::clone(item); - // items[slot] = item; - //items[slot]->popTime = FillingContainer::POP_TIME_DURATION; - linkEmptySlot(slot); - item->count = 0; - return true; - //} else if (player->abilities.instabuild) { - // // silently destroy the item when having a full inventory - // item->count = 0; - // return true; - } - - return false; -} - -ItemInstance FillingContainer::removeItem( int slot, int count ) -{ - ItemInstance* item = getItem(slot); - if (item) { - if (count > item->count) - count = item->count; - item->count -= count; - - if (item->count <= 0) - clearSlot(slot); - } - - /* - ItemList& pile = *getSlotList(slot); - if (pile[slot] != NULL) { - if (pile[slot]->count <= count) { - ItemInstance item = *pile[slot]; - release(slot); - return item; - } else { - ItemInstance i = pile[slot]->remove(count); - if (pile[slot]->count == 0) release(slot); - return i; - } - } - */ - return ItemInstance(); -} - -void FillingContainer::setItem( int slot, ItemInstance* item ) -{ - if (slot < 0 || slot >= numTotalSlots) - return; - - if (ItemList* p = getSlotList(slot)) { - ItemList& pile = *p; - if (pile[slot]) *pile[slot] = item? *item : ItemInstance(); - else pile[slot] = new ItemInstance(item? *item : ItemInstance()); - } -} - -ListTag* FillingContainer::save( ListTag* listTag ) -{ - //LOGI("Save.inv-creative? %d. Size %d\n", _isCreative, items.size()); - if (!_isCreative) { - ItemInstance selTmp; - for (int i = 0; i < (int)items.size(); i++) { - ItemInstance* item = items[i]; - - if (i < numLinkedSlots) { - int slot = linkedSlots[i].inventorySlot; - selTmp = ItemInstance(MAGIX_VAL, MAGIX_VAL, slot); - item = &selTmp; - } - if (item != NULL) { - CompoundTag* tag = new CompoundTag(); - tag->putByte("Slot", (char) i); - - if (item->count < 0) item->count = 0; - if (item->count > 255) item->count = 255; - - ItemInstance iitem(*item); - iitem.save(tag); - //LOGI("Saving %d as : %d@%d:%d\n", i, item->id, item->getAuxValue(), item->count); - listTag->add(tag); - } - } - } - return listTag; -} - -void FillingContainer::load( ListTag* inventoryList ) -{ - //LOGI("Load.inv-creative? %d. Size %d\n", _isCreative, items.size()); - if (_isCreative) - return; - - clearInventory(); - - //items = /*new*/ ItemInstance[INVENTORY_SIZE]; - for (int i = inventoryList->size()-1; i >= 0; --i) { - Tag* t = inventoryList->get(i); - if (t->getId() != Tag::TAG_Compound) continue; - - CompoundTag* tag = (CompoundTag*) t; - int slot = tag->getByte("Slot") & 0xff; - if (slot < 0) continue; - - ItemInstance* item = ItemInstance::fromTag(tag); - if (item != NULL) { - //LOGI("Loading %d as : %d@%d:%d\n", slot, item->id, item->getAuxValue(), item->count); - // Special case! (don't we love them!). item->count == 255 means - // we POINT to our real inventory item (from a selection slot). - // This is ONLY AND ALWAYS used in Selection Slots at this moment. - if (slot < numLinkedSlots) { - if (slot < (int)items.size() && item->id == MAGIX_VAL && item->count == MAGIX_VAL) { - int invSlot = item->getAuxValue(); - if (invSlot >= numLinkedSlots && invSlot < (int)items.size()) - linkSlot(slot, invSlot, false); - } else { // Something's wrong, shouldnt go here - LOGE("Error: Slot %d is selection slot (inventory size: %d) but id/count is %d/%d\n", slot, (int)items.size(), item->id, item->count); - } - delete item; - continue; - } - - //item->count = 3; - if (slot < MAX_SLOTS && slot >= numLinkedSlots) - { - // Zero count (valid before, but not anymore), destroy - if (item->count == 0) { - delete item; - continue; - } - // Suggesting the container is larger than it is, drop the item! - if (slot >= (int)items.size()) { - doDrop(item, true); - continue; - } - - fixBackwardCompabilityItem(*item); - items[slot] = item; - } - //else if (slot >= 100 && slot < armor.length + 100) armor[slot - 100] = item; - else { - if (slot >= MAX_SLOTS) { - LOGE("Error: Too large slot ID in Inventory: %d!\n", slot); - } - delete item; - } - } - } - compressLinkedSlotList(0); -} - -int FillingContainer::getContainerSize() const -{ - int sz = items.size(); - if (sz != numTotalSlots) { - LOGE("Error@getContainerSize: num items != InventorySize: %d != %d\n", sz, numTotalSlots); - } - return numTotalSlots; -} - -ItemInstance* FillingContainer::getItem( int slot ) -{ - if (slot < 0 || slot >= numTotalSlots) - return NULL; - - // Real inventory slot - if (slot >= numLinkedSlots) - return (*getSlotList(slot))[slot]; - - return getLinked(slot); //@note -} - -std::string FillingContainer::getName() const -{ - return "Inventory"; -} - -int FillingContainer::getMaxStackSize() const -{ - return MAX_INVENTORY_STACK_SIZE; -} - -void FillingContainer::dropSlot( int slot, bool onlyClearContainer, bool randomly/*=false*/ ) -{ - if (slot >= 0 && slot < numLinkedSlots) - slot = linkedSlots[slot].inventorySlot; - if (slot < 0 || slot >= (int)items.size()) return; - - if (items[slot] && items[slot]->count) { - if (!onlyClearContainer) - doDrop(items[slot]->copy(), randomly); - items[slot]->count = 0; - release(slot); //@itodo: - compressLinkedSlotList(slot); - } -} - -void FillingContainer::dropAll(bool onlyClearContainer) -{ - for (unsigned int i = numLinkedSlots; i < items.size(); i++) { - dropSlot(i, onlyClearContainer, true); - } -} - -void FillingContainer::setContainerChanged() -{ -} - -bool FillingContainer::stillValid( Player* player ) -{ - return !player->removed; -} - -bool FillingContainer::contains( ItemInstance* itemInstance ) const -{ - for (unsigned int i = 0; i < items.size(); i++) { - if (items[i] != NULL && items[i]->matches(itemInstance)) return true; - } - return false; -} - -int FillingContainer::getSlot( int tileId) const -{ - for (unsigned int i = numLinkedSlots; i < items.size(); i++) { - if (items[i] != NULL && items[i]->id == tileId) return i; - } - return -1; -} - -int FillingContainer::getSlot( int tileId, int data) const -{ - for (unsigned int i = numLinkedSlots; i < items.size(); i++) { - if (items[i] != NULL - && items[i]->id == tileId - && items[i]->getAuxValue() == data) - return i; - } - return -1; -} - -int FillingContainer::getNonEmptySlot( int tileId) const -{ - for (unsigned int i = numLinkedSlots; i < items.size(); i++) { - if (items[i] != NULL && items[i]->id == tileId && items[i]->count > 0) return i; - } - return -1; -} - -int FillingContainer::getNonEmptySlot( int tileId, int data) const -{ - for (unsigned int i = numLinkedSlots; i < items.size(); i++) { - if (items[i] != NULL - && items[i]->id == tileId - && items[i]->getAuxValue() == data - && items[i]->count > 0) - return i; - } - return -1; -} - -int FillingContainer::getNumEmptySlots() { - int numEmpty = 0; - for (unsigned int i = numLinkedSlots; i < items.size(); ++i) { - if (!items[i] || items[i]->isNull()) - ++numEmpty; - } - return numEmpty; -} - -int FillingContainer::getNumLinkedSlots() { - return numLinkedSlots; -} - -int FillingContainer::getSlotWithRemainingSpace( const ItemInstance& item ) -{ - for (unsigned int i = 0; i < items.size(); i++) { - if (items[i] != NULL && items[i]->id == item.id - && items[i]->isStackable() - && items[i]->count < items[i]->getMaxStackSize() - && items[i]->count < getMaxStackSize() - && (!items[i]->isStackedByData() || items[i]->getAuxValue() == item.getAuxValue())) { - return i; - } - } - return -1; -} - -int FillingContainer::addResource( const ItemInstance& itemInstance ) -{ - int type = itemInstance.id; - int count = itemInstance.count; - - if (itemInstance.getMaxStackSize() == 1) { - int slot = getFreeSlot(); - if (slot < 0) return count; - if (items[slot] == NULL) { - items[slot] = ItemInstance::clone(&itemInstance); - linkEmptySlot(slot); - } else if (items[slot]->isNull()) { - *items[slot] = itemInstance; - linkEmptySlot(slot); - } - return 0; - } - - int slot = getSlotWithRemainingSpace(itemInstance); - if (slot < 0) slot = getFreeSlot(); - if (slot < 0) return count; - if (items[slot] == NULL) { - items[slot] = new ItemInstance(type, 0, itemInstance.getAuxValue()); - } else if (items[slot]->isNull()) { //@attn: added when doing chests - *items[slot] = ItemInstance(type, 0, itemInstance.getAuxValue()); - } - - // Add the newly added item to a selections lot, if one's free - linkEmptySlot(slot); - - int toAdd = count; - - if (toAdd > items[slot]->getMaxStackSize() - items[slot]->count) { - toAdd = items[slot]->getMaxStackSize() - items[slot]->count; - } - - if (toAdd > getMaxStackSize() - items[slot]->count) { - toAdd = getMaxStackSize() - items[slot]->count; - } - - if (toAdd == 0) return count; - - count -= toAdd; - items[slot]->count += toAdd; - //items[slot]->popTime = POP_TIME_DURATION; - - return count; -} - -int FillingContainer::getFreeSlot() const -{ - for (unsigned int i = numLinkedSlots; i < items.size(); i++) { - if (items[i] == NULL || items[i]->isNull()) return i; - } - return -1; -} - -void FillingContainer::release( int slot ) -{ - if (items[slot]) { - delete items[slot];// @itodo - items[slot] = NULL; - } -} - -void FillingContainer::clearSlot( int slot ) -{ - if (slot < 0) - return; - - if (slot < numLinkedSlots) { - release(linkedSlots[slot].inventorySlot); - linkedSlots[slot].inventorySlot = -1; - } - else { - release(slot); - } - compressLinkedSlotList(slot); -} - -int FillingContainer::addItem(ItemInstance* item) { - for (unsigned int i = numLinkedSlots; i < items.size(); ++i) - if (!items[i]) { - items[i] = item; - return i; - } - - int newSize = items.size() + 1; - if (_isCreative && newSize > numTotalSlots) - numTotalSlots = newSize; - if (newSize <= numTotalSlots) { - items.push_back(item); - return newSize-1; - } - LOGE("Error@addItem: adding an item to an already full inventory: %s!\n", item->getDescriptionId().c_str()); - delete item; - return 0; -} - -void FillingContainer::fixBackwardCompabilityItem( ItemInstance& item ) -{ - if (item.id == Tile::stoneSlabHalf->id) - item.setAuxValue(item.getAuxValue() & StoneSlabTile::TYPE_MASK); -} - -void FillingContainer::replace( std::vector newItems, int maxCount /* = -1 */) -{ - clearInventory(); - maxCount = maxCount < 0 ? newItems.size() : Mth::Min(newItems.size(), maxCount); - - int base = numLinkedSlots; - const int iMax = Mth::Min(getContainerSize() - base, maxCount); - for (int i = 0; i < iMax; ++i) { - replaceSlot(base + i, newItems[i].isNull()? NULL : &newItems[i]); - //LOGI("Adding to slot: %d - %s :: %s\n", newItems[i], ) - } -} - -void FillingContainer::replaceSlot( int slotId, ItemInstance* ins ) -{ - if (ins) { - if (!items[slotId]) - items[slotId] = new ItemInstance(); - *items[slotId] = *ins; - } else { - release(slotId); - } -} - -FillingContainer::ItemList* FillingContainer::getSlotList( int& slot ) -{ - ItemList* pile = &items; - //if (slot >= pile->size()) { - // slot -= pile->size(); - // pile = armor; - //} - return pile; -} - -// Special for this "selection based" inventory -bool FillingContainer::linkSlot(int selectionSlot, int inventorySlot, bool propagate) { - if (selectionSlot < 0 || selectionSlot >= numLinkedSlots) - return false; - if (inventorySlot < numLinkedSlots || inventorySlot >= numTotalSlots) - return false; - if (inventorySlot == linkedSlots[selectionSlot].inventorySlot) - return false; - - if (propagate) { - int i = 0; - for (; i < numLinkedSlots - 1; ++i) - if (linkedSlots[i].inventorySlot == inventorySlot) break; - for (; i > selectionSlot; --i) { - linkedSlots[i].inventorySlot = linkedSlots[i-1].inventorySlot; - } - } - linkedSlots[selectionSlot].inventorySlot = inventorySlot; - - return true; -} - -bool FillingContainer::linkEmptySlot( int inventorySlot ) -{ - // Check if we already got the inventory slot - for (int i = 0; i < numLinkedSlots; ++i) - if (linkedSlots[i].inventorySlot == inventorySlot) return true; - - // Check if there's an empty slot to place the new resource in - for (int i = 0; i < numLinkedSlots; ++i) { - ItemInstance* item = getLinked(i); - if (!item) { - linkedSlots[i].inventorySlot = inventorySlot; - return true; - } - } - return false; -} - -void FillingContainer::compressLinkedSlotList(int slot) -{ - int i = slot-1, j = 0; - while (++i < numLinkedSlots) { - linkedSlots[i-j] = linkedSlots[i]; - - ItemInstance* item = getLinked(i); - if (!item) ++j; - } - for (int k = i-j; k < i; ++k) - linkedSlots[k].inventorySlot = -1; -} - -void FillingContainer::doDrop( ItemInstance* item, bool randomly ) -{ - delete item; -} - -ItemInstance* FillingContainer::getLinked( int slot ) -{ - // sanity checking to prevent exploits - if (slot < numLinkedSlots && slot >= 0) { - int i = linkedSlots[slot].inventorySlot; - return (i >= numLinkedSlots && i < numTotalSlots)? items[i] : NULL; - } - return NULL; -} +#include "FillingContainer.hpp" +#include "world/level/tile/TreeTile.hpp" +#include "world/item/crafting/Recipe.hpp" +#include "util/Mth.hpp" +#include "nbt/CompoundTag.hpp" +#include "world/level/tile/StoneSlabTile.hpp" + +#define MAGIX_VAL 255 +#define MAX_SLOTS 96 + +FillingContainer::FillingContainer( + int numTotalSlots, + int numLinkedSlots, + int containerType, + bool isCreative) +: super(containerType), + numTotalSlots(numTotalSlots), + numLinkedSlots(numLinkedSlots), + linkedSlots(NULL), + _isCreative(isCreative) +{ + if (numLinkedSlots > 0) + linkedSlots = new LinkedSlot[numLinkedSlots]; + + items.resize(numTotalSlots); +} + +FillingContainer::~FillingContainer() +{ + clearInventory(); + + if (numLinkedSlots > 0) + delete[] linkedSlots; +} + +void FillingContainer::clearInventory() +{ + for (int i = 0; i < numLinkedSlots; ++i) { + linkedSlots[i] = LinkedSlot(i); + } + + //@todo: i = MAX_ -> get() transforms count=255-ptrs to real + for (unsigned int i = numLinkedSlots; i < items.size(); i++) { + release(i); + } + + items.resize(numTotalSlots); +} + +bool FillingContainer::removeResource( int type ) +{ + if (_isCreative) return true; + + int slot = getSlot(type); + if (slot < 0) return false; + if (--items[slot]->count <= 0) release(slot); + + return true; +} + +bool FillingContainer::removeResource( const ItemInstance& item ) { + return removeResource(item, false) == 0; +} + +int FillingContainer::removeResource( const ItemInstance& item, bool requireExactAux ) +{ + if (_isCreative) return 0; + + int count = item.count; + while (count > 0) { + // If any AUX value, remove any with that id + int slot = -1; + if (!requireExactAux && (Recipe::isAnyAuxValue(&item) || item.getAuxValue() == Recipe::ANY_AUX_VALUE)) + slot = getNonEmptySlot(item.id); + else + slot = getNonEmptySlot(item.id, item.getAuxValue()); + + if (slot < 0) + return count; + + // Try to remove all items, but if it's not enough, + // we continue on another slot next time + ItemInstance* slotItem = items[slot]; + int toRemove = Mth::Min(count, slotItem->count); + slotItem->count -= toRemove; + count -= toRemove; + + if (slotItem->count <= 0) + clearSlot(slot); + //removeItem(slot, item.count); + } + return 0; +} + +bool FillingContainer::hasResource( int type ) const +{ + if (_isCreative) return true; + + int slot = getSlot(type); + if (slot < 0) return false; + + return true; +} + +void FillingContainer::swapSlots( int from, int to ) +{ + ItemInstance* tmp = items[to]; + items[to] = items[from]; + items[from] = tmp; +} + +bool FillingContainer::add( ItemInstance* item ) +{ + if (_isCreative) return true; + + if (!item || item->isNull()) return true; + + if (!item->isDamaged()) { + int lastSize; + do { + lastSize = item->count; + item->count = addResource(*item); + } while (item->count > 0 && item->count < lastSize); + //if (item->count == lastSize && player->abilities.instabuild) { + // // silently destroy the item when having a full inventory + // item->count = 0; + // return true; + //} + return item->count < lastSize; + } + + int slot = getFreeSlot(); + if (slot >= 0) { + items[slot] = ItemInstance::clone(item); + // items[slot] = item; + //items[slot]->popTime = FillingContainer::POP_TIME_DURATION; + linkEmptySlot(slot); + item->count = 0; + return true; + //} else if (player->abilities.instabuild) { + // // silently destroy the item when having a full inventory + // item->count = 0; + // return true; + } + + return false; +} + +ItemInstance FillingContainer::removeItem( int slot, int count ) +{ + ItemInstance* item = getItem(slot); + if (item) { + if (count > item->count) + count = item->count; + item->count -= count; + + if (item->count <= 0) + clearSlot(slot); + } + + /* + ItemList& pile = *getSlotList(slot); + if (pile[slot] != NULL) { + if (pile[slot]->count <= count) { + ItemInstance item = *pile[slot]; + release(slot); + return item; + } else { + ItemInstance i = pile[slot]->remove(count); + if (pile[slot]->count == 0) release(slot); + return i; + } + } + */ + return ItemInstance(); +} + +void FillingContainer::setItem( int slot, ItemInstance* item ) +{ + if (slot < 0 || slot >= numTotalSlots) + return; + + if (ItemList* p = getSlotList(slot)) { + ItemList& pile = *p; + if (pile[slot]) *pile[slot] = item? *item : ItemInstance(); + else pile[slot] = new ItemInstance(item? *item : ItemInstance()); + } +} + +ListTag* FillingContainer::save( ListTag* listTag ) +{ + //LOGI("Save.inv-creative? %d. Size %d\n", _isCreative, items.size()); + if (!_isCreative) { + ItemInstance selTmp; + for (int i = 0; i < (int)items.size(); i++) { + ItemInstance* item = items[i]; + + if (i < numLinkedSlots) { + int slot = linkedSlots[i].inventorySlot; + selTmp = ItemInstance(MAGIX_VAL, MAGIX_VAL, slot); + item = &selTmp; + } + if (item != NULL) { + CompoundTag* tag = new CompoundTag(); + tag->putByte("Slot", (char) i); + + if (item->count < 0) item->count = 0; + if (item->count > 255) item->count = 255; + + ItemInstance iitem(*item); + iitem.save(tag); + //LOGI("Saving %d as : %d@%d:%d\n", i, item->id, item->getAuxValue(), item->count); + listTag->add(tag); + } + } + } + return listTag; +} + +void FillingContainer::load( ListTag* inventoryList ) +{ + //LOGI("Load.inv-creative? %d. Size %d\n", _isCreative, items.size()); + if (_isCreative) + return; + + clearInventory(); + + //items = /*new*/ ItemInstance[INVENTORY_SIZE]; + for (int i = inventoryList->size()-1; i >= 0; --i) { + Tag* t = inventoryList->get(i); + if (t->getId() != Tag::TAG_Compound) continue; + + CompoundTag* tag = (CompoundTag*) t; + int slot = tag->getByte("Slot") & 0xff; + if (slot < 0) continue; + + ItemInstance* item = ItemInstance::fromTag(tag); + if (item != NULL) { + //LOGI("Loading %d as : %d@%d:%d\n", slot, item->id, item->getAuxValue(), item->count); + // Special case! (don't we love them!). item->count == 255 means + // we POINT to our real inventory item (from a selection slot). + // This is ONLY AND ALWAYS used in Selection Slots at this moment. + if (slot < numLinkedSlots) { + if (slot < (int)items.size() && item->id == MAGIX_VAL && item->count == MAGIX_VAL) { + int invSlot = item->getAuxValue(); + if (invSlot >= numLinkedSlots && invSlot < (int)items.size()) + linkSlot(slot, invSlot, false); + } else { // Something's wrong, shouldnt go here + LOGE("Error: Slot %d is selection slot (inventory size: %d) but id/count is %d/%d\n", slot, (int)items.size(), item->id, item->count); + } + delete item; + continue; + } + + //item->count = 3; + if (slot < MAX_SLOTS && slot >= numLinkedSlots) + { + // Zero count (valid before, but not anymore), destroy + if (item->count == 0) { + delete item; + continue; + } + // Suggesting the container is larger than it is, drop the item! + if (slot >= (int)items.size()) { + doDrop(item, true); + continue; + } + + fixBackwardCompabilityItem(*item); + items[slot] = item; + } + //else if (slot >= 100 && slot < armor.length + 100) armor[slot - 100] = item; + else { + if (slot >= MAX_SLOTS) { + LOGE("Error: Too large slot ID in Inventory: %d!\n", slot); + } + delete item; + } + } + } + compressLinkedSlotList(0); +} + +int FillingContainer::getContainerSize() const +{ + int sz = items.size(); + if (sz != numTotalSlots) { + LOGE("Error@getContainerSize: num items != InventorySize: %d != %d\n", sz, numTotalSlots); + } + return numTotalSlots; +} + +ItemInstance* FillingContainer::getItem( int slot ) +{ + if (slot < 0 || slot >= numTotalSlots) + return NULL; + + // Real inventory slot + if (slot >= numLinkedSlots) + return (*getSlotList(slot))[slot]; + + return getLinked(slot); //@note +} + +std::string FillingContainer::getName() const +{ + return "Inventory"; +} + +int FillingContainer::getMaxStackSize() const +{ + return MAX_INVENTORY_STACK_SIZE; +} + +void FillingContainer::dropSlot( int slot, bool onlyClearContainer, bool randomly/*=false*/ ) +{ + if (slot >= 0 && slot < numLinkedSlots) + slot = linkedSlots[slot].inventorySlot; + if (slot < 0 || slot >= (int)items.size()) return; + + if (items[slot] && items[slot]->count) { + if (!onlyClearContainer) + doDrop(items[slot]->copy(), randomly); + items[slot]->count = 0; + release(slot); //@itodo: + compressLinkedSlotList(slot); + } +} + +void FillingContainer::dropAll(bool onlyClearContainer) +{ + for (unsigned int i = numLinkedSlots; i < items.size(); i++) { + dropSlot(i, onlyClearContainer, true); + } +} + +void FillingContainer::setContainerChanged() +{ +} + +bool FillingContainer::stillValid( Player* player ) +{ + return !player->removed; +} + +bool FillingContainer::contains( ItemInstance* itemInstance ) const +{ + for (unsigned int i = 0; i < items.size(); i++) { + if (items[i] != NULL && items[i]->matches(itemInstance)) return true; + } + return false; +} + +int FillingContainer::getSlot( int tileId) const +{ + for (unsigned int i = numLinkedSlots; i < items.size(); i++) { + if (items[i] != NULL && items[i]->id == tileId) return i; + } + return -1; +} + +int FillingContainer::getSlot( int tileId, int data) const +{ + for (unsigned int i = numLinkedSlots; i < items.size(); i++) { + if (items[i] != NULL + && items[i]->id == tileId + && items[i]->getAuxValue() == data) + return i; + } + return -1; +} + +int FillingContainer::getNonEmptySlot( int tileId) const +{ + for (unsigned int i = numLinkedSlots; i < items.size(); i++) { + if (items[i] != NULL && items[i]->id == tileId && items[i]->count > 0) return i; + } + return -1; +} + +int FillingContainer::getNonEmptySlot( int tileId, int data) const +{ + for (unsigned int i = numLinkedSlots; i < items.size(); i++) { + if (items[i] != NULL + && items[i]->id == tileId + && items[i]->getAuxValue() == data + && items[i]->count > 0) + return i; + } + return -1; +} + +int FillingContainer::getNumEmptySlots() { + int numEmpty = 0; + for (unsigned int i = numLinkedSlots; i < items.size(); ++i) { + if (!items[i] || items[i]->isNull()) + ++numEmpty; + } + return numEmpty; +} + +int FillingContainer::getNumLinkedSlots() { + return numLinkedSlots; +} + +int FillingContainer::getSlotWithRemainingSpace( const ItemInstance& item ) +{ + for (unsigned int i = 0; i < items.size(); i++) { + if (items[i] != NULL && items[i]->id == item.id + && items[i]->isStackable() + && items[i]->count < items[i]->getMaxStackSize() + && items[i]->count < getMaxStackSize() + && (!items[i]->isStackedByData() || items[i]->getAuxValue() == item.getAuxValue())) { + return i; + } + } + return -1; +} + +int FillingContainer::addResource( const ItemInstance& itemInstance ) +{ + int type = itemInstance.id; + int count = itemInstance.count; + + if (itemInstance.getMaxStackSize() == 1) { + int slot = getFreeSlot(); + if (slot < 0) return count; + if (items[slot] == NULL) { + items[slot] = ItemInstance::clone(&itemInstance); + linkEmptySlot(slot); + } else if (items[slot]->isNull()) { + *items[slot] = itemInstance; + linkEmptySlot(slot); + } + return 0; + } + + int slot = getSlotWithRemainingSpace(itemInstance); + if (slot < 0) slot = getFreeSlot(); + if (slot < 0) return count; + if (items[slot] == NULL) { + items[slot] = new ItemInstance(type, 0, itemInstance.getAuxValue()); + } else if (items[slot]->isNull()) { //@attn: added when doing chests + *items[slot] = ItemInstance(type, 0, itemInstance.getAuxValue()); + } + + // Add the newly added item to a selections lot, if one's free + linkEmptySlot(slot); + + int toAdd = count; + + if (toAdd > items[slot]->getMaxStackSize() - items[slot]->count) { + toAdd = items[slot]->getMaxStackSize() - items[slot]->count; + } + + if (toAdd > getMaxStackSize() - items[slot]->count) { + toAdd = getMaxStackSize() - items[slot]->count; + } + + if (toAdd == 0) return count; + + count -= toAdd; + items[slot]->count += toAdd; + //items[slot]->popTime = POP_TIME_DURATION; + + return count; +} + +int FillingContainer::getFreeSlot() const +{ + for (unsigned int i = numLinkedSlots; i < items.size(); i++) { + if (items[i] == NULL || items[i]->isNull()) return i; + } + return -1; +} + +void FillingContainer::release( int slot ) +{ + if (items[slot]) { + delete items[slot];// @itodo + items[slot] = NULL; + } +} + +void FillingContainer::clearSlot( int slot ) +{ + if (slot < 0) + return; + + if (slot < numLinkedSlots) { + release(linkedSlots[slot].inventorySlot); + linkedSlots[slot].inventorySlot = -1; + } + else { + release(slot); + } + compressLinkedSlotList(slot); +} + +int FillingContainer::addItem(ItemInstance* item) { + for (unsigned int i = numLinkedSlots; i < items.size(); ++i) + if (!items[i]) { + items[i] = item; + return i; + } + + int newSize = items.size() + 1; + if (_isCreative && newSize > numTotalSlots) + numTotalSlots = newSize; + if (newSize <= numTotalSlots) { + items.push_back(item); + return newSize-1; + } + LOGE("Error@addItem: adding an item to an already full inventory: %s!\n", item->getDescriptionId().c_str()); + delete item; + return 0; +} + +void FillingContainer::fixBackwardCompabilityItem( ItemInstance& item ) +{ + if (item.id == Tile::stoneSlabHalf->id) + item.setAuxValue(item.getAuxValue() & StoneSlabTile::TYPE_MASK); +} + +void FillingContainer::replace( std::vector newItems, int maxCount /* = -1 */) +{ + clearInventory(); + maxCount = maxCount < 0 ? newItems.size() : Mth::Min(newItems.size(), maxCount); + + int base = numLinkedSlots; + const int iMax = Mth::Min(getContainerSize() - base, maxCount); + for (int i = 0; i < iMax; ++i) { + replaceSlot(base + i, newItems[i].isNull()? NULL : &newItems[i]); + //LOGI("Adding to slot: %d - %s :: %s\n", newItems[i], ) + } +} + +void FillingContainer::replaceSlot( int slotId, ItemInstance* ins ) +{ + if (ins) { + if (!items[slotId]) + items[slotId] = new ItemInstance(); + *items[slotId] = *ins; + } else { + release(slotId); + } +} + +FillingContainer::ItemList* FillingContainer::getSlotList( int& slot ) +{ + ItemList* pile = &items; + //if (slot >= pile->size()) { + // slot -= pile->size(); + // pile = armor; + //} + return pile; +} + +// Special for this "selection based" inventory +bool FillingContainer::linkSlot(int selectionSlot, int inventorySlot, bool propagate) { + if (selectionSlot < 0 || selectionSlot >= numLinkedSlots) + return false; + if (inventorySlot < numLinkedSlots || inventorySlot >= numTotalSlots) + return false; + if (inventorySlot == linkedSlots[selectionSlot].inventorySlot) + return false; + + if (propagate) { + int i = 0; + for (; i < numLinkedSlots - 1; ++i) + if (linkedSlots[i].inventorySlot == inventorySlot) break; + for (; i > selectionSlot; --i) { + linkedSlots[i].inventorySlot = linkedSlots[i-1].inventorySlot; + } + } + linkedSlots[selectionSlot].inventorySlot = inventorySlot; + + return true; +} + +bool FillingContainer::linkEmptySlot( int inventorySlot ) +{ + // Check if we already got the inventory slot + for (int i = 0; i < numLinkedSlots; ++i) + if (linkedSlots[i].inventorySlot == inventorySlot) return true; + + // Check if there's an empty slot to place the new resource in + for (int i = 0; i < numLinkedSlots; ++i) { + ItemInstance* item = getLinked(i); + if (!item) { + linkedSlots[i].inventorySlot = inventorySlot; + return true; + } + } + return false; +} + +void FillingContainer::compressLinkedSlotList(int slot) +{ + int i = slot-1, j = 0; + while (++i < numLinkedSlots) { + linkedSlots[i-j] = linkedSlots[i]; + + ItemInstance* item = getLinked(i); + if (!item) ++j; + } + for (int k = i-j; k < i; ++k) + linkedSlots[k].inventorySlot = -1; +} + +void FillingContainer::doDrop( ItemInstance* item, bool randomly ) +{ + delete item; +} + +ItemInstance* FillingContainer::getLinked( int slot ) +{ + // sanity checking to prevent exploits + if (slot < numLinkedSlots && slot >= 0) { + int i = linkedSlots[slot].inventorySlot; + return (i >= numLinkedSlots && i < numTotalSlots)? items[i] : NULL; + } + return NULL; +} diff --git a/src/world/inventory/FillingContainer.h b/src/world/inventory/FillingContainer.hpp similarity index 98% rename from src/world/inventory/FillingContainer.h rename to src/world/inventory/FillingContainer.hpp index a6d9c5a..396564e 100755 --- a/src/world/inventory/FillingContainer.h +++ b/src/world/inventory/FillingContainer.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../Container.h" +#include "world/Container.hpp" #include diff --git a/src/world/inventory/FurnaceMenu.cpp b/src/world/inventory/FurnaceMenu.cpp index 6155a7b..29d03d2 100755 --- a/src/world/inventory/FurnaceMenu.cpp +++ b/src/world/inventory/FurnaceMenu.cpp @@ -1,73 +1,73 @@ -#include "FurnaceMenu.h" -#include "../entity/player/Player.h" -#include "../item/ItemInstance.h" -#include "../level/tile/entity/FurnaceTileEntity.h" - -FurnaceMenu::FurnaceMenu( FurnaceTileEntity* furnace ) -: super(ContainerType::FURNACE), - furnace(furnace), - lastTickCount(0), - lastLitTime(0), - lastLitDuration(0) -{ - furnaceTileEntityId = furnace->runningId; -} - -void FurnaceMenu::setSlot( int slot, ItemInstance* item ) -{ - furnace->setItem(slot, item); -} - -void FurnaceMenu::setData( int id, int value ) -{ - if (id == 0) furnace->tickCount = value; - if (id == 1) furnace->litTime = value; - if (id == 2) furnace->litDuration = value; -} - -std::vector FurnaceMenu::getItems() -{ - std::vector out; - for (int i = 0; i < furnace->getContainerSize(); ++i) - out.push_back(*furnace->getItem(i)); - return out; -} - -void FurnaceMenu::broadcastChanges() -{ - super::broadcastChanges(); - - if (!listener) - return; - - //LOGI("broadcast: Derived: data: %d, %d : %d, %d\n", furnace->tickCount, lastTickCount, furnace->litTime, lastLitTime); - - if (furnace->tickCount != lastTickCount) { - listener->setContainerData(this, 0, furnace->tickCount); - lastTickCount = furnace->tickCount; - } - if (furnace->litTime != lastLitTime) { - listener->setContainerData(this, 1, furnace->litTime); - lastLitTime = furnace->litTime; - } - if (furnace->litDuration != lastLitDuration) { - listener->setContainerData(this, 2, furnace->litDuration); - lastLitDuration = furnace->litDuration; - } -} - -void FurnaceMenu::setListener( IContainerListener* listener ) -{ - super::setListener(listener); - - if (listener) { - listener->setContainerData(this, 0, furnace->tickCount); - listener->setContainerData(this, 1, furnace->litTime); - listener->setContainerData(this, 2, furnace->litDuration); - } -} - -bool FurnaceMenu::tileEntityDestroyedIsInvalid( int tileEntityId ) -{ - return (tileEntityId == furnaceTileEntityId); -} +#include "FurnaceMenu.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/tile/entity/FurnaceTileEntity.hpp" + +FurnaceMenu::FurnaceMenu( FurnaceTileEntity* furnace ) +: super(ContainerType::FURNACE), + furnace(furnace), + lastTickCount(0), + lastLitTime(0), + lastLitDuration(0) +{ + furnaceTileEntityId = furnace->runningId; +} + +void FurnaceMenu::setSlot( int slot, ItemInstance* item ) +{ + furnace->setItem(slot, item); +} + +void FurnaceMenu::setData( int id, int value ) +{ + if (id == 0) furnace->tickCount = value; + if (id == 1) furnace->litTime = value; + if (id == 2) furnace->litDuration = value; +} + +std::vector FurnaceMenu::getItems() +{ + std::vector out; + for (int i = 0; i < furnace->getContainerSize(); ++i) + out.push_back(*furnace->getItem(i)); + return out; +} + +void FurnaceMenu::broadcastChanges() +{ + super::broadcastChanges(); + + if (!listener) + return; + + //LOGI("broadcast: Derived: data: %d, %d : %d, %d\n", furnace->tickCount, lastTickCount, furnace->litTime, lastLitTime); + + if (furnace->tickCount != lastTickCount) { + listener->setContainerData(this, 0, furnace->tickCount); + lastTickCount = furnace->tickCount; + } + if (furnace->litTime != lastLitTime) { + listener->setContainerData(this, 1, furnace->litTime); + lastLitTime = furnace->litTime; + } + if (furnace->litDuration != lastLitDuration) { + listener->setContainerData(this, 2, furnace->litDuration); + lastLitDuration = furnace->litDuration; + } +} + +void FurnaceMenu::setListener( IContainerListener* listener ) +{ + super::setListener(listener); + + if (listener) { + listener->setContainerData(this, 0, furnace->tickCount); + listener->setContainerData(this, 1, furnace->litTime); + listener->setContainerData(this, 2, furnace->litDuration); + } +} + +bool FurnaceMenu::tileEntityDestroyedIsInvalid( int tileEntityId ) +{ + return (tileEntityId == furnaceTileEntityId); +} diff --git a/src/world/inventory/FurnaceMenu.h b/src/world/inventory/FurnaceMenu.hpp similarity index 95% rename from src/world/inventory/FurnaceMenu.h rename to src/world/inventory/FurnaceMenu.hpp index a9b36e9..facb1ac 100755 --- a/src/world/inventory/FurnaceMenu.h +++ b/src/world/inventory/FurnaceMenu.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.inventory; -#include "BaseContainerMenu.h" +#include "BaseContainerMenu.hpp" #include class FurnaceTileEntity; diff --git a/src/world/item/ArmorItem.cpp b/src/world/item/ArmorItem.cpp index 1580cc0..69730ac 100755 --- a/src/world/item/ArmorItem.cpp +++ b/src/world/item/ArmorItem.cpp @@ -1,77 +1,77 @@ -#include "ArmorItem.h" - -// -// ArmorMaterial -// -ArmorItem::ArmorMaterial::ArmorMaterial( int durabilityMultiplier, int p0, int p1, int p2, int p3 ) - : durabilityMultiplier(durabilityMultiplier) -{ - slotProtections[0] = p0; - slotProtections[1] = p1; - slotProtections[2] = p2; - slotProtections[3] = p3; - //this->enchantmentValue = enchantmentValue; -} - -int ArmorItem::ArmorMaterial::getHealthForSlot( int slot ) const { - return healthPerSlot[slot] * durabilityMultiplier; -} - -int ArmorItem::ArmorMaterial::getDefenseForSlot( int slot ) const { - return slotProtections[slot]; -} - -// -// ArmorItem -// -const int ArmorItem::healthPerSlot[4] = { - 11, 16, 15, 13 -}; - -ArmorItem::ArmorItem( int id, const ArmorMaterial& armorType, int icon, int slot ) : super(id), - armorType(armorType), - slot(slot), - modelIndex(icon), - defense(armorType.getDefenseForSlot(slot)) -{ - setMaxDamage(armorType.getHealthForSlot(slot)); - maxStackSize = 1; -} - -bool ArmorItem::isArmor() const { - return true; -} - -// -// Singleton ArmorMaterials -// - -const ArmorItem::ArmorMaterial ArmorItem::CLOTH( - 5, // durability - 1, 3, 2, 1 // protection values - //15, // enchantment -); - -const ArmorItem::ArmorMaterial ArmorItem::CHAIN( - 15, - 2, 5, 4, 1 - //12, -); - -const ArmorItem::ArmorMaterial ArmorItem::IRON( - 15, - 2, 6, 5, 2 - //9 -); - -const ArmorItem::ArmorMaterial ArmorItem::GOLD( - 7, - 2, 5, 3, 1 - //25 -); - -const ArmorItem::ArmorMaterial ArmorItem::DIAMOND( - 33, - 3, 8, 6, 3 - //10 -); +#include "ArmorItem.hpp" + +// +// ArmorMaterial +// +ArmorItem::ArmorMaterial::ArmorMaterial( int durabilityMultiplier, int p0, int p1, int p2, int p3 ) + : durabilityMultiplier(durabilityMultiplier) +{ + slotProtections[0] = p0; + slotProtections[1] = p1; + slotProtections[2] = p2; + slotProtections[3] = p3; + //this->enchantmentValue = enchantmentValue; +} + +int ArmorItem::ArmorMaterial::getHealthForSlot( int slot ) const { + return healthPerSlot[slot] * durabilityMultiplier; +} + +int ArmorItem::ArmorMaterial::getDefenseForSlot( int slot ) const { + return slotProtections[slot]; +} + +// +// ArmorItem +// +const int ArmorItem::healthPerSlot[4] = { + 11, 16, 15, 13 +}; + +ArmorItem::ArmorItem( int id, const ArmorMaterial& armorType, int icon, int slot ) : super(id), + armorType(armorType), + slot(slot), + modelIndex(icon), + defense(armorType.getDefenseForSlot(slot)) +{ + setMaxDamage(armorType.getHealthForSlot(slot)); + maxStackSize = 1; +} + +bool ArmorItem::isArmor() const { + return true; +} + +// +// Singleton ArmorMaterials +// + +const ArmorItem::ArmorMaterial ArmorItem::CLOTH( + 5, // durability + 1, 3, 2, 1 // protection values + //15, // enchantment +); + +const ArmorItem::ArmorMaterial ArmorItem::CHAIN( + 15, + 2, 5, 4, 1 + //12, +); + +const ArmorItem::ArmorMaterial ArmorItem::IRON( + 15, + 2, 6, 5, 2 + //9 +); + +const ArmorItem::ArmorMaterial ArmorItem::GOLD( + 7, + 2, 5, 3, 1 + //25 +); + +const ArmorItem::ArmorMaterial ArmorItem::DIAMOND( + 33, + 3, 8, 6, 3 + //10 +); diff --git a/src/world/item/ArmorItem.h b/src/world/item/ArmorItem.hpp similarity index 98% rename from src/world/item/ArmorItem.h rename to src/world/item/ArmorItem.hpp index 9e90c34..35dfc8a 100755 --- a/src/world/item/ArmorItem.h +++ b/src/world/item/ArmorItem.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.item; -#include "Item.h" +#include "Item.hpp" class ArmorItem: public Item { diff --git a/src/world/item/AuxDataTileItem.h b/src/world/item/AuxDataTileItem.hpp similarity index 89% rename from src/world/item/AuxDataTileItem.h rename to src/world/item/AuxDataTileItem.hpp index 1bc433f..7430876 100755 --- a/src/world/item/AuxDataTileItem.h +++ b/src/world/item/AuxDataTileItem.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.item; -#include "TileItem.h" -#include "../level/tile/Tile.h" +#include "TileItem.hpp" +#include "world/level/tile/Tile.hpp" class AuxDataTileItem: public TileItem { diff --git a/src/world/item/BedItem.cpp b/src/world/item/BedItem.cpp index 8a96878..2d7ff8d 100755 --- a/src/world/item/BedItem.cpp +++ b/src/world/item/BedItem.cpp @@ -1,36 +1,36 @@ -#include "BedItem.h" -#include "../level/Level.h" -#include "../level/tile/BedTile.h" -#include "../entity/player/Player.h" -#include "../Direction.h" -#include "../Facing.h" -bool BedItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) { - if(face != Facing::UP) { - return false; - } - y += 1; - BedTile *tile = (BedTile*) Tile::bed; - int dir = (Mth::floor(player->yRot * 4 / (360) + 0.5f)) & 3; - int xra = 0; - int zra = 0; - - if (dir == Direction::SOUTH) zra = 1; - if (dir == Direction::WEST) xra = -1; - if (dir == Direction::NORTH) zra = -1; - if (dir == Direction::EAST) xra = 1; - - //if (!player->mayBuild(x, y, z) || !player->mayBuild(x + xra, y, z + zra)) return false; - if (level->isEmptyTile(x, y, z) && level->isEmptyTile(x + xra, y, z + zra) && level->isSolidBlockingTile(x, y - 1, z) && level->isSolidBlockingTile(x + xra, y - 1, z + zra)) { - - level->setTileAndData(x, y, z, tile->id, dir); - // double-check that the bed was successfully placed - if (level->getTile(x, y, z) == tile->id) { - level->setTileAndData(x + xra, y, z + zra, tile->id, dir + BedTile::HEAD_PIECE_DATA); - } - - itemInstance->count--; - return true; - } - - return false; +#include "BedItem.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/BedTile.hpp" +#include "world/entity/player/Player.hpp" +#include "world/Direction.hpp" +#include "world/Facing.hpp" +bool BedItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) { + if(face != Facing::UP) { + return false; + } + y += 1; + BedTile *tile = (BedTile*) Tile::bed; + int dir = (Mth::floor(player->yRot * 4 / (360) + 0.5f)) & 3; + int xra = 0; + int zra = 0; + + if (dir == Direction::SOUTH) zra = 1; + if (dir == Direction::WEST) xra = -1; + if (dir == Direction::NORTH) zra = -1; + if (dir == Direction::EAST) xra = 1; + + //if (!player->mayBuild(x, y, z) || !player->mayBuild(x + xra, y, z + zra)) return false; + if (level->isEmptyTile(x, y, z) && level->isEmptyTile(x + xra, y, z + zra) && level->isSolidBlockingTile(x, y - 1, z) && level->isSolidBlockingTile(x + xra, y - 1, z + zra)) { + + level->setTileAndData(x, y, z, tile->id, dir); + // double-check that the bed was successfully placed + if (level->getTile(x, y, z) == tile->id) { + level->setTileAndData(x + xra, y, z + zra, tile->id, dir + BedTile::HEAD_PIECE_DATA); + } + + itemInstance->count--; + return true; + } + + return false; } \ No newline at end of file diff --git a/src/world/item/BedItem.h b/src/world/item/BedItem.hpp similarity index 93% rename from src/world/item/BedItem.h rename to src/world/item/BedItem.hpp index 3bcd25a..b723155 100755 --- a/src/world/item/BedItem.h +++ b/src/world/item/BedItem.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Item.h" +#include "Item.hpp" class Player; class ItemInstance; class Level; diff --git a/src/world/item/BowItem.h b/src/world/item/BowItem.hpp similarity index 89% rename from src/world/item/BowItem.h rename to src/world/item/BowItem.hpp index 1aed30f..e7d3934 100755 --- a/src/world/item/BowItem.h +++ b/src/world/item/BowItem.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.item; -#include "Item.h" +#include "Item.hpp" -#include "../entity/player/Player.h" -#include "../entity/projectile/Arrow.h" -#include "../level/Level.h" -#include "../entity/player/Inventory.h" +#include "world/entity/player/Player.hpp" +#include "world/entity/projectile/Arrow.hpp" +#include "world/level/Level.hpp" +#include "world/entity/player/Inventory.hpp" class BowItem: public Item { diff --git a/src/world/item/BowlFoodItem.h b/src/world/item/BowlFoodItem.hpp similarity index 94% rename from src/world/item/BowlFoodItem.h rename to src/world/item/BowlFoodItem.hpp index 90d74aa..b75bf74 100755 --- a/src/world/item/BowlFoodItem.h +++ b/src/world/item/BowlFoodItem.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.item; -#include "FoodItem.h" +#include "FoodItem.hpp" class BowlFoodItem: public FoodItem { diff --git a/src/world/item/CameraItem.h b/src/world/item/CameraItem.hpp similarity index 65% rename from src/world/item/CameraItem.h rename to src/world/item/CameraItem.hpp index 74803ea..d749059 100755 --- a/src/world/item/CameraItem.h +++ b/src/world/item/CameraItem.hpp @@ -1,10 +1,10 @@ #pragma once -#include "Item.h" -#include "ItemInstance.h" -#include "../level/Level.h" -#include "../entity/player/Player.h" -#include "../entity/item/TripodCamera.h" +#include "Item.hpp" +#include "ItemInstance.hpp" +#include "world/level/Level.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/item/TripodCamera.hpp" class CameraItem: public Item { diff --git a/src/world/item/ClothTileItem.h b/src/world/item/ClothTileItem.hpp similarity index 88% rename from src/world/item/ClothTileItem.h rename to src/world/item/ClothTileItem.hpp index 761ddcc..bd279f2 100755 --- a/src/world/item/ClothTileItem.h +++ b/src/world/item/ClothTileItem.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.item; -#include "TileItem.h" -#include "DyePowderItem.h" -#include "../level/tile/ClothTile.h" +#include "TileItem.hpp" +#include "DyePowderItem.hpp" +#include "world/level/tile/ClothTile.hpp" class ClothTileItem: public TileItem { diff --git a/src/world/item/CoalItem.h b/src/world/item/CoalItem.hpp similarity index 100% rename from src/world/item/CoalItem.h rename to src/world/item/CoalItem.hpp diff --git a/src/world/item/DiggerItem.h b/src/world/item/DiggerItem.hpp similarity index 95% rename from src/world/item/DiggerItem.h rename to src/world/item/DiggerItem.hpp index ccf15ae..554c1c1 100755 --- a/src/world/item/DiggerItem.h +++ b/src/world/item/DiggerItem.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.item; -#include "../level/tile/Tile.h" +#include "world/level/tile/Tile.hpp" -#include "Item.h" -#include "ItemInstance.h" +#include "Item.hpp" +#include "ItemInstance.hpp" class DiggerItem: public Item { diff --git a/src/world/item/DoorItem.h b/src/world/item/DoorItem.hpp similarity index 88% rename from src/world/item/DoorItem.h rename to src/world/item/DoorItem.hpp index 3772d65..f286702 100755 --- a/src/world/item/DoorItem.h +++ b/src/world/item/DoorItem.hpp @@ -2,14 +2,14 @@ //package net.minecraft.world.item; -#include "Item.h" -#include "ItemInstance.h" -#include "../Facing.h" -#include "../entity/player/Player.h" -#include "../level/Level.h" -#include "../level/material/Material.h" -#include "../level/tile/Tile.h" -#include "../../util/Mth.h" +#include "Item.hpp" +#include "ItemInstance.hpp" +#include "world/Facing.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Mth.hpp" class DoorItem: public Item { diff --git a/src/world/item/DyePowderItem.cpp b/src/world/item/DyePowderItem.cpp index 11c7964..01641df 100755 --- a/src/world/item/DyePowderItem.cpp +++ b/src/world/item/DyePowderItem.cpp @@ -1,122 +1,122 @@ -#include "DyePowderItem.h" -#include "../entity/Mob.h" -#include "../entity/animal/Sheep.h" -#include "../entity/player/Player.h" -#include "../level/Level.h" -#include "../level/tile/Tile.h" -#include "../level/tile/Sapling.h" -#include "../level/tile/GrassTile.h" -#include "../../util/Mth.h" -#include "../level/tile/ClothTile.h" -#include "../level/tile/CropTile.h" -#include "../level/tile/StemTile.h" - -const std::string DyePowderItem::COLOR_DESCS[] = { - "black", "red", "green", "brown", "blue", "purple", "cyan", "silver", "gray", "pink", "lime", "yellow", "lightBlue", "magenta", "orange", "white" -}; - -const int DyePowderItem::COLOR_RGB[] = { - 0x1e1b1b, 0xb3312c, 0x3b511a, 0x51301a, 0x253192, 0x7b2fbe, 0x287697, 0x287697, 0x434343, 0xd88198, 0x41cd34, 0xdecf2a, 0x6689d3, 0xc354cd, 0xeb8844, 0xf0f0f0 -}; - -DyePowderItem::DyePowderItem( int id ) -: super(id) -{ - setStackedByData(true); - setMaxDamage(0); -} - -int DyePowderItem::getIcon( int itemAuxValue ) -{ - int colorValue = Mth::clamp(itemAuxValue, 0, 15); - return icon + (colorValue % 8) * ICON_COLUMNS + (colorValue / 8); -} - -std::string DyePowderItem::getDescriptionId( const ItemInstance* itemInstance ) const -{ - int colorValue = Mth::clamp(itemInstance->getAuxValue(), 0, 15); - return super::getDescriptionId() + "." + COLOR_DESCS[colorValue]; -} - -bool DyePowderItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) -{ - //if (!player->mayBuild(x, y, z)) return false; - - if (itemInstance->getAuxValue() == WHITE) { - // bone meal is a fertilizer, so instantly grow trees and stuff - - int tile = level->getTile(x, y, z); - if (tile == Tile::sapling->id) { - if (!level->isClientSide) { - ((Sapling*) Tile::sapling)->growTree(level, x, y, z, &level->random); - } - itemInstance->count--; - return true; - } /*else if (tile == Tile::mushroom1->id || tile == Tile::mushroom2->id) { - if (!level->isOnline) { - if (((Mushroom) Tile::tiles[tile]).growTree(level, x, y, z, level->random)) { - itemInstance.count--; - } - } - return true; - }*/ else if (tile == Tile::melonStem->id/* || tile == Tile::pumpkinStem->id*/) { - if (!level->isClientSide) { - ((StemTile*) Tile::tiles[tile])->growCropsToMax(level, x, y, z); - } - itemInstance->count--; - return true; - } else if (tile == Tile::crops->id) { - if (!level->isClientSide) { - ((CropTile*) Tile::crops)->growCropsToMax(level, x, y, z); - } - itemInstance->count--; - } else if (tile == Tile::grass->id) { - if (!level->isClientSide) { - - for (int j = 0; j < 32; j++) { - int xx = x; - int yy = y + 1; - int zz = z; - bool continueMainLoop = false; - for (int i = 0; i < j / 16; i++) { - xx += random.nextInt(3) - 1; - yy += (random.nextInt(3) - 1) * random.nextInt(3) / 2; - zz += random.nextInt(3) - 1; - if (level->getTile(xx, yy - 1, zz) != Tile::grass->id || level->isSolidBlockingTile(xx, yy, zz)) { - continueMainLoop = true; - break; - } - } - if(continueMainLoop) - continue; - - if (level->getTile(xx, yy, zz) == 0) { - /*if (random.nextInt(10) != 0) { - level->setTileAndData(xx, yy, zz, Tile::tallgrass.id, TallGrass.TALL_GRASS); - } else*/ if (random.nextInt(3) != 0) { - level->setTile(xx, yy, zz, Tile::flower->id); - } else { - level->setTile(xx, yy, zz, Tile::rose->id); - } - } - } - } - itemInstance->count--; - return true; - } - } - return false; -} - -void DyePowderItem::interactEnemy( ItemInstance* itemInstance, Mob* mob ) -{ - if (mob->getEntityTypeId() == MobTypes::Sheep) { - Sheep* sheep = (Sheep*) mob; - // convert to tile-based color value (0 is white instead of black) - int newColor = ClothTile::getTileDataForItemAuxValue(itemInstance->getAuxValue()); - if (!sheep->isSheared() && sheep->getColor() != newColor) { - sheep->setColor(newColor); - itemInstance->count--; - } - } -} +#include "DyePowderItem.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/animal/Sheep.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/Sapling.hpp" +#include "world/level/tile/GrassTile.hpp" +#include "util/Mth.hpp" +#include "world/level/tile/ClothTile.hpp" +#include "world/level/tile/CropTile.hpp" +#include "world/level/tile/StemTile.hpp" + +const std::string DyePowderItem::COLOR_DESCS[] = { + "black", "red", "green", "brown", "blue", "purple", "cyan", "silver", "gray", "pink", "lime", "yellow", "lightBlue", "magenta", "orange", "white" +}; + +const int DyePowderItem::COLOR_RGB[] = { + 0x1e1b1b, 0xb3312c, 0x3b511a, 0x51301a, 0x253192, 0x7b2fbe, 0x287697, 0x287697, 0x434343, 0xd88198, 0x41cd34, 0xdecf2a, 0x6689d3, 0xc354cd, 0xeb8844, 0xf0f0f0 +}; + +DyePowderItem::DyePowderItem( int id ) +: super(id) +{ + setStackedByData(true); + setMaxDamage(0); +} + +int DyePowderItem::getIcon( int itemAuxValue ) +{ + int colorValue = Mth::clamp(itemAuxValue, 0, 15); + return icon + (colorValue % 8) * ICON_COLUMNS + (colorValue / 8); +} + +std::string DyePowderItem::getDescriptionId( const ItemInstance* itemInstance ) const +{ + int colorValue = Mth::clamp(itemInstance->getAuxValue(), 0, 15); + return super::getDescriptionId() + "." + COLOR_DESCS[colorValue]; +} + +bool DyePowderItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) +{ + //if (!player->mayBuild(x, y, z)) return false; + + if (itemInstance->getAuxValue() == WHITE) { + // bone meal is a fertilizer, so instantly grow trees and stuff + + int tile = level->getTile(x, y, z); + if (tile == Tile::sapling->id) { + if (!level->isClientSide) { + ((Sapling*) Tile::sapling)->growTree(level, x, y, z, &level->random); + } + itemInstance->count--; + return true; + } /*else if (tile == Tile::mushroom1->id || tile == Tile::mushroom2->id) { + if (!level->isOnline) { + if (((Mushroom) Tile::tiles[tile]).growTree(level, x, y, z, level->random)) { + itemInstance.count--; + } + } + return true; + }*/ else if (tile == Tile::melonStem->id/* || tile == Tile::pumpkinStem->id*/) { + if (!level->isClientSide) { + ((StemTile*) Tile::tiles[tile])->growCropsToMax(level, x, y, z); + } + itemInstance->count--; + return true; + } else if (tile == Tile::crops->id) { + if (!level->isClientSide) { + ((CropTile*) Tile::crops)->growCropsToMax(level, x, y, z); + } + itemInstance->count--; + } else if (tile == Tile::grass->id) { + if (!level->isClientSide) { + + for (int j = 0; j < 32; j++) { + int xx = x; + int yy = y + 1; + int zz = z; + bool continueMainLoop = false; + for (int i = 0; i < j / 16; i++) { + xx += random.nextInt(3) - 1; + yy += (random.nextInt(3) - 1) * random.nextInt(3) / 2; + zz += random.nextInt(3) - 1; + if (level->getTile(xx, yy - 1, zz) != Tile::grass->id || level->isSolidBlockingTile(xx, yy, zz)) { + continueMainLoop = true; + break; + } + } + if(continueMainLoop) + continue; + + if (level->getTile(xx, yy, zz) == 0) { + /*if (random.nextInt(10) != 0) { + level->setTileAndData(xx, yy, zz, Tile::tallgrass.id, TallGrass.TALL_GRASS); + } else*/ if (random.nextInt(3) != 0) { + level->setTile(xx, yy, zz, Tile::flower->id); + } else { + level->setTile(xx, yy, zz, Tile::rose->id); + } + } + } + } + itemInstance->count--; + return true; + } + } + return false; +} + +void DyePowderItem::interactEnemy( ItemInstance* itemInstance, Mob* mob ) +{ + if (mob->getEntityTypeId() == MobTypes::Sheep) { + Sheep* sheep = (Sheep*) mob; + // convert to tile-based color value (0 is white instead of black) + int newColor = ClothTile::getTileDataForItemAuxValue(itemInstance->getAuxValue()); + if (!sheep->isSheared() && sheep->getColor() != newColor) { + sheep->setColor(newColor); + itemInstance->count--; + } + } +} diff --git a/src/world/item/DyePowderItem.h b/src/world/item/DyePowderItem.hpp similarity index 98% rename from src/world/item/DyePowderItem.h rename to src/world/item/DyePowderItem.hpp index d13317e..cf31a9a 100755 --- a/src/world/item/DyePowderItem.h +++ b/src/world/item/DyePowderItem.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.item; -#include "Item.h" +#include "Item.hpp" #include class ItemInstance; diff --git a/src/world/item/EggItem.h b/src/world/item/EggItem.hpp similarity index 79% rename from src/world/item/EggItem.h rename to src/world/item/EggItem.hpp index 0f37e25..de80647 100755 --- a/src/world/item/EggItem.h +++ b/src/world/item/EggItem.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.item; -#include "Item.h" +#include "Item.hpp" -#include "../entity/player/Player.h" -#include "../entity/projectile/ThrownEgg.h" -#include "../level/Level.h" +#include "world/entity/player/Player.hpp" +#include "world/entity/projectile/ThrownEgg.hpp" +#include "world/level/Level.hpp" class EggItem: public Item { diff --git a/src/world/item/FlintAndSteelItem.h b/src/world/item/FlintAndSteelItem.hpp similarity index 86% rename from src/world/item/FlintAndSteelItem.h rename to src/world/item/FlintAndSteelItem.hpp index b436f14..890a8c4 100755 --- a/src/world/item/FlintAndSteelItem.h +++ b/src/world/item/FlintAndSteelItem.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.item; -#include "Item.h" -#include "../level/Level.h" -#include "../level/tile/Tile.h" -#include "../entity/player/Player.h" +#include "Item.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/entity/player/Player.hpp" class FlintAndSteelItem: public Item { diff --git a/src/world/item/FoodItem.h b/src/world/item/FoodItem.hpp similarity index 87% rename from src/world/item/FoodItem.h rename to src/world/item/FoodItem.hpp index fc24832..549d638 100755 --- a/src/world/item/FoodItem.h +++ b/src/world/item/FoodItem.hpp @@ -2,13 +2,13 @@ //package net.minecraft.world.item; -#include "Item.h" -#include "../level/Level.h" -#include "../entity/player/Player.h" -#include "../../SharedConstants.h" -#include "../../network/packet/SetHealthPacket.h" -//#include "../effect/MobEffectInstance.h" -//#include "../food/FoodConstants.h" +#include "Item.hpp" +#include "world/level/Level.hpp" +#include "world/entity/player/Player.hpp" +#include "SharedConstants.hpp" +#include "network/packet/SetHealthPacket.hpp" +//#include "world/effect/MobEffectInstance.hpp" +//#include "world/food/FoodConstants.hpp" class FoodItem: public Item { diff --git a/src/world/item/HangingEntityItem.cpp b/src/world/item/HangingEntityItem.cpp index d8cc436..c4ad3bb 100755 --- a/src/world/item/HangingEntityItem.cpp +++ b/src/world/item/HangingEntityItem.cpp @@ -1,43 +1,43 @@ -#include "HangingEntityItem.h" -#include "../entity/HangingEntity.h" -#include "../Facing.h" -#include "../Direction.h" -#include "../level/Level.h" -#include "../entity/EntityFactory.h" -#include "../entity/Painting.h" -HangingEntityItem::HangingEntityItem( int id, int type ) : super(id), entityType(type) { - -} - -bool HangingEntityItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) { - if (face == Facing::DOWN) return false; - if (face == Facing::UP) return false; - - int dir = Direction::FACING_DIRECTION[face]; - - HangingEntity* entity = createEntity(level, x, y, z, dir); - //if (!player->mayUseItemAt(xt, yt, zt, face, instance)) return false; - if(entity != NULL) { - if (entity->survives()) { - if (!level->isClientSide) { - level->addEntity(entity); - } - else { - delete entity; - } - itemInstance->count--; - } - else { - delete entity; - } - } - return true; -} - -HangingEntity* HangingEntityItem::createEntity( Level* level, int x, int y, int z, int dir ) { - switch(entityType) { - case EntityTypes::IdPainting: return new Painting(level, x, y, z, dir); - } - return NULL; -} - +#include "HangingEntityItem.hpp" +#include "world/entity/HangingEntity.hpp" +#include "world/Facing.hpp" +#include "world/Direction.hpp" +#include "world/level/Level.hpp" +#include "world/entity/EntityFactory.hpp" +#include "world/entity/Painting.hpp" +HangingEntityItem::HangingEntityItem( int id, int type ) : super(id), entityType(type) { + +} + +bool HangingEntityItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) { + if (face == Facing::DOWN) return false; + if (face == Facing::UP) return false; + + int dir = Direction::FACING_DIRECTION[face]; + + HangingEntity* entity = createEntity(level, x, y, z, dir); + //if (!player->mayUseItemAt(xt, yt, zt, face, instance)) return false; + if(entity != NULL) { + if (entity->survives()) { + if (!level->isClientSide) { + level->addEntity(entity); + } + else { + delete entity; + } + itemInstance->count--; + } + else { + delete entity; + } + } + return true; +} + +HangingEntity* HangingEntityItem::createEntity( Level* level, int x, int y, int z, int dir ) { + switch(entityType) { + case EntityTypes::IdPainting: return new Painting(level, x, y, z, dir); + } + return NULL; +} + diff --git a/src/world/item/HangingEntityItem.h b/src/world/item/HangingEntityItem.hpp similarity index 95% rename from src/world/item/HangingEntityItem.h rename to src/world/item/HangingEntityItem.hpp index c35e46a..1c2002b 100755 --- a/src/world/item/HangingEntityItem.h +++ b/src/world/item/HangingEntityItem.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Item.h" +#include "Item.hpp" class HangingEntity; class HangingEntityItem : public Item { typedef Item super; diff --git a/src/world/item/HatchetItem.cpp b/src/world/item/HatchetItem.cpp index 21cc324..9d853fc 100755 --- a/src/world/item/HatchetItem.cpp +++ b/src/world/item/HatchetItem.cpp @@ -1,27 +1,27 @@ -#include "HatchetItem.h" -#include "../level/material/Material.h" -#include "../level/tile/Tile.h" - - -HatchetItem::HatchetItem( int id, const Tier& tier ) : super(id, 3, tier) -{ - TileList d; - d.push_back(Tile::wood); - d.push_back(Tile::bookshelf); - d.push_back(Tile::treeTrunk); - d.push_back(Tile::chest); - d.push_back(Tile::stoneSlab); - d.push_back(Tile::stoneSlabHalf); - //d.push_back(Tile::pumpkin); - //d.push_back(Tile::litPumpkin); - - setTiles(d); -} - -float HatchetItem::getDestroySpeed( ItemInstance* itemInstance, Tile* tile ) -{ - if (tile != NULL && tile->material == Material::wood) { - return speed; - } - return super::getDestroySpeed(itemInstance, tile); -} +#include "HatchetItem.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" + + +HatchetItem::HatchetItem( int id, const Tier& tier ) : super(id, 3, tier) +{ + TileList d; + d.push_back(Tile::wood); + d.push_back(Tile::bookshelf); + d.push_back(Tile::treeTrunk); + d.push_back(Tile::chest); + d.push_back(Tile::stoneSlab); + d.push_back(Tile::stoneSlabHalf); + //d.push_back(Tile::pumpkin); + //d.push_back(Tile::litPumpkin); + + setTiles(d); +} + +float HatchetItem::getDestroySpeed( ItemInstance* itemInstance, Tile* tile ) +{ + if (tile != NULL && tile->material == Material::wood) { + return speed; + } + return super::getDestroySpeed(itemInstance, tile); +} diff --git a/src/world/item/HatchetItem.h b/src/world/item/HatchetItem.hpp similarity index 92% rename from src/world/item/HatchetItem.h rename to src/world/item/HatchetItem.hpp index 9c0e927..a379edd 100755 --- a/src/world/item/HatchetItem.h +++ b/src/world/item/HatchetItem.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.item; -#include "DiggerItem.h" +#include "DiggerItem.hpp" #include class Tile; diff --git a/src/world/item/HoeItem.cpp b/src/world/item/HoeItem.cpp index f844f2b..f477195 100755 --- a/src/world/item/HoeItem.cpp +++ b/src/world/item/HoeItem.cpp @@ -1,40 +1,40 @@ -#include "HoeItem.h" -#include "../level/tile/Tile.h" -#include "../level/Level.h" -#include "../entity/item/ItemEntity.h" - -HoeItem::HoeItem( int id, Tier tier ) : super(id), tier(tier) { - maxStackSize = 1; - setMaxDamage(tier.getUses()); -} - -bool HoeItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) { - //if (!player.mayBuild(x, y, z)) return false; - - int targetType = level->getTile(x, y, z); - int above = level->getTile(x, y + 1, z); - - if (face != 0 && above == 0 && targetType == Tile::grass->id || targetType == Tile::dirt->id) { - Tile* tile = Tile::farmland; - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, tile->soundType->getStepSound(), (tile->soundType->getVolume() + 1) / 2, tile->soundType->getPitch() * 0.8f); - itemInstance->hurt(1/*, player*/); - if (level->isClientSide) return true; - level->setTile(x, y, z, tile->id); - if(targetType == Tile::grass->id && level->random.nextInt( 8 ) == 0) { - float s = 0.7f; - float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; - float yo = level->random.nextFloat() * s + (1 - s) * 2.5f; - float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; - ItemEntity* item = new ItemEntity(level, float(x) + xo, float(y) + yo, float(z) + zo, ItemInstance(Item::seeds_wheat)); - item->throwTime = 10; - level->addEntity(item); - } - return true; - } - - return false; -} - -bool HoeItem::isHandEquipped() const { - return true; -} +#include "HoeItem.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/Level.hpp" +#include "world/entity/item/ItemEntity.hpp" + +HoeItem::HoeItem( int id, Tier tier ) : super(id), tier(tier) { + maxStackSize = 1; + setMaxDamage(tier.getUses()); +} + +bool HoeItem::useOn( ItemInstance* itemInstance, Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ ) { + //if (!player.mayBuild(x, y, z)) return false; + + int targetType = level->getTile(x, y, z); + int above = level->getTile(x, y + 1, z); + + if (face != 0 && above == 0 && targetType == Tile::grass->id || targetType == Tile::dirt->id) { + Tile* tile = Tile::farmland; + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, tile->soundType->getStepSound(), (tile->soundType->getVolume() + 1) / 2, tile->soundType->getPitch() * 0.8f); + itemInstance->hurt(1/*, player*/); + if (level->isClientSide) return true; + level->setTile(x, y, z, tile->id); + if(targetType == Tile::grass->id && level->random.nextInt( 8 ) == 0) { + float s = 0.7f; + float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; + float yo = level->random.nextFloat() * s + (1 - s) * 2.5f; + float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; + ItemEntity* item = new ItemEntity(level, float(x) + xo, float(y) + yo, float(z) + zo, ItemInstance(Item::seeds_wheat)); + item->throwTime = 10; + level->addEntity(item); + } + return true; + } + + return false; +} + +bool HoeItem::isHandEquipped() const { + return true; +} diff --git a/src/world/item/HoeItem.h b/src/world/item/HoeItem.hpp similarity index 93% rename from src/world/item/HoeItem.h rename to src/world/item/HoeItem.hpp index 2bed570..8633716 100755 --- a/src/world/item/HoeItem.h +++ b/src/world/item/HoeItem.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Item.h" +#include "Item.hpp" class HoeItem : public Item { typedef Item super; diff --git a/src/world/item/Item.cpp b/src/world/item/Item.cpp index 1430743..38ec921 100755 --- a/src/world/item/Item.cpp +++ b/src/world/item/Item.cpp @@ -1,308 +1,308 @@ -#include "ItemInclude.h" -#include "ItemCategory.h" -#include "../level/tile/Tile.h" -#include "ItemInstance.h" - -const std::string Item::ICON_DESCRIPTION_PREFIX("item."); -Random Item::random; - -Item* Item::items[MAX_ITEMS] = {NULL}; - -Item::Tier const Item::Tier::WOOD(0, 59, 2, 0); -Item::Tier const Item::Tier::STONE(1, 131, 4, 1); -Item::Tier const Item::Tier::IRON(2, 250, 6, 2); -Item::Tier const Item::Tier::EMERALD(3, 1561, 8, 3); -Item::Tier const Item::Tier::GOLD(0, 32, 12, 0); - -// Static Item Definitions -Item* Item::shovel_iron = NULL; -Item* Item::pickAxe_iron = NULL; -Item* Item::hatchet_iron = NULL; -Item* Item::flintAndSteel = NULL; -Item* Item::apple = NULL; -Item* Item::bow = NULL; -Item* Item::arrow = NULL; -Item* Item::coal = NULL; -Item* Item::emerald = NULL; -Item* Item::ironIngot = NULL; -Item* Item::goldIngot = NULL; -Item* Item::sword_iron = NULL; - -Item* Item::sword_wood = NULL; -Item* Item::shovel_wood = NULL; -Item* Item::pickAxe_wood = NULL; -Item* Item::hatchet_wood = NULL; - -Item* Item::sword_stone = NULL; -Item* Item::shovel_stone = NULL; -Item* Item::pickAxe_stone = NULL; -Item* Item::hatchet_stone = NULL; - -Item* Item::sword_emerald = NULL; -Item* Item::shovel_emerald = NULL; -Item* Item::pickAxe_emerald = NULL; -Item* Item::hatchet_emerald = NULL; - -Item* Item::stick = NULL; -Item* Item::bowl = NULL; -Item* Item::mushroomStew = NULL; - -Item* Item::sword_gold = NULL; -Item* Item::shovel_gold = NULL; -Item* Item::pickAxe_gold = NULL; -Item* Item::hatchet_gold = NULL; - -Item* Item::string = NULL; -Item* Item::feather = NULL; -Item* Item::sulphur = NULL; - -Item* Item::hoe_wood = NULL; -Item* Item::hoe_stone = NULL; -Item* Item::hoe_iron = NULL; -Item* Item::hoe_emerald = NULL; -Item* Item::hoe_gold = NULL; - -Item* Item::seeds_wheat = NULL; -Item* Item::wheat = NULL; -Item* Item::bread = NULL; - -Item* Item::helmet_cloth = NULL; -Item* Item::chestplate_cloth = NULL; -Item* Item::leggings_cloth = NULL; -Item* Item::boots_cloth = NULL; - -Item* Item::helmet_chain = NULL; -Item* Item::chestplate_chain = NULL; -Item* Item::leggings_chain = NULL; -Item* Item::boots_chain = NULL; - -Item* Item::helmet_iron = NULL; -Item* Item::chestplate_iron = NULL; -Item* Item::leggings_iron = NULL; -Item* Item::boots_iron = NULL; - -Item* Item::helmet_diamond = NULL; -Item* Item::chestplate_diamond = NULL; -Item* Item::leggings_diamond = NULL; -Item* Item::boots_diamond = NULL; - -Item* Item::helmet_gold = NULL; -Item* Item::chestplate_gold = NULL; -Item* Item::leggings_gold = NULL; -Item* Item::boots_gold = NULL; - -Item* Item::flint = NULL; -Item* Item::porkChop_raw = NULL; -Item* Item::porkChop_cooked = NULL; -Item* Item::painting = NULL; - -//Item* Item::apple_gold = NULL; - -Item* Item::sign = NULL; -Item* Item::door_wood = NULL; - -//Item* Item::bucket_empty = NULL; -//Item* Item::bucket_water = NULL; -//Item* Item::bucket_lava = NULL; - -//Item* Item::minecart = NULL; -//Item* Item::saddle = NULL; -Item* Item::door_iron = NULL; -//Item* Item::redStone = NULL; -Item* Item::snowBall = NULL; - -//Item* Item::boat = NULL; - -Item* Item::leather = NULL; -//Item* Item::milk = NULL; -Item* Item::brick = NULL; -Item* Item::clay = NULL; -Item* Item::reeds = NULL; -Item* Item::paper = NULL; -Item* Item::book = NULL; -Item* Item::slimeBall = NULL; -//Item* Item::minecart_chest = NULL; -//Item* Item::minecart_furnace = NULL; -Item* Item::egg = NULL; -Item* Item::compass = NULL; -//Item* Item::fishingRod = NULL; -Item* Item::clock = NULL; -Item* Item::yellowDust = NULL; -//Item* Item::fish_raw = NULL; -//Item* Item::fish_cooked = NULL; - -Item* Item::melon = NULL; -Item* Item::seeds_melon = NULL; - -Item* Item::dye_powder = NULL; -Item* Item::bone = NULL; -Item* Item::sugar = NULL; -//Item* Item::cake = NULL; - -Item* Item::bed = NULL; - -//Item* Item::diode = NULL; -ShearsItem* Item::shears = NULL; -Item* Item::beef_raw = NULL; -Item* Item::beef_cooked = NULL; -Item* Item::chicken_raw = NULL; -Item* Item::chicken_cooked = NULL; - -Item* Item::netherbrick = NULL; -Item* Item::netherQuartz = NULL; - -//Item* Item::record_01 = NULL; -//Item* Item::record_02 = NULL; - -Item* Item::camera = NULL; - -/*static*/ -void Item::initItems() { - static bool isInited = false; - - if (isInited) - return; - - isInited = true; - - Item::shovel_iron = (new ShovelItem(0, Tier::IRON))->setIcon(2, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelIron"); - Item::pickAxe_iron = (new PickaxeItem(1, Tier::IRON))->setIcon(2, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeIron"); - Item::hatchet_iron = (new HatchetItem(2, Tier::IRON))->setIcon(2, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetIron"); - Item::flintAndSteel = (new FlintAndSteelItem(3))->setIcon(5, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("flintAndSteel"); - Item::apple = (new FoodItem(4, 4, false))->setIcon(10, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("apple"); - Item::bow = (new BowItem(5))->setIcon(5, 1)->setCategory(ItemCategory::Tools)->setDescriptionId("bow"); - Item::arrow = (new Item(6))->setIcon(5, 2)->setCategory(ItemCategory::Tools)->setDescriptionId("arrow"); - Item::coal = (new CoalItem(7))->setIcon(7, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("coal"); - Item::emerald = (new Item(8))->setIcon(7, 3)->setCategory(ItemCategory::Decorations)->setDescriptionId("emerald"); - Item::ironIngot = (new Item(9))->setIcon(7, 1)->setCategory(ItemCategory::Decorations)->setDescriptionId("ingotIron"); - Item::goldIngot = (new Item(10))->setIcon(7, 2)->setCategory(ItemCategory::Decorations)->setDescriptionId("ingotGold"); - Item::sword_iron = (new WeaponItem(11, Tier::IRON))->setIcon(2, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordIron"); - Item::sword_wood = (new WeaponItem(12, Tier::WOOD))->setIcon(0, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordWood"); - Item::shovel_wood = (new ShovelItem(13, Tier::WOOD))->setIcon(0, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelWood"); - Item::pickAxe_wood = (new PickaxeItem(14, Tier::WOOD))->setIcon(0, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeWood"); - Item::hatchet_wood = (new HatchetItem(15, Tier::WOOD))->setIcon(0, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetWood"); - Item::sword_stone = (new WeaponItem(16, Tier::STONE))->setIcon(1, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordStone"); - Item::shovel_stone = (new ShovelItem(17, Tier::STONE))->setIcon(1, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelStone"); - Item::pickAxe_stone = (new PickaxeItem(18, Tier::STONE))->setIcon(1, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeStone"); - Item::hatchet_stone = (new HatchetItem(19, Tier::STONE))->setIcon(1, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetStone"); - Item::sword_emerald = (new WeaponItem(20, Tier::EMERALD))->setIcon(3, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordDiamond"); - Item::shovel_emerald = (new ShovelItem(21, Tier::EMERALD))->setIcon(3, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelDiamond"); - Item::pickAxe_emerald = (new PickaxeItem(22, Tier::EMERALD))->setIcon(3, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeDiamond"); - Item::hatchet_emerald = (new HatchetItem(23, Tier::EMERALD))->setIcon(3, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetDiamond"); - Item::stick = (new Item(24))->setIcon(5, 3)->handEquipped()->setCategory(ItemCategory::Structures)->setDescriptionId("stick"); - Item::bowl = (new Item(25))->setIcon(7, 4)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bowl"); - Item::mushroomStew = (new BowlFoodItem(26, 8))->setIcon(8, 4)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("mushroomStew"); - Item::sword_gold = (new WeaponItem(27, Tier::GOLD))->setIcon(4, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordGold"); - Item::shovel_gold = (new ShovelItem(28, Tier::GOLD))->setIcon(4, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelGold"); - Item::pickAxe_gold = (new PickaxeItem(29, Tier::GOLD))->setIcon(4, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeGold"); - Item::hatchet_gold = (new HatchetItem(30, Tier::GOLD))->setIcon(4, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetGold"); - Item::string = (new Item(31))->setIcon(8, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("string"); - Item::feather = (new Item(32))->setIcon(8, 1)->setCategory(ItemCategory::Tools)->setDescriptionId("feather"); - Item::sulphur = (new Item(33))->setIcon(8, 2)->setCategory(ItemCategory::Tools)->setDescriptionId("sulphur"); - Item::hoe_wood = (new HoeItem(34, Tier::WOOD))->setIcon(0, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeWood"); - Item::hoe_stone = (new HoeItem(35, Tier::STONE))->setIcon(1, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeStone"); - Item::hoe_iron = (new HoeItem(36, Tier::IRON))->setIcon(2, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeIron"); - Item::hoe_emerald = (new HoeItem(37, Tier::EMERALD))->setIcon(3, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeDiamond"); - Item::hoe_gold = (new HoeItem(38, Tier::GOLD))->setIcon(4, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeGold"); - Item::seeds_wheat = (new SeedItem(39, Tile::crops->id, Tile::farmland->id))->setIcon(9, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("seeds"); - Item::wheat = (new Item(40))->setIcon(9, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("wheat"); - Item::bread = (new FoodItem(41, 5, false))->setIcon(9, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bread"); - - Item::helmet_cloth = (new ArmorItem(42, ArmorItem::CLOTH, 0, ArmorItem::SLOT_HEAD))->setIcon(0, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetCloth"); - Item::chestplate_cloth = (new ArmorItem(43, ArmorItem::CLOTH, 0, ArmorItem::SLOT_TORSO))->setIcon(0, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateCloth"); - Item::leggings_cloth = (new ArmorItem(44, ArmorItem::CLOTH, 0, ArmorItem::SLOT_LEGS))->setIcon(0, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsCloth"); - Item::boots_cloth = (new ArmorItem(45, ArmorItem::CLOTH, 0, ArmorItem::SLOT_FEET))->setIcon(0, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsCloth"); - - Item::helmet_chain = (new ArmorItem(46, ArmorItem::CHAIN, 1, ArmorItem::SLOT_HEAD))->setIcon(1, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetChain"); - Item::chestplate_chain = (new ArmorItem(47, ArmorItem::CHAIN, 1, ArmorItem::SLOT_TORSO))->setIcon(1, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateChain"); - Item::leggings_chain = (new ArmorItem(48, ArmorItem::CHAIN, 1, ArmorItem::SLOT_LEGS))->setIcon(1, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsChain"); - Item::boots_chain = (new ArmorItem(49, ArmorItem::CHAIN, 1, 3))->setIcon(1, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsChain"); - - Item::helmet_iron = (new ArmorItem(50, ArmorItem::IRON, 2, ArmorItem::SLOT_HEAD))->setIcon(2, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetIron"); - Item::chestplate_iron = (new ArmorItem(51, ArmorItem::IRON, 2, ArmorItem::SLOT_TORSO))->setIcon(2, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateIron"); - Item::leggings_iron = (new ArmorItem(52, ArmorItem::IRON, 2, ArmorItem::SLOT_LEGS))->setIcon(2, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsIron"); - Item::boots_iron = (new ArmorItem(53, ArmorItem::IRON, 2, ArmorItem::SLOT_FEET))->setIcon(2, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsIron"); - - Item::helmet_diamond = (new ArmorItem(54, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_HEAD))->setIcon(3, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetDiamond"); - Item::chestplate_diamond=(new ArmorItem(55, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_TORSO))->setIcon(3, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateDiamond"); - Item::leggings_diamond = (new ArmorItem(56, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_LEGS))->setIcon(3, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsDiamond"); - Item::boots_diamond = (new ArmorItem(57, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_FEET))->setIcon(3, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsDiamond"); - - Item::helmet_gold = (new ArmorItem(58, ArmorItem::GOLD, 4, ArmorItem::SLOT_HEAD))->setIcon(4, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetGold"); - Item::chestplate_gold = (new ArmorItem(59, ArmorItem::GOLD, 4, ArmorItem::SLOT_TORSO))->setIcon(4, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateGold"); - Item::leggings_gold = (new ArmorItem(60, ArmorItem::GOLD, 4, ArmorItem::SLOT_LEGS))->setIcon(4, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsGold"); - Item::boots_gold = (new ArmorItem(61, ArmorItem::GOLD, 4, ArmorItem::SLOT_FEET))->setIcon(4, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsGold"); - - Item::flint = (new Item(62))->setIcon(6, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("flint"); - Item::porkChop_raw = (new FoodItem(63, 3, true))->setIcon(7, 5)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("porkchopRaw"); - Item::porkChop_cooked = (new FoodItem(64, 8, true))->setIcon(8, 5)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("porkchopCooked"); - Item::painting = (new HangingEntityItem(65, EntityTypes::IdPainting))->setIcon(10, 1)->setCategory(ItemCategory::Decorations)->setDescriptionId("painting"); - //Item::apple_gold = (new FoodItem(66, 42, false))->setIcon(11, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("appleGold"); - Item::sign = (new SignItem(67))->setIcon(10, 2)->setCategory(ItemCategory::Decorations)->setDescriptionId("sign"); - Item::door_wood = (new DoorItem(68, Material::wood))->setIcon(11, 2)->setCategory(ItemCategory::Structures)->setDescriptionId("doorWood"); - //Item::bucket_empty = (new BucketItem(69, 0))->setIcon(10, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("bucket"); - //Item::bucket_water = (new BucketItem(70, Tile::water.id))->setIcon(11, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("bucketWater")->setCraftingRemainingItem(Item.bucket_empty); - //Item::bucket_lava = (new BucketItem(71, Tile::lava.id))->setIcon(12, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("bucketLava")->setCraftingRemainingItem(Item.bucket_empty); - //Item::minecart = (new MinecartItem(72, Minecart.RIDEABLE))->setIcon(7, 8)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("minecart"); - //Item::saddle = (new SaddleItem(73))->setIcon(8, 6)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("saddle"); - Item::door_iron = (new DoorItem(74, Material::metal))->setIcon(12, 2)->setCategory(ItemCategory::Structures)->setDescriptionId("doorIron"); - //Item::redStone = (new RedStoneItem(75))->setIcon(8, 3)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("redstone"); - Item::snowBall = (new SnowballItem(76))->setIcon(14, 0)->setCategory(ItemCategory::Decorations)->setDescriptionId("snowball"); - //Item::boat = (new BoatItem(77))->setIcon(8, 8)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("boat"); - Item::leather = (new Item(78))->setIcon(7, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("leather"); - //Item::milk = (new BucketItem(79, -1))->setIcon(13, 4)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("milk")->setCraftingRemainingItem(Item.bucket_empty); - Item::brick = (new Item(80))->setIcon(6, 1)->setCategory(ItemCategory::Structures)->setDescriptionId("brick"); - Item::clay = (new Item(81))->setIcon(9, 3)->setCategory(ItemCategory::Structures)->setDescriptionId("clay"); - Item::reeds = (new TilePlanterItem(82, Tile::reeds))->setIcon(11, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("reeds"); - Item::paper = (new Item(83))->setIcon(10, 3)->setCategory(ItemCategory::Decorations)->setDescriptionId("paper"); - Item::book = (new Item(84))->setIcon(11, 3)->setCategory(ItemCategory::Decorations)->setDescriptionId("book"); - Item::slimeBall = (new Item(85))->setIcon(14, 1)->setCategory(ItemCategory::Decorations)->setDescriptionId("slimeball"); - //Item::minecart_chest = (new MinecartItem(86, Minecart::CHEST))->setIcon(7, 9)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("minecartChest"); - //Item::minecart_furnace = (new MinecartItem(87, Minecart::FURNACE))->setIcon(7, 10)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("minecartFurnace"); - Item::egg = (new EggItem(88))->setIcon(12, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("egg"); - Item::compass = (new Item(89))->setIcon(6, 3)->setCategory(ItemCategory::Tools)->setDescriptionId("compass"); - //Item::fishingRod = (new FishingRodItem(90))->setIcon(5, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("fishingRod"); - Item::clock = (new Item(91))->setIcon(6, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("clock"); - Item::yellowDust = (new Item(92))->setIcon(9, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("yellowDust"); - //Item::fish_raw = (new FoodItem(93, 2, false))->setIcon(9, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("fishRaw"); - //Item::fish_cooked = (new FoodItem(94, 5, false))->setIcon(10, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("fishCooked"); - Item::dye_powder = (new DyePowderItem(95))->setIcon(14, 4)->setCategory(ItemCategory::Decorations)->setDescriptionId("dyePowder"); - Item::bone = (new Item(96))->setIcon(12, 1)->setCategory(ItemCategory::Tools)->setDescriptionId("bone")->handEquipped(); - Item::sugar = (new Item(97))->setIcon(13, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("sugar")->handEquipped(); - //Item::cake = (new TilePlanterItem(98, Tile::cake))->setMaxStackSize(1)->setIcon(13, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("cake"); - Item::bed = (new BedItem(99))->setMaxStackSize(1)->setIcon(13, 2)->setCategory(ItemCategory::Structures)->setDescriptionId("bed"); - //Item::diode = (new TilePlanterItem(100, Tile::diode_off))->setIcon(6, 5)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("diode"); - Item::shears = (ShearsItem*)(new ShearsItem(103))->setIcon(13, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shears"); - Item::melon = (new FoodItem(104, 2, false))->setIcon(13, 6)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("melon"); - Item::seeds_melon = (new SeedItem(106, Tile::melonStem->id, Tile::farmland->id))->setIcon(14, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("seedsMelon"); - Item::beef_raw = (new FoodItem(107, 3, /*FoodConstants.FOOD_SATURATION_LOW,*/ true))->setIcon(9, 6)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("beefRaw"); - Item::beef_cooked = (new FoodItem(108, 8, /*FoodConstants.FOOD_SATURATION_GOOD,*/ true))->setIcon(10, 6)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("beefCooked"); - Item::chicken_raw = (new FoodItem(109, 2, /*FoodConstants.FOOD_SATURATION_LOW,*/ true))->setIcon(9, 7)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chickenRaw"); - Item::chicken_cooked = (new FoodItem(110, 6, /*FoodConstants.FOOD_SATURATION_NORMAL,*/ true))->setIcon(10, 7)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chickenCooked"); - - Item::netherbrick = (new Item(149))->setIcon(5, 9)->setDescriptionId("netherbrickItem")->setCategory(ItemCategory::Structures); - Item::netherQuartz = (new Item(150))->setIcon(5, 10)->setDescriptionId("netherquartz")->setCategory(ItemCategory::Mechanisms); - - //Item::record_01 = (new RecordingItem(2000, "13"))->setIcon(0, 15)->setCategory(ItemCategory::Decorations)->setDescriptionId("record"); - //Item::record_02 = (new RecordingItem(2001, "cat"))->setIcon(1, 15)->setCategory(ItemCategory::Decorations)->setDescriptionId("record"); - Item::camera = (new CameraItem(200))->setIcon(2, 15)->setCategory(ItemCategory::Decorations)->setDescriptionId("camera"); - - for (int i = 256; i < MAX_ITEMS; ++i) { - if (items[i] && items[i]->category == -1) - LOGE("Error: Missing category for item %d: %s\n", items[i]->id, items[i]->getDescriptionId().c_str()); - } -} - -/*static*/ -void Item::teardownItems() { - for (int i = 0; i < MAX_ITEMS; ++i) - if (Item::items[i]) { - delete Item::items[i]; - Item::items[i] = NULL; - } -} - -ItemInstance Item::useTimeDepleted(ItemInstance* itemInstance, Level* level, Player* player ) -{ - return *itemInstance; -} +#include "ItemInclude.hpp" +#include "ItemCategory.hpp" +#include "world/level/tile/Tile.hpp" +#include "ItemInstance.hpp" + +const std::string Item::ICON_DESCRIPTION_PREFIX("item."); +Random Item::random; + +Item* Item::items[MAX_ITEMS] = {NULL}; + +Item::Tier const Item::Tier::WOOD(0, 59, 2, 0); +Item::Tier const Item::Tier::STONE(1, 131, 4, 1); +Item::Tier const Item::Tier::IRON(2, 250, 6, 2); +Item::Tier const Item::Tier::EMERALD(3, 1561, 8, 3); +Item::Tier const Item::Tier::GOLD(0, 32, 12, 0); + +// Static Item Definitions +Item* Item::shovel_iron = NULL; +Item* Item::pickAxe_iron = NULL; +Item* Item::hatchet_iron = NULL; +Item* Item::flintAndSteel = NULL; +Item* Item::apple = NULL; +Item* Item::bow = NULL; +Item* Item::arrow = NULL; +Item* Item::coal = NULL; +Item* Item::emerald = NULL; +Item* Item::ironIngot = NULL; +Item* Item::goldIngot = NULL; +Item* Item::sword_iron = NULL; + +Item* Item::sword_wood = NULL; +Item* Item::shovel_wood = NULL; +Item* Item::pickAxe_wood = NULL; +Item* Item::hatchet_wood = NULL; + +Item* Item::sword_stone = NULL; +Item* Item::shovel_stone = NULL; +Item* Item::pickAxe_stone = NULL; +Item* Item::hatchet_stone = NULL; + +Item* Item::sword_emerald = NULL; +Item* Item::shovel_emerald = NULL; +Item* Item::pickAxe_emerald = NULL; +Item* Item::hatchet_emerald = NULL; + +Item* Item::stick = NULL; +Item* Item::bowl = NULL; +Item* Item::mushroomStew = NULL; + +Item* Item::sword_gold = NULL; +Item* Item::shovel_gold = NULL; +Item* Item::pickAxe_gold = NULL; +Item* Item::hatchet_gold = NULL; + +Item* Item::string = NULL; +Item* Item::feather = NULL; +Item* Item::sulphur = NULL; + +Item* Item::hoe_wood = NULL; +Item* Item::hoe_stone = NULL; +Item* Item::hoe_iron = NULL; +Item* Item::hoe_emerald = NULL; +Item* Item::hoe_gold = NULL; + +Item* Item::seeds_wheat = NULL; +Item* Item::wheat = NULL; +Item* Item::bread = NULL; + +Item* Item::helmet_cloth = NULL; +Item* Item::chestplate_cloth = NULL; +Item* Item::leggings_cloth = NULL; +Item* Item::boots_cloth = NULL; + +Item* Item::helmet_chain = NULL; +Item* Item::chestplate_chain = NULL; +Item* Item::leggings_chain = NULL; +Item* Item::boots_chain = NULL; + +Item* Item::helmet_iron = NULL; +Item* Item::chestplate_iron = NULL; +Item* Item::leggings_iron = NULL; +Item* Item::boots_iron = NULL; + +Item* Item::helmet_diamond = NULL; +Item* Item::chestplate_diamond = NULL; +Item* Item::leggings_diamond = NULL; +Item* Item::boots_diamond = NULL; + +Item* Item::helmet_gold = NULL; +Item* Item::chestplate_gold = NULL; +Item* Item::leggings_gold = NULL; +Item* Item::boots_gold = NULL; + +Item* Item::flint = NULL; +Item* Item::porkChop_raw = NULL; +Item* Item::porkChop_cooked = NULL; +Item* Item::painting = NULL; + +//Item* Item::apple_gold = NULL; + +Item* Item::sign = NULL; +Item* Item::door_wood = NULL; + +//Item* Item::bucket_empty = NULL; +//Item* Item::bucket_water = NULL; +//Item* Item::bucket_lava = NULL; + +//Item* Item::minecart = NULL; +//Item* Item::saddle = NULL; +Item* Item::door_iron = NULL; +//Item* Item::redStone = NULL; +Item* Item::snowBall = NULL; + +//Item* Item::boat = NULL; + +Item* Item::leather = NULL; +//Item* Item::milk = NULL; +Item* Item::brick = NULL; +Item* Item::clay = NULL; +Item* Item::reeds = NULL; +Item* Item::paper = NULL; +Item* Item::book = NULL; +Item* Item::slimeBall = NULL; +//Item* Item::minecart_chest = NULL; +//Item* Item::minecart_furnace = NULL; +Item* Item::egg = NULL; +Item* Item::compass = NULL; +//Item* Item::fishingRod = NULL; +Item* Item::clock = NULL; +Item* Item::yellowDust = NULL; +//Item* Item::fish_raw = NULL; +//Item* Item::fish_cooked = NULL; + +Item* Item::melon = NULL; +Item* Item::seeds_melon = NULL; + +Item* Item::dye_powder = NULL; +Item* Item::bone = NULL; +Item* Item::sugar = NULL; +//Item* Item::cake = NULL; + +Item* Item::bed = NULL; + +//Item* Item::diode = NULL; +ShearsItem* Item::shears = NULL; +Item* Item::beef_raw = NULL; +Item* Item::beef_cooked = NULL; +Item* Item::chicken_raw = NULL; +Item* Item::chicken_cooked = NULL; + +Item* Item::netherbrick = NULL; +Item* Item::netherQuartz = NULL; + +//Item* Item::record_01 = NULL; +//Item* Item::record_02 = NULL; + +Item* Item::camera = NULL; + +/*static*/ +void Item::initItems() { + static bool isInited = false; + + if (isInited) + return; + + isInited = true; + + Item::shovel_iron = (new ShovelItem(0, Tier::IRON))->setIcon(2, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelIron"); + Item::pickAxe_iron = (new PickaxeItem(1, Tier::IRON))->setIcon(2, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeIron"); + Item::hatchet_iron = (new HatchetItem(2, Tier::IRON))->setIcon(2, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetIron"); + Item::flintAndSteel = (new FlintAndSteelItem(3))->setIcon(5, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("flintAndSteel"); + Item::apple = (new FoodItem(4, 4, false))->setIcon(10, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("apple"); + Item::bow = (new BowItem(5))->setIcon(5, 1)->setCategory(ItemCategory::Tools)->setDescriptionId("bow"); + Item::arrow = (new Item(6))->setIcon(5, 2)->setCategory(ItemCategory::Tools)->setDescriptionId("arrow"); + Item::coal = (new CoalItem(7))->setIcon(7, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("coal"); + Item::emerald = (new Item(8))->setIcon(7, 3)->setCategory(ItemCategory::Decorations)->setDescriptionId("emerald"); + Item::ironIngot = (new Item(9))->setIcon(7, 1)->setCategory(ItemCategory::Decorations)->setDescriptionId("ingotIron"); + Item::goldIngot = (new Item(10))->setIcon(7, 2)->setCategory(ItemCategory::Decorations)->setDescriptionId("ingotGold"); + Item::sword_iron = (new WeaponItem(11, Tier::IRON))->setIcon(2, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordIron"); + Item::sword_wood = (new WeaponItem(12, Tier::WOOD))->setIcon(0, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordWood"); + Item::shovel_wood = (new ShovelItem(13, Tier::WOOD))->setIcon(0, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelWood"); + Item::pickAxe_wood = (new PickaxeItem(14, Tier::WOOD))->setIcon(0, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeWood"); + Item::hatchet_wood = (new HatchetItem(15, Tier::WOOD))->setIcon(0, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetWood"); + Item::sword_stone = (new WeaponItem(16, Tier::STONE))->setIcon(1, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordStone"); + Item::shovel_stone = (new ShovelItem(17, Tier::STONE))->setIcon(1, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelStone"); + Item::pickAxe_stone = (new PickaxeItem(18, Tier::STONE))->setIcon(1, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeStone"); + Item::hatchet_stone = (new HatchetItem(19, Tier::STONE))->setIcon(1, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetStone"); + Item::sword_emerald = (new WeaponItem(20, Tier::EMERALD))->setIcon(3, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordDiamond"); + Item::shovel_emerald = (new ShovelItem(21, Tier::EMERALD))->setIcon(3, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelDiamond"); + Item::pickAxe_emerald = (new PickaxeItem(22, Tier::EMERALD))->setIcon(3, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeDiamond"); + Item::hatchet_emerald = (new HatchetItem(23, Tier::EMERALD))->setIcon(3, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetDiamond"); + Item::stick = (new Item(24))->setIcon(5, 3)->handEquipped()->setCategory(ItemCategory::Structures)->setDescriptionId("stick"); + Item::bowl = (new Item(25))->setIcon(7, 4)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bowl"); + Item::mushroomStew = (new BowlFoodItem(26, 8))->setIcon(8, 4)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("mushroomStew"); + Item::sword_gold = (new WeaponItem(27, Tier::GOLD))->setIcon(4, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("swordGold"); + Item::shovel_gold = (new ShovelItem(28, Tier::GOLD))->setIcon(4, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shovelGold"); + Item::pickAxe_gold = (new PickaxeItem(29, Tier::GOLD))->setIcon(4, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("pickaxeGold"); + Item::hatchet_gold = (new HatchetItem(30, Tier::GOLD))->setIcon(4, 7)->setCategory(ItemCategory::Tools)->setDescriptionId("hatchetGold"); + Item::string = (new Item(31))->setIcon(8, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("string"); + Item::feather = (new Item(32))->setIcon(8, 1)->setCategory(ItemCategory::Tools)->setDescriptionId("feather"); + Item::sulphur = (new Item(33))->setIcon(8, 2)->setCategory(ItemCategory::Tools)->setDescriptionId("sulphur"); + Item::hoe_wood = (new HoeItem(34, Tier::WOOD))->setIcon(0, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeWood"); + Item::hoe_stone = (new HoeItem(35, Tier::STONE))->setIcon(1, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeStone"); + Item::hoe_iron = (new HoeItem(36, Tier::IRON))->setIcon(2, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeIron"); + Item::hoe_emerald = (new HoeItem(37, Tier::EMERALD))->setIcon(3, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeDiamond"); + Item::hoe_gold = (new HoeItem(38, Tier::GOLD))->setIcon(4, 8)->setCategory(ItemCategory::Tools)->setDescriptionId("hoeGold"); + Item::seeds_wheat = (new SeedItem(39, Tile::crops->id, Tile::farmland->id))->setIcon(9, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("seeds"); + Item::wheat = (new Item(40))->setIcon(9, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("wheat"); + Item::bread = (new FoodItem(41, 5, false))->setIcon(9, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bread"); + + Item::helmet_cloth = (new ArmorItem(42, ArmorItem::CLOTH, 0, ArmorItem::SLOT_HEAD))->setIcon(0, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetCloth"); + Item::chestplate_cloth = (new ArmorItem(43, ArmorItem::CLOTH, 0, ArmorItem::SLOT_TORSO))->setIcon(0, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateCloth"); + Item::leggings_cloth = (new ArmorItem(44, ArmorItem::CLOTH, 0, ArmorItem::SLOT_LEGS))->setIcon(0, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsCloth"); + Item::boots_cloth = (new ArmorItem(45, ArmorItem::CLOTH, 0, ArmorItem::SLOT_FEET))->setIcon(0, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsCloth"); + + Item::helmet_chain = (new ArmorItem(46, ArmorItem::CHAIN, 1, ArmorItem::SLOT_HEAD))->setIcon(1, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetChain"); + Item::chestplate_chain = (new ArmorItem(47, ArmorItem::CHAIN, 1, ArmorItem::SLOT_TORSO))->setIcon(1, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateChain"); + Item::leggings_chain = (new ArmorItem(48, ArmorItem::CHAIN, 1, ArmorItem::SLOT_LEGS))->setIcon(1, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsChain"); + Item::boots_chain = (new ArmorItem(49, ArmorItem::CHAIN, 1, 3))->setIcon(1, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsChain"); + + Item::helmet_iron = (new ArmorItem(50, ArmorItem::IRON, 2, ArmorItem::SLOT_HEAD))->setIcon(2, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetIron"); + Item::chestplate_iron = (new ArmorItem(51, ArmorItem::IRON, 2, ArmorItem::SLOT_TORSO))->setIcon(2, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateIron"); + Item::leggings_iron = (new ArmorItem(52, ArmorItem::IRON, 2, ArmorItem::SLOT_LEGS))->setIcon(2, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsIron"); + Item::boots_iron = (new ArmorItem(53, ArmorItem::IRON, 2, ArmorItem::SLOT_FEET))->setIcon(2, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsIron"); + + Item::helmet_diamond = (new ArmorItem(54, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_HEAD))->setIcon(3, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetDiamond"); + Item::chestplate_diamond=(new ArmorItem(55, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_TORSO))->setIcon(3, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateDiamond"); + Item::leggings_diamond = (new ArmorItem(56, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_LEGS))->setIcon(3, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsDiamond"); + Item::boots_diamond = (new ArmorItem(57, ArmorItem::DIAMOND, 3, ArmorItem::SLOT_FEET))->setIcon(3, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsDiamond"); + + Item::helmet_gold = (new ArmorItem(58, ArmorItem::GOLD, 4, ArmorItem::SLOT_HEAD))->setIcon(4, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("helmetGold"); + Item::chestplate_gold = (new ArmorItem(59, ArmorItem::GOLD, 4, ArmorItem::SLOT_TORSO))->setIcon(4, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chestplateGold"); + Item::leggings_gold = (new ArmorItem(60, ArmorItem::GOLD, 4, ArmorItem::SLOT_LEGS))->setIcon(4, 2)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("leggingsGold"); + Item::boots_gold = (new ArmorItem(61, ArmorItem::GOLD, 4, ArmorItem::SLOT_FEET))->setIcon(4, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("bootsGold"); + + Item::flint = (new Item(62))->setIcon(6, 0)->setCategory(ItemCategory::Tools)->setDescriptionId("flint"); + Item::porkChop_raw = (new FoodItem(63, 3, true))->setIcon(7, 5)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("porkchopRaw"); + Item::porkChop_cooked = (new FoodItem(64, 8, true))->setIcon(8, 5)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("porkchopCooked"); + Item::painting = (new HangingEntityItem(65, EntityTypes::IdPainting))->setIcon(10, 1)->setCategory(ItemCategory::Decorations)->setDescriptionId("painting"); + //Item::apple_gold = (new FoodItem(66, 42, false))->setIcon(11, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("appleGold"); + Item::sign = (new SignItem(67))->setIcon(10, 2)->setCategory(ItemCategory::Decorations)->setDescriptionId("sign"); + Item::door_wood = (new DoorItem(68, Material::wood))->setIcon(11, 2)->setCategory(ItemCategory::Structures)->setDescriptionId("doorWood"); + //Item::bucket_empty = (new BucketItem(69, 0))->setIcon(10, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("bucket"); + //Item::bucket_water = (new BucketItem(70, Tile::water.id))->setIcon(11, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("bucketWater")->setCraftingRemainingItem(Item.bucket_empty); + //Item::bucket_lava = (new BucketItem(71, Tile::lava.id))->setIcon(12, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("bucketLava")->setCraftingRemainingItem(Item.bucket_empty); + //Item::minecart = (new MinecartItem(72, Minecart.RIDEABLE))->setIcon(7, 8)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("minecart"); + //Item::saddle = (new SaddleItem(73))->setIcon(8, 6)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("saddle"); + Item::door_iron = (new DoorItem(74, Material::metal))->setIcon(12, 2)->setCategory(ItemCategory::Structures)->setDescriptionId("doorIron"); + //Item::redStone = (new RedStoneItem(75))->setIcon(8, 3)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("redstone"); + Item::snowBall = (new SnowballItem(76))->setIcon(14, 0)->setCategory(ItemCategory::Decorations)->setDescriptionId("snowball"); + //Item::boat = (new BoatItem(77))->setIcon(8, 8)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("boat"); + Item::leather = (new Item(78))->setIcon(7, 6)->setCategory(ItemCategory::Tools)->setDescriptionId("leather"); + //Item::milk = (new BucketItem(79, -1))->setIcon(13, 4)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("milk")->setCraftingRemainingItem(Item.bucket_empty); + Item::brick = (new Item(80))->setIcon(6, 1)->setCategory(ItemCategory::Structures)->setDescriptionId("brick"); + Item::clay = (new Item(81))->setIcon(9, 3)->setCategory(ItemCategory::Structures)->setDescriptionId("clay"); + Item::reeds = (new TilePlanterItem(82, Tile::reeds))->setIcon(11, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("reeds"); + Item::paper = (new Item(83))->setIcon(10, 3)->setCategory(ItemCategory::Decorations)->setDescriptionId("paper"); + Item::book = (new Item(84))->setIcon(11, 3)->setCategory(ItemCategory::Decorations)->setDescriptionId("book"); + Item::slimeBall = (new Item(85))->setIcon(14, 1)->setCategory(ItemCategory::Decorations)->setDescriptionId("slimeball"); + //Item::minecart_chest = (new MinecartItem(86, Minecart::CHEST))->setIcon(7, 9)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("minecartChest"); + //Item::minecart_furnace = (new MinecartItem(87, Minecart::FURNACE))->setIcon(7, 10)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("minecartFurnace"); + Item::egg = (new EggItem(88))->setIcon(12, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("egg"); + Item::compass = (new Item(89))->setIcon(6, 3)->setCategory(ItemCategory::Tools)->setDescriptionId("compass"); + //Item::fishingRod = (new FishingRodItem(90))->setIcon(5, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("fishingRod"); + Item::clock = (new Item(91))->setIcon(6, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("clock"); + Item::yellowDust = (new Item(92))->setIcon(9, 4)->setCategory(ItemCategory::Tools)->setDescriptionId("yellowDust"); + //Item::fish_raw = (new FoodItem(93, 2, false))->setIcon(9, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("fishRaw"); + //Item::fish_cooked = (new FoodItem(94, 5, false))->setIcon(10, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("fishCooked"); + Item::dye_powder = (new DyePowderItem(95))->setIcon(14, 4)->setCategory(ItemCategory::Decorations)->setDescriptionId("dyePowder"); + Item::bone = (new Item(96))->setIcon(12, 1)->setCategory(ItemCategory::Tools)->setDescriptionId("bone")->handEquipped(); + Item::sugar = (new Item(97))->setIcon(13, 0)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("sugar")->handEquipped(); + //Item::cake = (new TilePlanterItem(98, Tile::cake))->setMaxStackSize(1)->setIcon(13, 1)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("cake"); + Item::bed = (new BedItem(99))->setMaxStackSize(1)->setIcon(13, 2)->setCategory(ItemCategory::Structures)->setDescriptionId("bed"); + //Item::diode = (new TilePlanterItem(100, Tile::diode_off))->setIcon(6, 5)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("diode"); + Item::shears = (ShearsItem*)(new ShearsItem(103))->setIcon(13, 5)->setCategory(ItemCategory::Tools)->setDescriptionId("shears"); + Item::melon = (new FoodItem(104, 2, false))->setIcon(13, 6)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("melon"); + Item::seeds_melon = (new SeedItem(106, Tile::melonStem->id, Tile::farmland->id))->setIcon(14, 3)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("seedsMelon"); + Item::beef_raw = (new FoodItem(107, 3, /*FoodConstants.FOOD_SATURATION_LOW,*/ true))->setIcon(9, 6)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("beefRaw"); + Item::beef_cooked = (new FoodItem(108, 8, /*FoodConstants.FOOD_SATURATION_GOOD,*/ true))->setIcon(10, 6)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("beefCooked"); + Item::chicken_raw = (new FoodItem(109, 2, /*FoodConstants.FOOD_SATURATION_LOW,*/ true))->setIcon(9, 7)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chickenRaw"); + Item::chicken_cooked = (new FoodItem(110, 6, /*FoodConstants.FOOD_SATURATION_NORMAL,*/ true))->setIcon(10, 7)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("chickenCooked"); + + Item::netherbrick = (new Item(149))->setIcon(5, 9)->setDescriptionId("netherbrickItem")->setCategory(ItemCategory::Structures); + Item::netherQuartz = (new Item(150))->setIcon(5, 10)->setDescriptionId("netherquartz")->setCategory(ItemCategory::Mechanisms); + + //Item::record_01 = (new RecordingItem(2000, "13"))->setIcon(0, 15)->setCategory(ItemCategory::Decorations)->setDescriptionId("record"); + //Item::record_02 = (new RecordingItem(2001, "cat"))->setIcon(1, 15)->setCategory(ItemCategory::Decorations)->setDescriptionId("record"); + Item::camera = (new CameraItem(200))->setIcon(2, 15)->setCategory(ItemCategory::Decorations)->setDescriptionId("camera"); + + for (int i = 256; i < MAX_ITEMS; ++i) { + if (items[i] && items[i]->category == -1) + LOGE("Error: Missing category for item %d: %s\n", items[i]->id, items[i]->getDescriptionId().c_str()); + } +} + +/*static*/ +void Item::teardownItems() { + for (int i = 0; i < MAX_ITEMS; ++i) + if (Item::items[i]) { + delete Item::items[i]; + Item::items[i] = NULL; + } +} + +ItemInstance Item::useTimeDepleted(ItemInstance* itemInstance, Level* level, Player* player ) +{ + return *itemInstance; +} diff --git a/src/world/item/Item.h b/src/world/item/Item.hpp similarity index 99% rename from src/world/item/Item.h rename to src/world/item/Item.hpp index cd51f6f..b559f3c 100755 --- a/src/world/item/Item.h +++ b/src/world/item/Item.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.item; -#include "../../locale/I18n.h" -#include "../../util/Random.h" -#include "UseAnim.h" +#include "locale/I18n.hpp" +#include "util/Random.hpp" +#include "UseAnim.hpp" class Level; class Tile; class Entity; diff --git a/src/world/item/ItemCategory.h b/src/world/item/ItemCategory.hpp similarity index 100% rename from src/world/item/ItemCategory.h rename to src/world/item/ItemCategory.hpp diff --git a/src/world/item/ItemInclude.h b/src/world/item/ItemInclude.h deleted file mode 100755 index eef84c5..0000000 --- a/src/world/item/ItemInclude.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include "Item.h" -#include "BedItem.h" -#include "CameraItem.h" -#include "CoalItem.h" -#include "DoorItem.h" -#include "EggItem.h" -#include "FlintAndSteelItem.h" -#include "SnowballItem.h" -#include "TilePlanterItem.h" - -#include "AuxDataTileItem.h" -#include "BowlFoodItem.h" -#include "ClothTileItem.h" -#include "DyePowderItem.h" -#include "FoodItem.h" -#include "LeafTileItem.h" -#include "StoneSlabTileItem.h" - -#include "ArmorItem.h" -#include "BowItem.h" -#include "DiggerItem.h" -#include "HatchetItem.h" -#include "HoeItem.h" -#include "PickaxeItem.h" -#include "ShovelItem.h" -#include "ShearsItem.h" -#include "WeaponItem.h" - -#include "SeedItem.h" -#include "HangingEntityItem.h" -#include "SignItem.h" - diff --git a/src/world/item/ItemInclude.hpp b/src/world/item/ItemInclude.hpp new file mode 100755 index 0000000..8b8d7a0 --- /dev/null +++ b/src/world/item/ItemInclude.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "Item.hpp" +#include "BedItem.hpp" +#include "CameraItem.hpp" +#include "CoalItem.hpp" +#include "DoorItem.hpp" +#include "EggItem.hpp" +#include "FlintAndSteelItem.hpp" +#include "SnowballItem.hpp" +#include "TilePlanterItem.hpp" + +#include "AuxDataTileItem.hpp" +#include "BowlFoodItem.hpp" +#include "ClothTileItem.hpp" +#include "DyePowderItem.hpp" +#include "FoodItem.hpp" +#include "LeafTileItem.hpp" +#include "StoneSlabTileItem.hpp" + +#include "ArmorItem.hpp" +#include "BowItem.hpp" +#include "DiggerItem.hpp" +#include "HatchetItem.hpp" +#include "HoeItem.hpp" +#include "PickaxeItem.hpp" +#include "ShovelItem.hpp" +#include "ShearsItem.hpp" +#include "WeaponItem.hpp" + +#include "SeedItem.hpp" +#include "HangingEntityItem.hpp" +#include "SignItem.hpp" + diff --git a/src/world/item/ItemInstance.cpp b/src/world/item/ItemInstance.cpp index 9d7d03f..b985e8e 100755 --- a/src/world/item/ItemInstance.cpp +++ b/src/world/item/ItemInstance.cpp @@ -1,292 +1,292 @@ -#include "ItemInstance.h" -#include "Item.h" -#include "../level/tile/Tile.h" -#include "../../nbt/CompoundTag.h" - -ItemInstance::ItemInstance() { - init(0, 0, 0); -} - -ItemInstance::ItemInstance(const Tile* tile) { - init(tile->id, 1, 0); -} - -ItemInstance::ItemInstance(const Tile* tile, int count) { - init(tile->id, count, 0); -} - -ItemInstance::ItemInstance(const Tile* tile, int count, int auxValue) { - init(tile->id, count, auxValue); -} - -ItemInstance::ItemInstance(const Item* item) { - init(item->id, 1, 0); -} - -ItemInstance::ItemInstance(const Item* item, int count) { - init(item->id, count, 0); -} - -ItemInstance::ItemInstance(const Item* item, int count, int auxValue) { - init(item->id, count, auxValue); -} - -ItemInstance::ItemInstance(int id, int count, int damage) { - init(id, count, damage); -} - -ItemInstance::ItemInstance(const ItemInstance& rhs) { - this->auxValue = rhs.auxValue; - this->count = rhs.count; - //this->popTime = rhs.popTime; - this->id = rhs.id; -} - -void ItemInstance::init(int id, int count, int damage) { - this->id = id; - this->count = count; - this->auxValue = damage; -} - -bool ItemInstance::isNull() const { - return (id|count|auxValue) == 0; -} - -void ItemInstance::setNull() { - id = count = auxValue = 0; -} - -//ItemInstance::ItemInstance(CompoundTag itemTag) { -// load(itemTag); -//} - -ItemInstance ItemInstance::remove(int count) { - this->count -= count; - return /*new*/ ItemInstance(id, count, auxValue); -} - -bool ItemInstance::useOn(Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ) { - if (getItem()->useOn(this, player, level, x, y, z, face, clickX, clickY, clickZ)) { - //player.awardStat(Stats.itemUsed[id], 1); - return true; - } - return false; -} - -float ItemInstance::getDestroySpeed(Tile* tile) { - return getItem()->getDestroySpeed(this, tile); -} - -ItemInstance* ItemInstance::use(Level* level, Player* player) { - return getItem()->use(this, level, player); -} - -int ItemInstance::getMaxStackSize() const { - return getItem()->getMaxStackSize(); -} - -bool ItemInstance::isStackable() const { - return getMaxStackSize() > 1 && (!isDamageableItem() || !isDamaged()); -} - -bool ItemInstance::isStackable( const ItemInstance* a, const ItemInstance* b ) { - return a && b && a->id == b->id && b->isStackable() - && (!b->isStackedByData() || a->getAuxValue() == b->getAuxValue()); -} - -bool ItemInstance::isDamageableItem() const { - return Item::items[id]->getMaxDamage() > 0; -} - -/** - * Returns true if this item type only can be stacked with items that have - * the same auxValue data. - * - * @return - */ -bool ItemInstance::isStackedByData() const { - return Item::items[id]->isStackedByData(); -} - -bool ItemInstance::isDamaged() const { - return isDamageableItem() && auxValue > 0; -} - -int ItemInstance::getDamageValue() const { - return auxValue; -} - -int ItemInstance::getAuxValue() const { - return auxValue; -} -void ItemInstance::setAuxValue(int value) { - auxValue = value; -} - -int ItemInstance::getMaxDamage() const { - return Item::items[id]->getMaxDamage(); -} - -void ItemInstance::hurt(int i) { - if (!isDamageableItem()) - return; - - auxValue += i; - if (auxValue > getMaxDamage()) { - count--; - if (count < 0) count = 0; - auxValue = 0; - } -} - -void ItemInstance::hurtEnemy(Mob* mob) { - Item::items[id]->hurtEnemy(this, mob); -} - -void ItemInstance::mineBlock(int tile, int x, int y, int z) { - Item::items[id]->mineBlock(this, tile, x, y, z); -} - -int ItemInstance::getAttackDamage(Entity* entity) { - return Item::items[id]->getAttackDamage(entity); -} - -bool ItemInstance::canDestroySpecial(Tile* tile) { - return Item::items[id]->canDestroySpecial(tile); -} - -void ItemInstance::snap(Player* player) { -} - -void ItemInstance::interactEnemy(Mob* mob) { - Item::items[id]->interactEnemy(this, mob); -} - -ItemInstance* ItemInstance::copy() const { - return new ItemInstance(id, count, auxValue); -} - -/*static*/ -bool ItemInstance::matches(const ItemInstance* a, const ItemInstance* b) { - if (a == NULL && b == NULL) return true; - if (a == NULL || b == NULL) return false; - return a->matches(b); -} - -/*static*/ -bool ItemInstance::matchesNulls(const ItemInstance* a, const ItemInstance* b) { - bool aNull = !a || a->isNull(); - bool bNull = !b || b->isNull(); - if (aNull && bNull) return true; - if (aNull || bNull) return false; - return a->matches(b); -} - -/** - * Checks if this item is the same item as the other one, disregarding the - * 'count' value. - * - * @param b - * @return - */ -bool ItemInstance::sameItem(ItemInstance* b) { - return id == b->id && auxValue == b->auxValue; -} - -std::string ItemInstance::getDescriptionId() const { - return id? Item::items[id]->getDescriptionId(this) : "EmptyItemInstance"; -} - -ItemInstance* ItemInstance::setDescriptionId(const std::string& id) { - return this; -} - -std::string ItemInstance::getName() const { - return I18n::get(getDescriptionId() + ".name"); -} - -std::string ItemInstance::toString() const { - std::stringstream ss; - ss << count << " x " << getDescriptionId() << "(" << id << ")" << "@" << auxValue; - return ss.str(); -} - -/*static*/ -ItemInstance* ItemInstance::clone(const ItemInstance* item) { - return item == NULL ? NULL : item->copy(); -} - -/*static*/ -ItemInstance ItemInstance::cloneSafe( const ItemInstance* item ) { - return item? *item : ItemInstance(); -} - -/*private*/ -bool ItemInstance::matches(const ItemInstance* b) const { - return (id == b->id) - && (count == b->count) - && (auxValue == b->auxValue); -} - -CompoundTag* ItemInstance::save(CompoundTag* compoundTag) { - compoundTag->putShort("id", (short) id); - compoundTag->putByte("Count", (unsigned char) count); - compoundTag->putShort("Damage", (short) auxValue); - return compoundTag; -} - -void ItemInstance::load(CompoundTag* compoundTag) { - id = compoundTag->getShort("id"); - count = (unsigned char) compoundTag->getByte("Count"); - auxValue = compoundTag->getShort("Damage"); -} - -bool ItemInstance::operator==( const ItemInstance& rhs ) const { - return id == rhs.id - && auxValue == rhs.auxValue - && count == rhs.count; -} - -ItemInstance* ItemInstance::fromTag( CompoundTag* tag ) { - ItemInstance* item = new ItemInstance(); - item->load(tag); - if (item->getItem() == NULL) { - delete item; - item = NULL; - } - return item; -} - -Item* ItemInstance::getItem() const { - return Item::items[id]; -} - -int ItemInstance::getIcon() const { - return Item::items[id]->getIcon(this->auxValue); -} -void ItemInstance::releaseUsing( Level* level, Player* player, int durationLeft ) { - getItem()->releaseUsing(this, level, player, durationLeft); -} - -int ItemInstance::getUseDuration() { - return getItem()->getUseDuration(this); -} - -UseAnim::UseAnimation ItemInstance::getUseAnimation() const { - return getItem()->getUseAnimation(); -} - -ItemInstance ItemInstance::useTimeDepleted( Level* level, Player* player ) { - return getItem()->useTimeDepleted(this, level, player); -} - -bool ItemInstance::isArmorItem( const ItemInstance* instance ) { - if (!instance) - return false; - - Item* item = instance->getItem(); - if (!item) - return false; - - return item->isArmor(); -} +#include "ItemInstance.hpp" +#include "Item.hpp" +#include "world/level/tile/Tile.hpp" +#include "nbt/CompoundTag.hpp" + +ItemInstance::ItemInstance() { + init(0, 0, 0); +} + +ItemInstance::ItemInstance(const Tile* tile) { + init(tile->id, 1, 0); +} + +ItemInstance::ItemInstance(const Tile* tile, int count) { + init(tile->id, count, 0); +} + +ItemInstance::ItemInstance(const Tile* tile, int count, int auxValue) { + init(tile->id, count, auxValue); +} + +ItemInstance::ItemInstance(const Item* item) { + init(item->id, 1, 0); +} + +ItemInstance::ItemInstance(const Item* item, int count) { + init(item->id, count, 0); +} + +ItemInstance::ItemInstance(const Item* item, int count, int auxValue) { + init(item->id, count, auxValue); +} + +ItemInstance::ItemInstance(int id, int count, int damage) { + init(id, count, damage); +} + +ItemInstance::ItemInstance(const ItemInstance& rhs) { + this->auxValue = rhs.auxValue; + this->count = rhs.count; + //this->popTime = rhs.popTime; + this->id = rhs.id; +} + +void ItemInstance::init(int id, int count, int damage) { + this->id = id; + this->count = count; + this->auxValue = damage; +} + +bool ItemInstance::isNull() const { + return (id|count|auxValue) == 0; +} + +void ItemInstance::setNull() { + id = count = auxValue = 0; +} + +//ItemInstance::ItemInstance(CompoundTag itemTag) { +// load(itemTag); +//} + +ItemInstance ItemInstance::remove(int count) { + this->count -= count; + return /*new*/ ItemInstance(id, count, auxValue); +} + +bool ItemInstance::useOn(Player* player, Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ) { + if (getItem()->useOn(this, player, level, x, y, z, face, clickX, clickY, clickZ)) { + //player.awardStat(Stats.itemUsed[id], 1); + return true; + } + return false; +} + +float ItemInstance::getDestroySpeed(Tile* tile) { + return getItem()->getDestroySpeed(this, tile); +} + +ItemInstance* ItemInstance::use(Level* level, Player* player) { + return getItem()->use(this, level, player); +} + +int ItemInstance::getMaxStackSize() const { + return getItem()->getMaxStackSize(); +} + +bool ItemInstance::isStackable() const { + return getMaxStackSize() > 1 && (!isDamageableItem() || !isDamaged()); +} + +bool ItemInstance::isStackable( const ItemInstance* a, const ItemInstance* b ) { + return a && b && a->id == b->id && b->isStackable() + && (!b->isStackedByData() || a->getAuxValue() == b->getAuxValue()); +} + +bool ItemInstance::isDamageableItem() const { + return Item::items[id]->getMaxDamage() > 0; +} + +/** + * Returns true if this item type only can be stacked with items that have + * the same auxValue data. + * + * @return + */ +bool ItemInstance::isStackedByData() const { + return Item::items[id]->isStackedByData(); +} + +bool ItemInstance::isDamaged() const { + return isDamageableItem() && auxValue > 0; +} + +int ItemInstance::getDamageValue() const { + return auxValue; +} + +int ItemInstance::getAuxValue() const { + return auxValue; +} +void ItemInstance::setAuxValue(int value) { + auxValue = value; +} + +int ItemInstance::getMaxDamage() const { + return Item::items[id]->getMaxDamage(); +} + +void ItemInstance::hurt(int i) { + if (!isDamageableItem()) + return; + + auxValue += i; + if (auxValue > getMaxDamage()) { + count--; + if (count < 0) count = 0; + auxValue = 0; + } +} + +void ItemInstance::hurtEnemy(Mob* mob) { + Item::items[id]->hurtEnemy(this, mob); +} + +void ItemInstance::mineBlock(int tile, int x, int y, int z) { + Item::items[id]->mineBlock(this, tile, x, y, z); +} + +int ItemInstance::getAttackDamage(Entity* entity) { + return Item::items[id]->getAttackDamage(entity); +} + +bool ItemInstance::canDestroySpecial(Tile* tile) { + return Item::items[id]->canDestroySpecial(tile); +} + +void ItemInstance::snap(Player* player) { +} + +void ItemInstance::interactEnemy(Mob* mob) { + Item::items[id]->interactEnemy(this, mob); +} + +ItemInstance* ItemInstance::copy() const { + return new ItemInstance(id, count, auxValue); +} + +/*static*/ +bool ItemInstance::matches(const ItemInstance* a, const ItemInstance* b) { + if (a == NULL && b == NULL) return true; + if (a == NULL || b == NULL) return false; + return a->matches(b); +} + +/*static*/ +bool ItemInstance::matchesNulls(const ItemInstance* a, const ItemInstance* b) { + bool aNull = !a || a->isNull(); + bool bNull = !b || b->isNull(); + if (aNull && bNull) return true; + if (aNull || bNull) return false; + return a->matches(b); +} + +/** + * Checks if this item is the same item as the other one, disregarding the + * 'count' value. + * + * @param b + * @return + */ +bool ItemInstance::sameItem(ItemInstance* b) { + return id == b->id && auxValue == b->auxValue; +} + +std::string ItemInstance::getDescriptionId() const { + return id? Item::items[id]->getDescriptionId(this) : "EmptyItemInstance"; +} + +ItemInstance* ItemInstance::setDescriptionId(const std::string& id) { + return this; +} + +std::string ItemInstance::getName() const { + return I18n::get(getDescriptionId() + ".name"); +} + +std::string ItemInstance::toString() const { + std::stringstream ss; + ss << count << " x " << getDescriptionId() << "(" << id << ")" << "@" << auxValue; + return ss.str(); +} + +/*static*/ +ItemInstance* ItemInstance::clone(const ItemInstance* item) { + return item == NULL ? NULL : item->copy(); +} + +/*static*/ +ItemInstance ItemInstance::cloneSafe( const ItemInstance* item ) { + return item? *item : ItemInstance(); +} + +/*private*/ +bool ItemInstance::matches(const ItemInstance* b) const { + return (id == b->id) + && (count == b->count) + && (auxValue == b->auxValue); +} + +CompoundTag* ItemInstance::save(CompoundTag* compoundTag) { + compoundTag->putShort("id", (short) id); + compoundTag->putByte("Count", (unsigned char) count); + compoundTag->putShort("Damage", (short) auxValue); + return compoundTag; +} + +void ItemInstance::load(CompoundTag* compoundTag) { + id = compoundTag->getShort("id"); + count = (unsigned char) compoundTag->getByte("Count"); + auxValue = compoundTag->getShort("Damage"); +} + +bool ItemInstance::operator==( const ItemInstance& rhs ) const { + return id == rhs.id + && auxValue == rhs.auxValue + && count == rhs.count; +} + +ItemInstance* ItemInstance::fromTag( CompoundTag* tag ) { + ItemInstance* item = new ItemInstance(); + item->load(tag); + if (item->getItem() == NULL) { + delete item; + item = NULL; + } + return item; +} + +Item* ItemInstance::getItem() const { + return Item::items[id]; +} + +int ItemInstance::getIcon() const { + return Item::items[id]->getIcon(this->auxValue); +} +void ItemInstance::releaseUsing( Level* level, Player* player, int durationLeft ) { + getItem()->releaseUsing(this, level, player, durationLeft); +} + +int ItemInstance::getUseDuration() { + return getItem()->getUseDuration(this); +} + +UseAnim::UseAnimation ItemInstance::getUseAnimation() const { + return getItem()->getUseAnimation(); +} + +ItemInstance ItemInstance::useTimeDepleted( Level* level, Player* player ) { + return getItem()->useTimeDepleted(this, level, player); +} + +bool ItemInstance::isArmorItem( const ItemInstance* instance ) { + if (!instance) + return false; + + Item* item = instance->getItem(); + if (!item) + return false; + + return item->isArmor(); +} diff --git a/src/world/item/ItemInstance.h b/src/world/item/ItemInstance.hpp similarity index 99% rename from src/world/item/ItemInstance.h rename to src/world/item/ItemInstance.hpp index a71ad4b..01bd411 100755 --- a/src/world/item/ItemInstance.h +++ b/src/world/item/ItemInstance.hpp @@ -3,7 +3,7 @@ //package net.minecraft.world.item; #include -#include "UseAnim.h" +#include "UseAnim.hpp" class Level; class Tile; diff --git a/src/world/item/LeafTileItem.h b/src/world/item/LeafTileItem.hpp similarity index 88% rename from src/world/item/LeafTileItem.h rename to src/world/item/LeafTileItem.hpp index 1aaeed5..51bc850 100755 --- a/src/world/item/LeafTileItem.h +++ b/src/world/item/LeafTileItem.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.item; -#include "TileItem.h" -#include "../level/tile/LeafTile.h" -#include "../level/FoliageColor.h" +#include "TileItem.hpp" +#include "world/level/tile/LeafTile.hpp" +#include "world/level/FoliageColor.hpp" class LeafTileItem: public TileItem { diff --git a/src/world/item/PickaxeItem.cpp b/src/world/item/PickaxeItem.cpp index 185ef5d..745112d 100755 --- a/src/world/item/PickaxeItem.cpp +++ b/src/world/item/PickaxeItem.cpp @@ -1,53 +1,53 @@ -#include "PickaxeItem.h" -#include "../level/material/Material.h" -#include "../level/tile/Tile.h" - -PickaxeItem::PickaxeItem( int id, const Tier& tier ) : super(id, 2, tier) -{ - TileList d; - d.push_back(Tile::stoneBrick); - d.push_back(Tile::stoneSlab); - d.push_back(Tile::stoneSlabHalf); - d.push_back(Tile::rock); - d.push_back(Tile::sandStone); - d.push_back(Tile::mossStone); - d.push_back(Tile::ironOre); - d.push_back(Tile::ironBlock); - d.push_back(Tile::coalOre); - d.push_back(Tile::goldBlock); - d.push_back(Tile::goldOre); - d.push_back(Tile::emeraldOre); - d.push_back(Tile::emeraldBlock); - d.push_back(Tile::ice); - //d.push_back(Tile::hellRock); - d.push_back(Tile::lapisOre); - d.push_back(Tile::lapisBlock); - d.push_back(Tile::redStoneOre); - d.push_back(Tile::redStoneOre_lit); - //d.push_back(Tile::rail); - //d.push_back(Tile::detectorRail); - //d.push_back(Tile::goldenRail); - - setTiles(d); -} - -bool PickaxeItem::canDestroySpecial( const Tile* tile ) const -{ - if (tile == Tile::obsidian) return tier.getLevel() == 3; - if (tile == Tile::emeraldBlock || tile == Tile::emeraldOre) return tier.getLevel() >= 2; - if (tile == Tile::goldBlock || tile == Tile::goldOre) return tier.getLevel() >= 2; - if (tile == Tile::ironBlock || tile == Tile::ironOre) return tier.getLevel() >= 1; - if (tile == Tile::lapisBlock || tile == Tile::lapisOre) return tier.getLevel() >= 1; - if (tile == Tile::redStoneOre || tile == Tile::redStoneOre_lit) return tier.getLevel() >= 2; - if (tile->material == Material::stone) return true; - if (tile->material == Material::metal) return true; - return false; -} - -float PickaxeItem::getDestroySpeed( ItemInstance* itemInstance, Tile* tile ) -{ - if (tile != NULL && (tile->material == Material::metal || tile->material == Material::stone)) { - return speed; - } - return super::getDestroySpeed(itemInstance, tile); -} +#include "PickaxeItem.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" + +PickaxeItem::PickaxeItem( int id, const Tier& tier ) : super(id, 2, tier) +{ + TileList d; + d.push_back(Tile::stoneBrick); + d.push_back(Tile::stoneSlab); + d.push_back(Tile::stoneSlabHalf); + d.push_back(Tile::rock); + d.push_back(Tile::sandStone); + d.push_back(Tile::mossStone); + d.push_back(Tile::ironOre); + d.push_back(Tile::ironBlock); + d.push_back(Tile::coalOre); + d.push_back(Tile::goldBlock); + d.push_back(Tile::goldOre); + d.push_back(Tile::emeraldOre); + d.push_back(Tile::emeraldBlock); + d.push_back(Tile::ice); + //d.push_back(Tile::hellRock); + d.push_back(Tile::lapisOre); + d.push_back(Tile::lapisBlock); + d.push_back(Tile::redStoneOre); + d.push_back(Tile::redStoneOre_lit); + //d.push_back(Tile::rail); + //d.push_back(Tile::detectorRail); + //d.push_back(Tile::goldenRail); + + setTiles(d); +} + +bool PickaxeItem::canDestroySpecial( const Tile* tile ) const +{ + if (tile == Tile::obsidian) return tier.getLevel() == 3; + if (tile == Tile::emeraldBlock || tile == Tile::emeraldOre) return tier.getLevel() >= 2; + if (tile == Tile::goldBlock || tile == Tile::goldOre) return tier.getLevel() >= 2; + if (tile == Tile::ironBlock || tile == Tile::ironOre) return tier.getLevel() >= 1; + if (tile == Tile::lapisBlock || tile == Tile::lapisOre) return tier.getLevel() >= 1; + if (tile == Tile::redStoneOre || tile == Tile::redStoneOre_lit) return tier.getLevel() >= 2; + if (tile->material == Material::stone) return true; + if (tile->material == Material::metal) return true; + return false; +} + +float PickaxeItem::getDestroySpeed( ItemInstance* itemInstance, Tile* tile ) +{ + if (tile != NULL && (tile->material == Material::metal || tile->material == Material::stone)) { + return speed; + } + return super::getDestroySpeed(itemInstance, tile); +} diff --git a/src/world/item/PickaxeItem.h b/src/world/item/PickaxeItem.hpp similarity index 93% rename from src/world/item/PickaxeItem.h rename to src/world/item/PickaxeItem.hpp index 962f600..b0748af 100755 --- a/src/world/item/PickaxeItem.h +++ b/src/world/item/PickaxeItem.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.item; -#include "DiggerItem.h" +#include "DiggerItem.hpp" class Tile; class Tier; diff --git a/src/world/item/SaplingTileItem.h b/src/world/item/SaplingTileItem.hpp similarity index 87% rename from src/world/item/SaplingTileItem.h rename to src/world/item/SaplingTileItem.hpp index 1a07385..155c9ed 100755 --- a/src/world/item/SaplingTileItem.h +++ b/src/world/item/SaplingTileItem.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.item; -#include "TileItem.h" -#include "../level/tile/Tile.h" +#include "TileItem.hpp" +#include "world/level/tile/Tile.hpp" class SaplingTileItem: public TileItem { diff --git a/src/world/item/SeedItem.h b/src/world/item/SeedItem.hpp similarity index 97% rename from src/world/item/SeedItem.h rename to src/world/item/SeedItem.hpp index 818a9f4..a5f61fa 100755 --- a/src/world/item/SeedItem.h +++ b/src/world/item/SeedItem.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Item.h" +#include "Item.hpp" class SeedItem : public Item { typedef Item super; diff --git a/src/world/item/ShearsItem.h b/src/world/item/ShearsItem.hpp similarity index 92% rename from src/world/item/ShearsItem.h rename to src/world/item/ShearsItem.hpp index 2490f31..9130b85 100755 --- a/src/world/item/ShearsItem.h +++ b/src/world/item/ShearsItem.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.item; -#include "Item.h" +#include "Item.hpp" -#include "../entity/Mob.h" -#include "../level/tile/Tile.h" +#include "world/entity/Mob.hpp" +#include "world/level/tile/Tile.hpp" // @todo: web and perhaps mineBlock class ShearsItem: public Item diff --git a/src/world/item/ShovelItem.cpp b/src/world/item/ShovelItem.cpp index 8d4f022..d50c4e6 100755 --- a/src/world/item/ShovelItem.cpp +++ b/src/world/item/ShovelItem.cpp @@ -1,24 +1,24 @@ -#include "ShovelItem.h" -#include "../level/tile/Tile.h" - -ShovelItem::ShovelItem( int id, const Tier& tier ) -: super(id, 1, tier) -{ - TileList d; - d.push_back((Tile*)Tile::grass); - d.push_back(Tile::dirt); - d.push_back(Tile::sand); - d.push_back(Tile::gravel); - d.push_back(Tile::topSnow); - d.push_back(Tile::snow); - d.push_back(Tile::clay); - d.push_back(Tile::farmland); - - setTiles(d); -} - -bool ShovelItem::canDestroySpecial( const Tile* tile ) const { - if (tile == Tile::topSnow) return true; - if (tile == Tile::snow) return true; - return false; -} +#include "ShovelItem.hpp" +#include "world/level/tile/Tile.hpp" + +ShovelItem::ShovelItem( int id, const Tier& tier ) +: super(id, 1, tier) +{ + TileList d; + d.push_back((Tile*)Tile::grass); + d.push_back(Tile::dirt); + d.push_back(Tile::sand); + d.push_back(Tile::gravel); + d.push_back(Tile::topSnow); + d.push_back(Tile::snow); + d.push_back(Tile::clay); + d.push_back(Tile::farmland); + + setTiles(d); +} + +bool ShovelItem::canDestroySpecial( const Tile* tile ) const { + if (tile == Tile::topSnow) return true; + if (tile == Tile::snow) return true; + return false; +} diff --git a/src/world/item/ShovelItem.h b/src/world/item/ShovelItem.hpp similarity index 91% rename from src/world/item/ShovelItem.h rename to src/world/item/ShovelItem.hpp index b93b117..e72df94 100755 --- a/src/world/item/ShovelItem.h +++ b/src/world/item/ShovelItem.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.item; -#include "DiggerItem.h" +#include "DiggerItem.hpp" #include class Tile; diff --git a/src/world/item/SignItem.h b/src/world/item/SignItem.hpp similarity index 87% rename from src/world/item/SignItem.h rename to src/world/item/SignItem.hpp index 58d68a0..148809e 100755 --- a/src/world/item/SignItem.h +++ b/src/world/item/SignItem.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.item; -#include "../entity/player/Player.h" -#include "../level/Level.h" -#include "../level/tile/Tile.h" -#include "../level/tile/entity/SignTileEntity.h" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/entity/SignTileEntity.hpp" class SignItem: public Item { diff --git a/src/world/item/SnowballItem.h b/src/world/item/SnowballItem.hpp similarity index 79% rename from src/world/item/SnowballItem.h rename to src/world/item/SnowballItem.hpp index 17503b3..2eac270 100755 --- a/src/world/item/SnowballItem.h +++ b/src/world/item/SnowballItem.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.item; -#include "Item.h" -#include "../entity/player/Player.h" -#include "../entity/projectile/Snowball.h" -#include "../level/Level.h" +#include "Item.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/projectile/Snowball.hpp" +#include "world/level/Level.hpp" class SnowballItem: public Item { typedef Item super; diff --git a/src/world/item/StoneSlabTileItem.h b/src/world/item/StoneSlabTileItem.hpp similarity index 90% rename from src/world/item/StoneSlabTileItem.h rename to src/world/item/StoneSlabTileItem.hpp index 92b6d73..4b3500b 100755 --- a/src/world/item/StoneSlabTileItem.h +++ b/src/world/item/StoneSlabTileItem.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.item; -#include "TileItem.h" -#include "../Facing.h" -#include "../level/Level.h" -#include "../entity/player/Player.h" -#include "../level/tile/StoneSlabTile.h" -#include "../level/tile/Tile.h" +#include "TileItem.hpp" +#include "world/Facing.hpp" +#include "world/level/Level.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/tile/StoneSlabTile.hpp" +#include "world/level/tile/Tile.hpp" class StoneSlabTileItem: public TileItem { diff --git a/src/world/item/TileItem.h b/src/world/item/TileItem.hpp similarity index 89% rename from src/world/item/TileItem.h rename to src/world/item/TileItem.hpp index c43d2a1..2946acc 100755 --- a/src/world/item/TileItem.h +++ b/src/world/item/TileItem.hpp @@ -4,14 +4,14 @@ #include -#include "Item.h" -#include "ItemInstance.h" -#include "../entity/player/Player.h" -#include "../level/Level.h" -#include "../level/tile/Tile.h" +#include "Item.hpp" +#include "ItemInstance.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" -#include "../../network/RakNetInstance.h" -#include "../../network/packet/PlaceBlockPacket.h" +#include "network/RakNetInstance.hpp" +#include "network/packet/PlaceBlockPacket.hpp" class TileItem: public Item { diff --git a/src/world/item/TilePlanterItem.h b/src/world/item/TilePlanterItem.hpp similarity index 89% rename from src/world/item/TilePlanterItem.h rename to src/world/item/TilePlanterItem.hpp index ecee7c2..923b325 100755 --- a/src/world/item/TilePlanterItem.h +++ b/src/world/item/TilePlanterItem.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.item; -#include "../entity/player/Player.h" -#include "../level/Level.h" -#include "../level/tile/Tile.h" -#include "Item.h" -#include "ItemInstance.h" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "Item.hpp" +#include "ItemInstance.hpp" class TilePlanterItem: public Item { diff --git a/src/world/item/TreeTileItem.h b/src/world/item/TreeTileItem.hpp similarity index 87% rename from src/world/item/TreeTileItem.h rename to src/world/item/TreeTileItem.hpp index f38997f..5f6f596 100755 --- a/src/world/item/TreeTileItem.h +++ b/src/world/item/TreeTileItem.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.item; -#include "../level/tile/Tile.h" -#include "ItemInstance.h" +#include "world/level/tile/Tile.hpp" +#include "ItemInstance.hpp" class TreeTileItem: public TileItem { diff --git a/src/world/item/UseAnim.h b/src/world/item/UseAnim.hpp similarity index 100% rename from src/world/item/UseAnim.h rename to src/world/item/UseAnim.hpp diff --git a/src/world/item/WeaponItem.h b/src/world/item/WeaponItem.hpp similarity index 89% rename from src/world/item/WeaponItem.h rename to src/world/item/WeaponItem.hpp index 09d9381..4282ef9 100755 --- a/src/world/item/WeaponItem.h +++ b/src/world/item/WeaponItem.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.item; -#include "Item.h" -#include "../entity/Entity.h" -#include "../entity/Mob.h" -#include "../entity/player/Player.h" -#include "../level/Level.h" -#include "../level/tile/Tile.h" +#include "Item.hpp" +#include "world/entity/Entity.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" class WeaponItem: public Item { diff --git a/src/world/item/crafting/ArmorRecipes.cpp b/src/world/item/crafting/ArmorRecipes.cpp index 87cdee7..e30b9e2 100755 --- a/src/world/item/crafting/ArmorRecipes.cpp +++ b/src/world/item/crafting/ArmorRecipes.cpp @@ -1,53 +1,53 @@ -#include "ArmorRecipes.h" -#include "Recipes.h" -#include "../../level/tile/Tile.h" - -static RowList shapes[] = { - // Helmet - Recipes::Shape( - "XXX", // - "X X"),// - - // Chest plate - Recipes::Shape( - "X X",// - "XXX",// - "XXX"),// - - // Leggings - Recipes::Shape( - "XXX",// - "X X",// - "X X"),// - - // Boots - Recipes::Shape( - "X X",// - "X X")// -}; - -void ArmorRecipes::addRecipes( Recipes* r ) -{ - int materialIds[] = {Item::leather->id, /*((Tile*)Tile::fire)->id,*/ Item::ironIngot->id, Item::emerald->id, Item::goldIngot->id}; - - const int NumMaterials = sizeof(materialIds) / sizeof(int); - const int NumRecipes = sizeof(shapes) / sizeof(RowList); - - Item* map[NumRecipes][NumMaterials] = { - {Item::helmet_cloth, /*Item::helmet_chain,*/ Item::helmet_iron, Item::helmet_diamond, Item::helmet_gold}, - {Item::chestplate_cloth, /*Item::chestplate_chain,*/ Item::chestplate_iron, Item::chestplate_diamond, Item::chestplate_gold}, - {Item::leggings_cloth, /*Item::leggings_chain,*/ Item::leggings_iron, Item::leggings_diamond, Item::leggings_gold}, - {Item::boots_cloth, /*Item::boots_chain,*/ Item::boots_iron, Item::boots_diamond, Item::boots_gold}, - }; - - //const int OVERRIDDEN_MaterialCount = 2; - for (int m = 0; m < NumMaterials; m++) { - int materialId = materialIds[m]; - for (int t = 0; t < NumRecipes; t++) { - Item* target = (Item*) map[t][m]; - - r->addShapedRecipe( ItemInstance(target), shapes[t], - definition('X', Item::items[materialId]) ); - } - } -} +#include "ArmorRecipes.hpp" +#include "Recipes.hpp" +#include "world/level/tile/Tile.hpp" + +static RowList shapes[] = { + // Helmet + Recipes::Shape( + "XXX", // + "X X"),// + + // Chest plate + Recipes::Shape( + "X X",// + "XXX",// + "XXX"),// + + // Leggings + Recipes::Shape( + "XXX",// + "X X",// + "X X"),// + + // Boots + Recipes::Shape( + "X X",// + "X X")// +}; + +void ArmorRecipes::addRecipes( Recipes* r ) +{ + int materialIds[] = {Item::leather->id, /*((Tile*)Tile::fire)->id,*/ Item::ironIngot->id, Item::emerald->id, Item::goldIngot->id}; + + const int NumMaterials = sizeof(materialIds) / sizeof(int); + const int NumRecipes = sizeof(shapes) / sizeof(RowList); + + Item* map[NumRecipes][NumMaterials] = { + {Item::helmet_cloth, /*Item::helmet_chain,*/ Item::helmet_iron, Item::helmet_diamond, Item::helmet_gold}, + {Item::chestplate_cloth, /*Item::chestplate_chain,*/ Item::chestplate_iron, Item::chestplate_diamond, Item::chestplate_gold}, + {Item::leggings_cloth, /*Item::leggings_chain,*/ Item::leggings_iron, Item::leggings_diamond, Item::leggings_gold}, + {Item::boots_cloth, /*Item::boots_chain,*/ Item::boots_iron, Item::boots_diamond, Item::boots_gold}, + }; + + //const int OVERRIDDEN_MaterialCount = 2; + for (int m = 0; m < NumMaterials; m++) { + int materialId = materialIds[m]; + for (int t = 0; t < NumRecipes; t++) { + Item* target = (Item*) map[t][m]; + + r->addShapedRecipe( ItemInstance(target), shapes[t], + definition('X', Item::items[materialId]) ); + } + } +} diff --git a/src/world/item/crafting/ArmorRecipes.h b/src/world/item/crafting/ArmorRecipes.hpp similarity index 100% rename from src/world/item/crafting/ArmorRecipes.h rename to src/world/item/crafting/ArmorRecipes.hpp diff --git a/src/world/item/crafting/ClothDyeRecipes.h b/src/world/item/crafting/ClothDyeRecipes.hpp similarity index 95% rename from src/world/item/crafting/ClothDyeRecipes.h rename to src/world/item/crafting/ClothDyeRecipes.hpp index 8f221d1..436a0fc 100755 --- a/src/world/item/crafting/ClothDyeRecipes.h +++ b/src/world/item/crafting/ClothDyeRecipes.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.item.crafting; -#include "Recipes.h" -#include "../DyePowderItem.h" -#include "../Item.h" -#include "../ItemInstance.h" -#include "../../level/tile/ClothTile.h" -#include "../../level/tile/Tile.h" +#include "Recipes.hpp" +#include "world/item/DyePowderItem.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/tile/ClothTile.hpp" +#include "world/level/tile/Tile.hpp" class ClothDyeRecipes { diff --git a/src/world/item/crafting/FoodRecipes.h b/src/world/item/crafting/FoodRecipes.hpp similarity index 90% rename from src/world/item/crafting/FoodRecipes.h rename to src/world/item/crafting/FoodRecipes.hpp index 1f50055..4e556b1 100755 --- a/src/world/item/crafting/FoodRecipes.h +++ b/src/world/item/crafting/FoodRecipes.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.item.crafting; -#include "Recipes.h" -#include "../Item.h" -#include "../ItemInstance.h" -#include "../DyePowderItem.h" -#include "../../level/tile/Tile.h" +#include "Recipes.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/item/DyePowderItem.hpp" +#include "world/level/tile/Tile.hpp" class FoodRecipes { public: diff --git a/src/world/item/crafting/FurnaceRecipes.cpp b/src/world/item/crafting/FurnaceRecipes.cpp index eed3e50..5ac7a15 100755 --- a/src/world/item/crafting/FurnaceRecipes.cpp +++ b/src/world/item/crafting/FurnaceRecipes.cpp @@ -1,66 +1,66 @@ -#include "FurnaceRecipes.h" -#include "../../level/tile/Tile.h" -#include "../DyePowderItem.h" -#include "../CoalItem.h" - -/*static*/ -FurnaceRecipes* FurnaceRecipes::instance = NULL; - -const FurnaceRecipes* FurnaceRecipes::getInstance() -{ - if (!instance) instance = new FurnaceRecipes(); - return instance; -} - -void FurnaceRecipes::addFurnaceRecipe( int itemId, const ItemInstance& result ) -{ - recipes.insert(std::make_pair(itemId, result)); -} - -bool FurnaceRecipes::isFurnaceItem( int itemId ) const -{ - return recipes.find(itemId) != recipes.end(); -} - -ItemInstance FurnaceRecipes::getResult( int itemId ) const -{ - Map::const_iterator cit = recipes.find(itemId); - return (cit != recipes.end())? cit->second : ItemInstance(); -} - -const FurnaceRecipes::Map& FurnaceRecipes::getRecipes() const -{ - return recipes; -} - -FurnaceRecipes::FurnaceRecipes() -{ - addFurnaceRecipe(Tile::ironOre->id, ItemInstance(Item::ironIngot)); - addFurnaceRecipe(Tile::goldOre->id, ItemInstance(Item::goldIngot)); - addFurnaceRecipe(Tile::emeraldOre->id, ItemInstance(Item::emerald)); - addFurnaceRecipe(Tile::sand->id, ItemInstance(Tile::glass)); - addFurnaceRecipe(Item::porkChop_raw->id,ItemInstance(Item::porkChop_cooked)); - addFurnaceRecipe(Item::beef_raw->id, ItemInstance(Item::beef_cooked)); - addFurnaceRecipe(Item::chicken_raw->id, ItemInstance(Item::chicken_cooked)); - //addFurnaceRecipe(Item::fish_raw->id, ItemInstance(Item::fish_cooked)); - addFurnaceRecipe(Tile::stoneBrick->id, ItemInstance(Tile::rock)); - addFurnaceRecipe(Item::clay->id, ItemInstance(Item::brick)); - addFurnaceRecipe(Tile::cactus->id, ItemInstance(Item::dye_powder, 1, DyePowderItem::GREEN)); - addFurnaceRecipe(Tile::mushroom2->id, ItemInstance(Item::dye_powder, 1, DyePowderItem::RED)); - addFurnaceRecipe(Tile::treeTrunk->id, ItemInstance(Item::coal, 1, CoalItem::CHAR_COAL)); - addFurnaceRecipe(Tile::netherrack->id, ItemInstance(Item::netherbrick)); - /* - // special silk touch related recipes: - addFurnaceRecipe(Tile::coalOre->id, ItemInstance(Item::coal)); - addFurnaceRecipe(Tile::redStoneOre->id, ItemInstance(Item::redStone)); - addFurnaceRecipe(Tile::lapisOre->id, ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE)); - */ -} - -void FurnaceRecipes::teardownFurnaceRecipes() -{ - if (instance) { - delete instance; - instance = NULL; - } -} +#include "FurnaceRecipes.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/item/DyePowderItem.hpp" +#include "world/item/CoalItem.hpp" + +/*static*/ +FurnaceRecipes* FurnaceRecipes::instance = NULL; + +const FurnaceRecipes* FurnaceRecipes::getInstance() +{ + if (!instance) instance = new FurnaceRecipes(); + return instance; +} + +void FurnaceRecipes::addFurnaceRecipe( int itemId, const ItemInstance& result ) +{ + recipes.insert(std::make_pair(itemId, result)); +} + +bool FurnaceRecipes::isFurnaceItem( int itemId ) const +{ + return recipes.find(itemId) != recipes.end(); +} + +ItemInstance FurnaceRecipes::getResult( int itemId ) const +{ + Map::const_iterator cit = recipes.find(itemId); + return (cit != recipes.end())? cit->second : ItemInstance(); +} + +const FurnaceRecipes::Map& FurnaceRecipes::getRecipes() const +{ + return recipes; +} + +FurnaceRecipes::FurnaceRecipes() +{ + addFurnaceRecipe(Tile::ironOre->id, ItemInstance(Item::ironIngot)); + addFurnaceRecipe(Tile::goldOre->id, ItemInstance(Item::goldIngot)); + addFurnaceRecipe(Tile::emeraldOre->id, ItemInstance(Item::emerald)); + addFurnaceRecipe(Tile::sand->id, ItemInstance(Tile::glass)); + addFurnaceRecipe(Item::porkChop_raw->id,ItemInstance(Item::porkChop_cooked)); + addFurnaceRecipe(Item::beef_raw->id, ItemInstance(Item::beef_cooked)); + addFurnaceRecipe(Item::chicken_raw->id, ItemInstance(Item::chicken_cooked)); + //addFurnaceRecipe(Item::fish_raw->id, ItemInstance(Item::fish_cooked)); + addFurnaceRecipe(Tile::stoneBrick->id, ItemInstance(Tile::rock)); + addFurnaceRecipe(Item::clay->id, ItemInstance(Item::brick)); + addFurnaceRecipe(Tile::cactus->id, ItemInstance(Item::dye_powder, 1, DyePowderItem::GREEN)); + addFurnaceRecipe(Tile::mushroom2->id, ItemInstance(Item::dye_powder, 1, DyePowderItem::RED)); + addFurnaceRecipe(Tile::treeTrunk->id, ItemInstance(Item::coal, 1, CoalItem::CHAR_COAL)); + addFurnaceRecipe(Tile::netherrack->id, ItemInstance(Item::netherbrick)); + /* + // special silk touch related recipes: + addFurnaceRecipe(Tile::coalOre->id, ItemInstance(Item::coal)); + addFurnaceRecipe(Tile::redStoneOre->id, ItemInstance(Item::redStone)); + addFurnaceRecipe(Tile::lapisOre->id, ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE)); + */ +} + +void FurnaceRecipes::teardownFurnaceRecipes() +{ + if (instance) { + delete instance; + instance = NULL; + } +} diff --git a/src/world/item/crafting/FurnaceRecipes.h b/src/world/item/crafting/FurnaceRecipes.hpp similarity index 92% rename from src/world/item/crafting/FurnaceRecipes.h rename to src/world/item/crafting/FurnaceRecipes.hpp index a2a77a7..e009db4 100755 --- a/src/world/item/crafting/FurnaceRecipes.h +++ b/src/world/item/crafting/FurnaceRecipes.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.item.crafting; -#include "../ItemInstance.h" +#include "world/item/ItemInstance.hpp" #include class FurnaceRecipes diff --git a/src/world/item/crafting/OreRecipes.cpp b/src/world/item/crafting/OreRecipes.cpp index 028bde8..227d63c 100755 --- a/src/world/item/crafting/OreRecipes.cpp +++ b/src/world/item/crafting/OreRecipes.cpp @@ -1,45 +1,45 @@ -#include "OreRecipes.h" -#include "Recipes.h" -#include "../../level/tile/Tile.h" -#include "../DyePowderItem.h" -#include - -void OreRecipes::addRecipes(Recipes* r) -{ - typedef std::pair Pair; - Pair map[] = { - std::make_pair(Tile::goldBlock, ItemInstance(Item::goldIngot, 9)), - std::make_pair(Tile::ironBlock, ItemInstance(Item::ironIngot, 9)), - std::make_pair(Tile::emeraldBlock, ItemInstance(Item::emerald, 9)), - std::make_pair(Tile::lapisBlock, ItemInstance(Item::dye_powder, 9, DyePowderItem::BLUE)) - }; - const int NumItems = sizeof(map) / sizeof(Pair); - - for (int i = 0; i < NumItems; i++) { - Tile* from = map[i].first; - ItemInstance to = map[i].second; - - r->addShapedRecipe(ItemInstance(from), // - "###", // - "###", // - "###", // - - definition('#', to)); - - r->addShapedRecipe(to, // - "#", // - - definition('#', from)); - } - - //r->addShapedRecipe(ItemInstance(Item::goldIngot), // - // "###", // - // "###", // - // "###", // - - // definition('#', Item::goldNugget)); - //r->addShapedRecipe(ItemInstance(Item::goldNugget, 9), // - // "#", // - - // definition('#', Item::goldIngot)); -} +#include "OreRecipes.hpp" +#include "Recipes.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/item/DyePowderItem.hpp" +#include + +void OreRecipes::addRecipes(Recipes* r) +{ + typedef std::pair Pair; + Pair map[] = { + std::make_pair(Tile::goldBlock, ItemInstance(Item::goldIngot, 9)), + std::make_pair(Tile::ironBlock, ItemInstance(Item::ironIngot, 9)), + std::make_pair(Tile::emeraldBlock, ItemInstance(Item::emerald, 9)), + std::make_pair(Tile::lapisBlock, ItemInstance(Item::dye_powder, 9, DyePowderItem::BLUE)) + }; + const int NumItems = sizeof(map) / sizeof(Pair); + + for (int i = 0; i < NumItems; i++) { + Tile* from = map[i].first; + ItemInstance to = map[i].second; + + r->addShapedRecipe(ItemInstance(from), // + "###", // + "###", // + "###", // + + definition('#', to)); + + r->addShapedRecipe(to, // + "#", // + + definition('#', from)); + } + + //r->addShapedRecipe(ItemInstance(Item::goldIngot), // + // "###", // + // "###", // + // "###", // + + // definition('#', Item::goldNugget)); + //r->addShapedRecipe(ItemInstance(Item::goldNugget, 9), // + // "#", // + + // definition('#', Item::goldIngot)); +} diff --git a/src/world/item/crafting/OreRecipes.h b/src/world/item/crafting/OreRecipes.hpp similarity index 100% rename from src/world/item/crafting/OreRecipes.h rename to src/world/item/crafting/OreRecipes.hpp diff --git a/src/world/item/crafting/Recipe.cpp b/src/world/item/crafting/Recipe.cpp index e1fda0a..8cde9ef 100755 --- a/src/world/item/crafting/Recipe.cpp +++ b/src/world/item/crafting/Recipe.cpp @@ -1,109 +1,109 @@ -#include "Recipe.h" -#include "../../../util/Mth.h" -#include "../../level/tile/Tile.h" - -void ItemPack::add( int id, int count /* = 1 */ ) -{ - Map::iterator it = items.find(id); - if (it == items.end()) { - items.insert(std::make_pair(id, count)); - } else { - it->second += count; - } -} - -void ItemPack::print() const -{ - Map::const_iterator it = items.begin(); - while (it != items.end()) { - ItemInstance item = getItemInstanceForId(it->first); - //LOGI("> %d - %d, %d\n", it->first, item.id, item.getAuxValue()); - ++it; - } -} - -int ItemPack::getMaxMultipliesOf( ItemPack& v ) const -{ - if (v.items.empty()) - return 0; - int minCount = 99; - - Map::iterator it = v.items.begin(); - while (it != v.items.end()) { - if (it->first <= 0) { - ++it; - continue; - } - - Map::const_iterator jt = items.find(it->first); - if (jt == items.end()) { - //LOGI("shotto: %d (%s) wasn't found!\n", it->first, getItemInstanceForId(it->first).toString().c_str()); - return 0; - } - if (it->second == 0) { - //LOGE("getMaxMultipliesOf: Can't have count 0 of item: %d\n", it->first); - return 0; - } - - int count = jt->second / it->second; - if (count == 0) return 0; - minCount = Mth::Min(minCount, count); - ++it; - } - return minCount; -} - -std::vector ItemPack::getItemInstances() const -{ - std::vector out; - Map::const_iterator it = items.begin(); - while (it != items.end()) { - int id = it->first; - int count = it->second; - - ItemInstance item = getItemInstanceForId(id); - item.count = count; - out.push_back(item); - ++it; - } - return out; -} - -int ItemPack::getIdForItemInstance( const ItemInstance* ii ) -{ - bool anyAuxValue = Recipe::isAnyAuxValue(ii); - return ii->id * 512 + (anyAuxValue? -1/*Recipes::ANY_AUX_VALUE*/ : ii->getAuxValue()); -} -int ItemPack::getIdForItemInstanceAnyAux( const ItemInstance* ii ) -{ - return ii->id * 512 - 1; -} - -ItemInstance ItemPack::getItemInstanceForId( int id ) -{ - id += 256; - return ItemInstance(id / 512, 1, (id & 511) - 256); -} - -int ItemPack::getCount( int id ) const -{ - Map::const_iterator it = items.find(id); - if (it == items.end()) return 0; - return it->second; -} - - -/*static*/ -const int Recipe::SIZE_2X2 = 0; -const int Recipe::SIZE_3X3 = 1; - -bool Recipe::isAnyAuxValue( int id ) -{ - bool isTile = id < 256; - if (!isTile) return false; - if (id == Tile::cloth->id - || id == Tile::stoneSlabHalf->id - || id == Tile::sandStone->id) - return false; - return true; -} +#include "Recipe.hpp" +#include "util/Mth.hpp" +#include "world/level/tile/Tile.hpp" + +void ItemPack::add( int id, int count /* = 1 */ ) +{ + Map::iterator it = items.find(id); + if (it == items.end()) { + items.insert(std::make_pair(id, count)); + } else { + it->second += count; + } +} + +void ItemPack::print() const +{ + Map::const_iterator it = items.begin(); + while (it != items.end()) { + ItemInstance item = getItemInstanceForId(it->first); + //LOGI("> %d - %d, %d\n", it->first, item.id, item.getAuxValue()); + ++it; + } +} + +int ItemPack::getMaxMultipliesOf( ItemPack& v ) const +{ + if (v.items.empty()) + return 0; + int minCount = 99; + + Map::iterator it = v.items.begin(); + while (it != v.items.end()) { + if (it->first <= 0) { + ++it; + continue; + } + + Map::const_iterator jt = items.find(it->first); + if (jt == items.end()) { + //LOGI("shotto: %d (%s) wasn't found!\n", it->first, getItemInstanceForId(it->first).toString().c_str()); + return 0; + } + if (it->second == 0) { + //LOGE("getMaxMultipliesOf: Can't have count 0 of item: %d\n", it->first); + return 0; + } + + int count = jt->second / it->second; + if (count == 0) return 0; + minCount = Mth::Min(minCount, count); + ++it; + } + return minCount; +} + +std::vector ItemPack::getItemInstances() const +{ + std::vector out; + Map::const_iterator it = items.begin(); + while (it != items.end()) { + int id = it->first; + int count = it->second; + + ItemInstance item = getItemInstanceForId(id); + item.count = count; + out.push_back(item); + ++it; + } + return out; +} + +int ItemPack::getIdForItemInstance( const ItemInstance* ii ) +{ + bool anyAuxValue = Recipe::isAnyAuxValue(ii); + return ii->id * 512 + (anyAuxValue? -1/*Recipes::ANY_AUX_VALUE*/ : ii->getAuxValue()); +} +int ItemPack::getIdForItemInstanceAnyAux( const ItemInstance* ii ) +{ + return ii->id * 512 - 1; +} + +ItemInstance ItemPack::getItemInstanceForId( int id ) +{ + id += 256; + return ItemInstance(id / 512, 1, (id & 511) - 256); +} + +int ItemPack::getCount( int id ) const +{ + Map::const_iterator it = items.find(id); + if (it == items.end()) return 0; + return it->second; +} + + +/*static*/ +const int Recipe::SIZE_2X2 = 0; +const int Recipe::SIZE_3X3 = 1; + +bool Recipe::isAnyAuxValue( int id ) +{ + bool isTile = id < 256; + if (!isTile) return false; + if (id == Tile::cloth->id + || id == Tile::stoneSlabHalf->id + || id == Tile::sandStone->id) + return false; + return true; +} diff --git a/src/world/item/crafting/Recipe.h b/src/world/item/crafting/Recipe.hpp similarity index 93% rename from src/world/item/crafting/Recipe.h rename to src/world/item/crafting/Recipe.hpp index 84494fe..e707551 100755 --- a/src/world/item/crafting/Recipe.h +++ b/src/world/item/crafting/Recipe.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.item.crafting; -//#include "../../inventory/CraftingContainer.h" -#include "../ItemInstance.h" +//#include "world/inventory/CraftingContainer.hpp" +#include "world/item/ItemInstance.hpp" #include #include diff --git a/src/world/item/crafting/RecipeCategory.h b/src/world/item/crafting/RecipeCategory.hpp similarity index 100% rename from src/world/item/crafting/RecipeCategory.h rename to src/world/item/crafting/RecipeCategory.hpp diff --git a/src/world/item/crafting/Recipes.cpp b/src/world/item/crafting/Recipes.cpp index a97af3b..6775102 100755 --- a/src/world/item/crafting/Recipes.cpp +++ b/src/world/item/crafting/Recipes.cpp @@ -1,642 +1,642 @@ -#include "Recipes.h" -#include "ShapedRecipe.h" -#include "ShapelessRecipe.h" - -#include "ClothDyeRecipes.h" -#include "ToolRecipes.h" -#include "WeaponRecipes.h" -#include "StructureRecipes.h" -#include "FoodRecipes.h" -#include "FurnaceRecipes.h" -#include "ArmorRecipes.h" -#include "OreRecipes.h" -#include "../CoalItem.h" -#include "../../level/tile/StoneSlabTile.h" - -/*static*/ -Recipes* Recipes::instance = NULL; - -Recipes::Recipes() -{ - ToolRecipes::addRecipes(this); - WeaponRecipes::addRecipes(this); - OreRecipes::addRecipes(this); - FoodRecipes::addRecipes(this); - StructureRecipes::addRecipes(this); - ArmorRecipes::addRecipes(this); - ClothDyeRecipes::addRecipes(this); - - addShapedRecipe(ItemInstance(Item::paper, 3), // - "###", // - - definition('#', Item::reeds)); - - addShapedRecipe(ItemInstance(Item::book, 1), // - "#", // - "#", // - "#", // - - definition('#', Item::paper)); - - addShapedRecipe(ItemInstance(Tile::fence, 2), // - "###", // - "###", // - - definition('#', Item::stick)); - - //addShapedRecipe(ItemInstance(Tile::netherFence, 6), // - // "###", // - // "###", // - - // '#', Tile::netherBrick); - - addShapedRecipe(ItemInstance(Tile::fenceGate, 1), // - "#W#", // - "#W#", // - - definition('#', Item::stick, 'W', Tile::wood)); - - //addShapedRecipe(ItemInstance(Tile::recordPlayer, 1), // - // "###", // - // "#X#", // - // "###", // - - // definition('#', Tile::wood, 'X', Item::emerald)); - - //addShapedRecipe(ItemInstance(Tile::musicBlock, 1), // - // "###", // - // "#X#", // - // "###", // - - // definition('#', Tile::wood, 'X', Item::redStone)); - - addShapedRecipe(ItemInstance(Tile::bookshelf, 1), // - "###", // - "XXX", // - "###", // - - definition('#', Tile::wood, 'X', Item::book)); - - addShapedRecipe(ItemInstance(Tile::snow, 1), // - "##", // - "##", // - - definition('#', Item::snowBall)); - - addShapedRecipe(ItemInstance(Tile::clay, 1), // - "##", // - "##", // - - definition('#', Item::clay)); - - addShapedRecipe(ItemInstance(Tile::redBrick, 1), // - "##", // - "##", // - - definition('#', Item::brick)); - - addShapedRecipe(ItemInstance(Tile::lightGem, 1), // - "##", // - "##", // - - definition('#', Item::yellowDust)); - - addShapedRecipe(ItemInstance(Tile::cloth, 1), // - "##", // - "##", // - - definition('#', Item::string)); - - addShapedRecipe(ItemInstance(Tile::tnt, 1), // - "X#X", // - "#X#", // - "X#X", // - - definition( 'X', Item::sulphur, - '#', Tile::sand)); - - addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::COBBLESTONE_SLAB), // - "###", // - - definition('#', Tile::stoneBrick)); - - addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::STONE_SLAB), // - "###", // - - definition('#', Tile::rock)); - - addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::SAND_SLAB), // - "###", // - definition('#', Tile::sandStone)); - - addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::WOOD_SLAB), // - "###", // - - definition('#', Tile::wood)); - - addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::BRICK_SLAB), // - "###", // - - definition('#', Tile::redBrick)); - - addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::SMOOTHBRICK_SLAB), // - "###", // - definition('#', Tile::stoneBrickSmooth)); - - addShapedRecipe(ItemInstance(Tile::ladder, 2), // - "# #", // - "###", // - "# #", // - - definition('#', Item::stick)); - - addShapedRecipe(ItemInstance(Item::door_wood, 1), // - "##", // - "##", // - "##", // - - definition('#', Tile::wood)); - - addShapedRecipe(ItemInstance(Tile::trapdoor, 2), // - "###", // - "###", // - - definition('#', Tile::wood)); - - //addShapedRecipe(ItemInstance(Item::door_iron, 1), // - // "##", // - // "##", // - // "##", // - - // definition('#', Item::ironIngot)); - - addShapedRecipe(ItemInstance(Item::sign, 1), // - "###", // - "###", // - " X ", // - - definition('#', Tile::wood, 'X', Item::stick)); - - //addShapedRecipe(ItemInstance(Item::cake, 1), // - // "AAA", // - // "BEB", // - // "CCC", // - - // definition( 'A', Item::milk,// - // 'B', Item::sugar,// - // 'C', Item::wheat, 'E', Item::egg)); - - addShapedRecipe(ItemInstance(Item::sugar, 1), // - "#", // - - definition('#', Item::reeds)); - - addShapedRecipe(ItemInstance(Tile::wood, 4), // - "#", // - - definition('#', Tile::treeTrunk)); - - addShapedRecipe(ItemInstance(Item::stick, 4), // - "#", // - "#", // - - definition('#', Tile::wood)); - - addShapedRecipe(ItemInstance(Tile::torch, 4), // - "X", // - "#", // - - definition( 'X', Item::coal,// - '#', Item::stick)); - // torch made of charcoal - addShapedRecipe(ItemInstance(Tile::torch, 4), // - "X", // - "#", // - - definition( 'X', ItemInstance(Item::coal, 1, CoalItem::CHAR_COAL),// - '#', Item::stick)); - - addShapedRecipe(ItemInstance(Item::bowl, 4), // - "# #", // - " # ", // - - definition('#', Tile::wood)); - - //addShapedRecipe(ItemInstance(Item::glassBottle, 3), // - // "# #", // - // " # ", // - - // '#', Tile::glass); - - //addShapedRecipe(ItemInstance(Tile::rail, 16), // - // "X X", // - // "X#X", // - // "X X", // - - // definition( 'X', Item::ironIngot,// - // '#', Item::stick)); - - //addShapedRecipe(ItemInstance(Tile::goldenRail, 6), // - // "X X", // - // "X#X", // - // "XRX", // - - // 'X', Item::goldIngot,// - // 'R', Item::redStone,// - // '#', Item::stick); - - //addShapedRecipe(ItemInstance(Tile::detectorRail, 6), // - // "X X", // - // "X#X", // - // "XRX", // - - // 'X', Item::ironIngot,// - // 'R', Item::redStone,// - // '#', Tile::pressurePlate_stone); - - //addShapedRecipe(ItemInstance(Item::minecart, 1), // - // "# #", // - // "###", // - - // definition('#', Item::ironIngot)); - - //addShapedRecipe(ItemInstance(Item::cauldron, 1), // - // "# #", // - // "# #", // - // "###", // - - // '#', Item::ironIngot); - - //addShapedRecipe(ItemInstance(Item::brewingStand, 1), // - // " B ", // - // "###", // - - // '#', Tile::stoneBrick, 'B', Item::blazeRod); - - //addShapedRecipe(ItemInstance(Tile::litPumpkin, 1), // - // "A", // - // "B", // - - // definition('A', Tile::pumpkin, 'B', Tile::torch)); - - //addShapedRecipe(ItemInstance(Item::minecart_chest, 1), // - // "A", // - // "B", // - - // definition('A', Tile::chest, 'B', Item::minecart)); - - //addShapedRecipe(ItemInstance(Item::minecart_furnace, 1), // - // "A", // - // "B", // - - // definition('A', Tile::furnace, 'B', Item::minecart)); - - //addShapedRecipe(ItemInstance(Item::boat, 1), // - // "# #", // - // "###", // - - // definition('#', Tile::wood)); - - //addShapedRecipe(ItemInstance(Item::bucket_empty, 1), // - // "# #", // - // " # ", // - - // definition('#', Item::ironIngot)); - - addShapedRecipe(ItemInstance(Item::flintAndSteel, 1), // - "A ", // - " B", // - - definition('A', Item::ironIngot, 'B', Item::flint)); - - addShapedRecipe(ItemInstance(Item::bread, 1), // - "###", // - - definition('#', Item::wheat)); - - addShapedRecipe(ItemInstance(Tile::stairs_wood, 4), // - "# ", // - "## ", // - "###", // - - definition('#', Tile::wood)); - - //addShapedRecipe(ItemInstance(Item::fishingRod, 1), // - // " #", // - // " #X", // - // "# X", // - - // definition('#', Item::stick, 'X', Item::string)); - - addShapedRecipe(ItemInstance(Tile::stairs_stone, 4), // - "# ", // - "## ", // - "###", // - - definition('#', Tile::stoneBrick)); - - addShapedRecipe(ItemInstance(Tile::stairs_brick, 4), // - "# ", // - "## ", // - "###", // - definition('#', Tile::redBrick)); - - addShapedRecipe(ItemInstance(Tile::stairs_stoneBrickSmooth, 4), // - "# ", // - "## ", // - "###", // - - definition('#', Tile::stoneBrickSmooth)); - - addShapedRecipe(ItemInstance(Tile::stairs_netherBricks, 4), // - "# ", // - "## ", // - "###", // - - definition('#', Tile::netherBrick)); - - addShapedRecipe(ItemInstance(Item::painting, 1), // - "###", // - "#X#", // - "###", // - - definition('#', Item::stick, 'X', Tile::cloth)); - - //addShapedRecipe(ItemInstance(Item::apple_gold, 1), // - // "###", // - // "#X#", // - // "###", // - - // definition('#', Tile::goldBlock, 'X', Item::apple)); - - //addShapedRecipe(ItemInstance(Tile::lever, 1), // - // "X", // - // "#", // - - // definition('#', Tile::stoneBrick, 'X', Item::stick)); - - //addShapedRecipe(ItemInstance(Tile::notGate_on, 1), // - // "X", // - // "#", // - - // definition('#', Item::stick, 'X', Item::redStone)); - - //addShapedRecipe(ItemInstance(Item::diode, 1), // - // "#X#", // - // "III", // - - // definition('#', Tile::notGate_on, 'X', Item::redStone, 'I', Tile::rock)); - - - //addShapedRecipe(ItemInstance(Item::clock, 1), // - // " # ", // - // "#X#", // - // " # ", // - - // definition('#', Item::goldIngot, 'X', Item::redStone)); - - //addShapedRecipe(ItemInstance(Item::compass, 1), // - // " # ", // - // "#X#", // - // " # ", // - - // definition('#', Item::ironIngot, 'X', Item::redStone)); - - //addShapedRecipe(ItemInstance(Item::map, 1), // - // "###", // - // "#X#", // - // "###", // - - // '#', Item::paper, 'X', Item::compass); - - //addShapedRecipe(ItemInstance(Tile::button, 1), // - // "#", // - // "#", // - - // definition('#', Tile::rock)); - - - //addShapedRecipe(ItemInstance(Tile::pressurePlate_stone, 1), // - // "##", // - - // definition('#', Tile::rock)); - - //addShapedRecipe(ItemInstance(Tile::pressurePlate_wood, 1), // - // "##", // - - // definition('#', Tile::wood)); - - //addShapedRecipe(ItemInstance(Tile::dispenser, 1), // - // "###", // - // "#X#", // - // "#R#", // - - // definition('#', Tile::stoneBrick, 'X', Item::bow, 'R', Item::redStone)); - - //addShapedRecipe(ItemInstance(Tile::pistonBase, 1), // - // "TTT", // - // "#X#", // - // "#R#", // - - // '#', Tile::stoneBrick, 'X', Item::ironIngot, 'R', Item::redStone, 'T', Tile::wood); - - //addShapedRecipe(ItemInstance(Tile::pistonStickyBase, 1), // - // "S", // - // "P", // - - // 'S', Item::slimeBall, 'P', Tile::pistonBase); - - addShapedRecipe(ItemInstance(Item::bed, 1), // - "###", // - "XXX", // - definition('#', Tile::cloth, 'X', Tile::wood)); - - //addShapedRecipe(ItemInstance(Tile::enchantTable, 1), // - // " B ", // - // "D#D", // - // "###", // - - // '#', Tile::obsidian, 'B', Item::book, 'D', Item::emerald); - - //addShapelessRecipe(ItemInstance(Item::eyeOfEnder, 1), // - // Item::enderPearl, Item::blazePowder); - addShapedRecipe(ItemInstance(Tile::netherReactor, 1), // - "X#X", // - "X#X", // - "X#X", // - - definition('#', Item::emerald, 'X', Item::ironIngot)); - - LOGI("%d recipes\n", (int)recipes.size()); -} - -void Recipes::addShapedRecipe( const ItemInstance& result, const RowList& rows, const TypeList& types ) -{ - if (rows.empty()) { - LOGE("Recipes::addShapedRecipe: adding an empty recipe!\n"); - return; - } - - std::string map = ""; - int width = rows[0].length(); - int height = rows.size(); - - for (unsigned int i = 0; i < rows.size(); ++i) - map += rows[i]; - - typedef std::map Map; - Map mappings; - for (unsigned int i = 0; i < types.size(); i++) { - const Type& type = types[i]; - char from = type.c; - ItemInstance to; - - if (type.item) { - to = ItemInstance(type.item); - } else if (type.tile) { - to = ItemInstance(type.tile, 1, Recipe::ANY_AUX_VALUE); - } else if (!type.itemInstance.isNull()) { - to = type.itemInstance; - } - - mappings.insert(std::make_pair(from, to)); - } - - ItemInstance* ids = new ItemInstance[width * height]; - - for (int i = 0; i < width * height; i++) { - char ch = map[i]; - Map::iterator it = mappings.find(ch); - if (it != mappings.end()) - ids[i] = it->second; - } - - // are deleted in ShapedRecipe - recipes.push_back(new ShapedRecipe(width, height, ids, result)); -} - -void Recipes::addShapedRecipe( const ItemInstance& result, const std::string& r0, const TypeList& types) { - addShapedRecipe(result, Shape(r0), types); -} - -void Recipes::addShapedRecipe( const ItemInstance& result, const std::string& r0, const std::string& r1, const TypeList& types) { - addShapedRecipe(result, Shape(r0, r1), types); -} - -void Recipes::addShapedRecipe( const ItemInstance& result, const std::string& r0, const std::string& r1, const std::string& r2, const TypeList& types) { - addShapedRecipe(result, Shape(r0, r1, r2), types); -} - -void Recipes::addShapelessRecipe(const ItemInstance& result, const TypeList& types) { - - std::vector ingredients; - - for (unsigned int i = 0; i < types.size(); i++) { - const Type& type = types[i]; - if (type.item) { - ingredients.push_back( ItemInstance(type.item) ); - } else if (type.tile) { - ingredients.push_back( ItemInstance(type.tile) ); - } else if (!type.itemInstance.isNull()) { - ingredients.push_back( type.itemInstance ); - } else { - LOGE("addShapeLessRecipe: Incorrect shapeless recipe!\n"); - } - } - - recipes.push_back(new ShapelessRecipe(result, ingredients)); -} - -RowList Recipes::Shape( const std::string& r0 ) { - RowList rows; - rows.push_back(r0); - return rows; -} - -RowList Recipes::Shape( const std::string& r0, const std::string& r1 ) { - RowList rows; - rows.push_back(r0); - rows.push_back(r1); - return rows; -} - -RowList Recipes::Shape( const std::string& r0, const std::string& r1, const std::string& r2 ) { - RowList rows; - rows.push_back(r0); - rows.push_back(r1); - rows.push_back(r2); - return rows; -} - -Recipe* Recipes::getRecipeFor( const ItemInstance& result ) -{ - for (unsigned int i = 0; i < recipes.size(); ++i) { - Recipe* recipe = recipes[i]; - ItemInstance res = recipe->getResultItem(); - if (result.id != res.id) continue; - - if ( result.count == 0 && result.getAuxValue() == res.getAuxValue() - || (result.count == res.count && result.getAuxValue() == res.getAuxValue())) - return recipe; - } - return NULL; -} - -Recipes* Recipes::getInstance() -{ - if (!instance) - instance = new Recipes(); - - return instance; -} - -void Recipes::teardownRecipes() -{ - if (instance) { - delete instance; - instance = NULL; - } - FurnaceRecipes::teardownFurnaceRecipes(); -} - -const RecipeList& Recipes::getRecipes() -{ - return recipes; -} - -ItemInstance Recipes::getItemFor( CraftingContainer* craftSlots ) -{ - int count = 0; - ItemInstance* first; - ItemInstance* second; - for (int i = 0; i < craftSlots->getContainerSize(); i++) { - ItemInstance* item = craftSlots->getItem(i); - if (item) { - if (count == 0) first = item; - if (count == 1) second = item; - count++; - } - } - - if (count == 2 && first->id == second->id && first->count == 1 && second->count == 1 && Item::items[first->id]->canBeDepleted()) { - Item* item = Item::items[first->id]; - int remaining1 = item->getMaxDamage() - first->getDamageValue(); - int remaining2 = item->getMaxDamage() - second->getDamageValue(); - int remaining = (remaining1 + remaining2) + item->getMaxDamage() * 10 / 100; - int resultDamage = item->getMaxDamage() - remaining; - if (resultDamage < 0) resultDamage = 0; - return ItemInstance(first->id, 1, resultDamage); - } - - for (unsigned int i = 0; i < recipes.size(); i++) { - Recipe* r = recipes[i]; - if (r->matches(craftSlots)) return r->assemble(craftSlots); - } - return ItemInstance(); -} - -Recipes::~Recipes() -{ - for (unsigned int i = 0; i < recipes.size(); ++i) - delete recipes[i]; -} +#include "Recipes.hpp" +#include "ShapedRecipe.hpp" +#include "ShapelessRecipe.hpp" + +#include "ClothDyeRecipes.hpp" +#include "ToolRecipes.hpp" +#include "WeaponRecipes.hpp" +#include "StructureRecipes.hpp" +#include "FoodRecipes.hpp" +#include "FurnaceRecipes.hpp" +#include "ArmorRecipes.hpp" +#include "OreRecipes.hpp" +#include "world/item/CoalItem.hpp" +#include "world/level/tile/StoneSlabTile.hpp" + +/*static*/ +Recipes* Recipes::instance = NULL; + +Recipes::Recipes() +{ + ToolRecipes::addRecipes(this); + WeaponRecipes::addRecipes(this); + OreRecipes::addRecipes(this); + FoodRecipes::addRecipes(this); + StructureRecipes::addRecipes(this); + ArmorRecipes::addRecipes(this); + ClothDyeRecipes::addRecipes(this); + + addShapedRecipe(ItemInstance(Item::paper, 3), // + "###", // + + definition('#', Item::reeds)); + + addShapedRecipe(ItemInstance(Item::book, 1), // + "#", // + "#", // + "#", // + + definition('#', Item::paper)); + + addShapedRecipe(ItemInstance(Tile::fence, 2), // + "###", // + "###", // + + definition('#', Item::stick)); + + //addShapedRecipe(ItemInstance(Tile::netherFence, 6), // + // "###", // + // "###", // + + // '#', Tile::netherBrick); + + addShapedRecipe(ItemInstance(Tile::fenceGate, 1), // + "#W#", // + "#W#", // + + definition('#', Item::stick, 'W', Tile::wood)); + + //addShapedRecipe(ItemInstance(Tile::recordPlayer, 1), // + // "###", // + // "#X#", // + // "###", // + + // definition('#', Tile::wood, 'X', Item::emerald)); + + //addShapedRecipe(ItemInstance(Tile::musicBlock, 1), // + // "###", // + // "#X#", // + // "###", // + + // definition('#', Tile::wood, 'X', Item::redStone)); + + addShapedRecipe(ItemInstance(Tile::bookshelf, 1), // + "###", // + "XXX", // + "###", // + + definition('#', Tile::wood, 'X', Item::book)); + + addShapedRecipe(ItemInstance(Tile::snow, 1), // + "##", // + "##", // + + definition('#', Item::snowBall)); + + addShapedRecipe(ItemInstance(Tile::clay, 1), // + "##", // + "##", // + + definition('#', Item::clay)); + + addShapedRecipe(ItemInstance(Tile::redBrick, 1), // + "##", // + "##", // + + definition('#', Item::brick)); + + addShapedRecipe(ItemInstance(Tile::lightGem, 1), // + "##", // + "##", // + + definition('#', Item::yellowDust)); + + addShapedRecipe(ItemInstance(Tile::cloth, 1), // + "##", // + "##", // + + definition('#', Item::string)); + + addShapedRecipe(ItemInstance(Tile::tnt, 1), // + "X#X", // + "#X#", // + "X#X", // + + definition( 'X', Item::sulphur, + '#', Tile::sand)); + + addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::COBBLESTONE_SLAB), // + "###", // + + definition('#', Tile::stoneBrick)); + + addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::STONE_SLAB), // + "###", // + + definition('#', Tile::rock)); + + addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::SAND_SLAB), // + "###", // + definition('#', Tile::sandStone)); + + addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::WOOD_SLAB), // + "###", // + + definition('#', Tile::wood)); + + addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::BRICK_SLAB), // + "###", // + + definition('#', Tile::redBrick)); + + addShapedRecipe(ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::SMOOTHBRICK_SLAB), // + "###", // + definition('#', Tile::stoneBrickSmooth)); + + addShapedRecipe(ItemInstance(Tile::ladder, 2), // + "# #", // + "###", // + "# #", // + + definition('#', Item::stick)); + + addShapedRecipe(ItemInstance(Item::door_wood, 1), // + "##", // + "##", // + "##", // + + definition('#', Tile::wood)); + + addShapedRecipe(ItemInstance(Tile::trapdoor, 2), // + "###", // + "###", // + + definition('#', Tile::wood)); + + //addShapedRecipe(ItemInstance(Item::door_iron, 1), // + // "##", // + // "##", // + // "##", // + + // definition('#', Item::ironIngot)); + + addShapedRecipe(ItemInstance(Item::sign, 1), // + "###", // + "###", // + " X ", // + + definition('#', Tile::wood, 'X', Item::stick)); + + //addShapedRecipe(ItemInstance(Item::cake, 1), // + // "AAA", // + // "BEB", // + // "CCC", // + + // definition( 'A', Item::milk,// + // 'B', Item::sugar,// + // 'C', Item::wheat, 'E', Item::egg)); + + addShapedRecipe(ItemInstance(Item::sugar, 1), // + "#", // + + definition('#', Item::reeds)); + + addShapedRecipe(ItemInstance(Tile::wood, 4), // + "#", // + + definition('#', Tile::treeTrunk)); + + addShapedRecipe(ItemInstance(Item::stick, 4), // + "#", // + "#", // + + definition('#', Tile::wood)); + + addShapedRecipe(ItemInstance(Tile::torch, 4), // + "X", // + "#", // + + definition( 'X', Item::coal,// + '#', Item::stick)); + // torch made of charcoal + addShapedRecipe(ItemInstance(Tile::torch, 4), // + "X", // + "#", // + + definition( 'X', ItemInstance(Item::coal, 1, CoalItem::CHAR_COAL),// + '#', Item::stick)); + + addShapedRecipe(ItemInstance(Item::bowl, 4), // + "# #", // + " # ", // + + definition('#', Tile::wood)); + + //addShapedRecipe(ItemInstance(Item::glassBottle, 3), // + // "# #", // + // " # ", // + + // '#', Tile::glass); + + //addShapedRecipe(ItemInstance(Tile::rail, 16), // + // "X X", // + // "X#X", // + // "X X", // + + // definition( 'X', Item::ironIngot,// + // '#', Item::stick)); + + //addShapedRecipe(ItemInstance(Tile::goldenRail, 6), // + // "X X", // + // "X#X", // + // "XRX", // + + // 'X', Item::goldIngot,// + // 'R', Item::redStone,// + // '#', Item::stick); + + //addShapedRecipe(ItemInstance(Tile::detectorRail, 6), // + // "X X", // + // "X#X", // + // "XRX", // + + // 'X', Item::ironIngot,// + // 'R', Item::redStone,// + // '#', Tile::pressurePlate_stone); + + //addShapedRecipe(ItemInstance(Item::minecart, 1), // + // "# #", // + // "###", // + + // definition('#', Item::ironIngot)); + + //addShapedRecipe(ItemInstance(Item::cauldron, 1), // + // "# #", // + // "# #", // + // "###", // + + // '#', Item::ironIngot); + + //addShapedRecipe(ItemInstance(Item::brewingStand, 1), // + // " B ", // + // "###", // + + // '#', Tile::stoneBrick, 'B', Item::blazeRod); + + //addShapedRecipe(ItemInstance(Tile::litPumpkin, 1), // + // "A", // + // "B", // + + // definition('A', Tile::pumpkin, 'B', Tile::torch)); + + //addShapedRecipe(ItemInstance(Item::minecart_chest, 1), // + // "A", // + // "B", // + + // definition('A', Tile::chest, 'B', Item::minecart)); + + //addShapedRecipe(ItemInstance(Item::minecart_furnace, 1), // + // "A", // + // "B", // + + // definition('A', Tile::furnace, 'B', Item::minecart)); + + //addShapedRecipe(ItemInstance(Item::boat, 1), // + // "# #", // + // "###", // + + // definition('#', Tile::wood)); + + //addShapedRecipe(ItemInstance(Item::bucket_empty, 1), // + // "# #", // + // " # ", // + + // definition('#', Item::ironIngot)); + + addShapedRecipe(ItemInstance(Item::flintAndSteel, 1), // + "A ", // + " B", // + + definition('A', Item::ironIngot, 'B', Item::flint)); + + addShapedRecipe(ItemInstance(Item::bread, 1), // + "###", // + + definition('#', Item::wheat)); + + addShapedRecipe(ItemInstance(Tile::stairs_wood, 4), // + "# ", // + "## ", // + "###", // + + definition('#', Tile::wood)); + + //addShapedRecipe(ItemInstance(Item::fishingRod, 1), // + // " #", // + // " #X", // + // "# X", // + + // definition('#', Item::stick, 'X', Item::string)); + + addShapedRecipe(ItemInstance(Tile::stairs_stone, 4), // + "# ", // + "## ", // + "###", // + + definition('#', Tile::stoneBrick)); + + addShapedRecipe(ItemInstance(Tile::stairs_brick, 4), // + "# ", // + "## ", // + "###", // + definition('#', Tile::redBrick)); + + addShapedRecipe(ItemInstance(Tile::stairs_stoneBrickSmooth, 4), // + "# ", // + "## ", // + "###", // + + definition('#', Tile::stoneBrickSmooth)); + + addShapedRecipe(ItemInstance(Tile::stairs_netherBricks, 4), // + "# ", // + "## ", // + "###", // + + definition('#', Tile::netherBrick)); + + addShapedRecipe(ItemInstance(Item::painting, 1), // + "###", // + "#X#", // + "###", // + + definition('#', Item::stick, 'X', Tile::cloth)); + + //addShapedRecipe(ItemInstance(Item::apple_gold, 1), // + // "###", // + // "#X#", // + // "###", // + + // definition('#', Tile::goldBlock, 'X', Item::apple)); + + //addShapedRecipe(ItemInstance(Tile::lever, 1), // + // "X", // + // "#", // + + // definition('#', Tile::stoneBrick, 'X', Item::stick)); + + //addShapedRecipe(ItemInstance(Tile::notGate_on, 1), // + // "X", // + // "#", // + + // definition('#', Item::stick, 'X', Item::redStone)); + + //addShapedRecipe(ItemInstance(Item::diode, 1), // + // "#X#", // + // "III", // + + // definition('#', Tile::notGate_on, 'X', Item::redStone, 'I', Tile::rock)); + + + //addShapedRecipe(ItemInstance(Item::clock, 1), // + // " # ", // + // "#X#", // + // " # ", // + + // definition('#', Item::goldIngot, 'X', Item::redStone)); + + //addShapedRecipe(ItemInstance(Item::compass, 1), // + // " # ", // + // "#X#", // + // " # ", // + + // definition('#', Item::ironIngot, 'X', Item::redStone)); + + //addShapedRecipe(ItemInstance(Item::map, 1), // + // "###", // + // "#X#", // + // "###", // + + // '#', Item::paper, 'X', Item::compass); + + //addShapedRecipe(ItemInstance(Tile::button, 1), // + // "#", // + // "#", // + + // definition('#', Tile::rock)); + + + //addShapedRecipe(ItemInstance(Tile::pressurePlate_stone, 1), // + // "##", // + + // definition('#', Tile::rock)); + + //addShapedRecipe(ItemInstance(Tile::pressurePlate_wood, 1), // + // "##", // + + // definition('#', Tile::wood)); + + //addShapedRecipe(ItemInstance(Tile::dispenser, 1), // + // "###", // + // "#X#", // + // "#R#", // + + // definition('#', Tile::stoneBrick, 'X', Item::bow, 'R', Item::redStone)); + + //addShapedRecipe(ItemInstance(Tile::pistonBase, 1), // + // "TTT", // + // "#X#", // + // "#R#", // + + // '#', Tile::stoneBrick, 'X', Item::ironIngot, 'R', Item::redStone, 'T', Tile::wood); + + //addShapedRecipe(ItemInstance(Tile::pistonStickyBase, 1), // + // "S", // + // "P", // + + // 'S', Item::slimeBall, 'P', Tile::pistonBase); + + addShapedRecipe(ItemInstance(Item::bed, 1), // + "###", // + "XXX", // + definition('#', Tile::cloth, 'X', Tile::wood)); + + //addShapedRecipe(ItemInstance(Tile::enchantTable, 1), // + // " B ", // + // "D#D", // + // "###", // + + // '#', Tile::obsidian, 'B', Item::book, 'D', Item::emerald); + + //addShapelessRecipe(ItemInstance(Item::eyeOfEnder, 1), // + // Item::enderPearl, Item::blazePowder); + addShapedRecipe(ItemInstance(Tile::netherReactor, 1), // + "X#X", // + "X#X", // + "X#X", // + + definition('#', Item::emerald, 'X', Item::ironIngot)); + + LOGI("%d recipes\n", (int)recipes.size()); +} + +void Recipes::addShapedRecipe( const ItemInstance& result, const RowList& rows, const TypeList& types ) +{ + if (rows.empty()) { + LOGE("Recipes::addShapedRecipe: adding an empty recipe!\n"); + return; + } + + std::string map = ""; + int width = rows[0].length(); + int height = rows.size(); + + for (unsigned int i = 0; i < rows.size(); ++i) + map += rows[i]; + + typedef std::map Map; + Map mappings; + for (unsigned int i = 0; i < types.size(); i++) { + const Type& type = types[i]; + char from = type.c; + ItemInstance to; + + if (type.item) { + to = ItemInstance(type.item); + } else if (type.tile) { + to = ItemInstance(type.tile, 1, Recipe::ANY_AUX_VALUE); + } else if (!type.itemInstance.isNull()) { + to = type.itemInstance; + } + + mappings.insert(std::make_pair(from, to)); + } + + ItemInstance* ids = new ItemInstance[width * height]; + + for (int i = 0; i < width * height; i++) { + char ch = map[i]; + Map::iterator it = mappings.find(ch); + if (it != mappings.end()) + ids[i] = it->second; + } + + // are deleted in ShapedRecipe + recipes.push_back(new ShapedRecipe(width, height, ids, result)); +} + +void Recipes::addShapedRecipe( const ItemInstance& result, const std::string& r0, const TypeList& types) { + addShapedRecipe(result, Shape(r0), types); +} + +void Recipes::addShapedRecipe( const ItemInstance& result, const std::string& r0, const std::string& r1, const TypeList& types) { + addShapedRecipe(result, Shape(r0, r1), types); +} + +void Recipes::addShapedRecipe( const ItemInstance& result, const std::string& r0, const std::string& r1, const std::string& r2, const TypeList& types) { + addShapedRecipe(result, Shape(r0, r1, r2), types); +} + +void Recipes::addShapelessRecipe(const ItemInstance& result, const TypeList& types) { + + std::vector ingredients; + + for (unsigned int i = 0; i < types.size(); i++) { + const Type& type = types[i]; + if (type.item) { + ingredients.push_back( ItemInstance(type.item) ); + } else if (type.tile) { + ingredients.push_back( ItemInstance(type.tile) ); + } else if (!type.itemInstance.isNull()) { + ingredients.push_back( type.itemInstance ); + } else { + LOGE("addShapeLessRecipe: Incorrect shapeless recipe!\n"); + } + } + + recipes.push_back(new ShapelessRecipe(result, ingredients)); +} + +RowList Recipes::Shape( const std::string& r0 ) { + RowList rows; + rows.push_back(r0); + return rows; +} + +RowList Recipes::Shape( const std::string& r0, const std::string& r1 ) { + RowList rows; + rows.push_back(r0); + rows.push_back(r1); + return rows; +} + +RowList Recipes::Shape( const std::string& r0, const std::string& r1, const std::string& r2 ) { + RowList rows; + rows.push_back(r0); + rows.push_back(r1); + rows.push_back(r2); + return rows; +} + +Recipe* Recipes::getRecipeFor( const ItemInstance& result ) +{ + for (unsigned int i = 0; i < recipes.size(); ++i) { + Recipe* recipe = recipes[i]; + ItemInstance res = recipe->getResultItem(); + if (result.id != res.id) continue; + + if ( result.count == 0 && result.getAuxValue() == res.getAuxValue() + || (result.count == res.count && result.getAuxValue() == res.getAuxValue())) + return recipe; + } + return NULL; +} + +Recipes* Recipes::getInstance() +{ + if (!instance) + instance = new Recipes(); + + return instance; +} + +void Recipes::teardownRecipes() +{ + if (instance) { + delete instance; + instance = NULL; + } + FurnaceRecipes::teardownFurnaceRecipes(); +} + +const RecipeList& Recipes::getRecipes() +{ + return recipes; +} + +ItemInstance Recipes::getItemFor( CraftingContainer* craftSlots ) +{ + int count = 0; + ItemInstance* first; + ItemInstance* second; + for (int i = 0; i < craftSlots->getContainerSize(); i++) { + ItemInstance* item = craftSlots->getItem(i); + if (item) { + if (count == 0) first = item; + if (count == 1) second = item; + count++; + } + } + + if (count == 2 && first->id == second->id && first->count == 1 && second->count == 1 && Item::items[first->id]->canBeDepleted()) { + Item* item = Item::items[first->id]; + int remaining1 = item->getMaxDamage() - first->getDamageValue(); + int remaining2 = item->getMaxDamage() - second->getDamageValue(); + int remaining = (remaining1 + remaining2) + item->getMaxDamage() * 10 / 100; + int resultDamage = item->getMaxDamage() - remaining; + if (resultDamage < 0) resultDamage = 0; + return ItemInstance(first->id, 1, resultDamage); + } + + for (unsigned int i = 0; i < recipes.size(); i++) { + Recipe* r = recipes[i]; + if (r->matches(craftSlots)) return r->assemble(craftSlots); + } + return ItemInstance(); +} + +Recipes::~Recipes() +{ + for (unsigned int i = 0; i < recipes.size(); ++i) + delete recipes[i]; +} diff --git a/src/world/item/crafting/Recipes.h b/src/world/item/crafting/Recipes.hpp similarity index 94% rename from src/world/item/crafting/Recipes.h rename to src/world/item/crafting/Recipes.hpp index c47e00b..5bb33de 100755 --- a/src/world/item/crafting/Recipes.h +++ b/src/world/item/crafting/Recipes.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.item.crafting; -#include "../Item.h" -#include "../../inventory/CraftingContainer.h" -#include "../../level/tile/Tile.h" +#include "world/item/Item.hpp" +#include "world/inventory/CraftingContainer.hpp" +#include "world/level/tile/Tile.hpp" -#include "Recipe.h" +#include "Recipe.hpp" typedef std::vector RowList; typedef std::vector RecipeList; diff --git a/src/world/item/crafting/ShapedRecipe.h b/src/world/item/crafting/ShapedRecipe.hpp similarity index 96% rename from src/world/item/crafting/ShapedRecipe.h rename to src/world/item/crafting/ShapedRecipe.hpp index 2e3a028..f8c5055 100755 --- a/src/world/item/crafting/ShapedRecipe.h +++ b/src/world/item/crafting/ShapedRecipe.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.item.crafting; -#include "../../inventory/CraftingContainer.h" -#include "../ItemInstance.h" -#include "Recipe.h" +#include "world/inventory/CraftingContainer.hpp" +#include "world/item/ItemInstance.hpp" +#include "Recipe.hpp" class ShapedRecipe: public Recipe { diff --git a/src/world/item/crafting/ShapelessRecipe.h b/src/world/item/crafting/ShapelessRecipe.hpp similarity index 94% rename from src/world/item/crafting/ShapelessRecipe.h rename to src/world/item/crafting/ShapelessRecipe.hpp index c40ff0c..db2a199 100755 --- a/src/world/item/crafting/ShapelessRecipe.h +++ b/src/world/item/crafting/ShapelessRecipe.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.item.crafting; -#include "Recipe.h" -#include "../ItemInstance.h" -#include "../../inventory/CraftingContainer.h" +#include "Recipe.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/inventory/CraftingContainer.hpp" class ShapelessRecipe: public Recipe { diff --git a/src/world/item/crafting/StructureRecipes.cpp b/src/world/item/crafting/StructureRecipes.cpp index 9c297f0..296eed8 100755 --- a/src/world/item/crafting/StructureRecipes.cpp +++ b/src/world/item/crafting/StructureRecipes.cpp @@ -1 +1 @@ -#include "StructureRecipes.h" \ No newline at end of file +#include "StructureRecipes.hpp" \ No newline at end of file diff --git a/src/world/item/crafting/StructureRecipes.h b/src/world/item/crafting/StructureRecipes.hpp similarity index 93% rename from src/world/item/crafting/StructureRecipes.h rename to src/world/item/crafting/StructureRecipes.hpp index bca41d9..8279e05 100755 --- a/src/world/item/crafting/StructureRecipes.h +++ b/src/world/item/crafting/StructureRecipes.hpp @@ -3,10 +3,10 @@ //package net.minecraft.world.item.crafting; /* import net.minecraft.world.item.* */ -#include "Recipes.h" -#include "../../level/tile/Tile.h" -#include "../../level/tile/SandStoneTile.h" -#include "../../level/tile/StoneSlabTile.h" +#include "Recipes.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/SandStoneTile.hpp" +#include "world/level/tile/StoneSlabTile.hpp" class StructureRecipes { diff --git a/src/world/item/crafting/ToolRecipes.cpp b/src/world/item/crafting/ToolRecipes.cpp index 5c79278..aba4ed7 100755 --- a/src/world/item/crafting/ToolRecipes.cpp +++ b/src/world/item/crafting/ToolRecipes.cpp @@ -1,59 +1,59 @@ -#include "ToolRecipes.h" -#include "Recipes.h" -#include "../ShearsItem.h" -#include "../../level/tile/Tile.h" - - -static RowList shapes[] = { - Recipes::Shape( "XXX", // - " # ",// - " # "),// - - Recipes::Shape( "X",// - "#",// - "#"),// - - Recipes::Shape( "XX",// - "X#",// - " #"),// - - Recipes::Shape( "XX",// - " #",// - " #")// -}; - -void ToolRecipes::addRecipes( Recipes* r ) -{ - int materialIds[] = {Tile::wood->id, Tile::stoneBrick->id, Item::ironIngot->id, Item::emerald->id, Item::goldIngot->id}; - const int NumMaterials = sizeof(materialIds) / sizeof(int); - const int NumRecipes = sizeof(shapes) / sizeof(RowList); - - Item* map[NumRecipes][NumMaterials] = { - {Item::pickAxe_wood, Item::pickAxe_stone, Item::pickAxe_iron, Item::pickAxe_emerald, Item::pickAxe_gold}, - {Item::shovel_wood, Item::shovel_stone, Item::shovel_iron, Item::shovel_emerald, Item::shovel_gold}, - {Item::hatchet_wood, Item::hatchet_stone, Item::hatchet_iron, Item::hatchet_emerald, Item::hatchet_gold}, - {Item::hoe_wood, Item::hoe_stone, Item::hoe_iron, Item::hoe_emerald, Item::hoe_gold}, - }; - - //const int OVERRIDDEN_MaterialCount = 2; - for (int m = 0; m < NumMaterials; m++) { - int mId = materialIds[m]; - for (int t = 0; t < NumRecipes; t++) { - Item* target = (Item*) map[t][m]; - - if (mId < 256) { // Tile - r->addShapedRecipe( ItemInstance(target), shapes[t], - definition('#', Item::stick, 'X', Tile::tiles[mId]) ); - } else { // Item - r->addShapedRecipe( ItemInstance(target), shapes[t], - definition('#', Item::stick, 'X', Item::items[mId]) ); - } - } - } - - r->addShapedRecipe( ItemInstance(Item::shears), // - " #", // - "# ", // - - definition('#', Item::ironIngot)); -} +#include "ToolRecipes.hpp" +#include "Recipes.hpp" +#include "world/item/ShearsItem.hpp" +#include "world/level/tile/Tile.hpp" + + +static RowList shapes[] = { + Recipes::Shape( "XXX", // + " # ",// + " # "),// + + Recipes::Shape( "X",// + "#",// + "#"),// + + Recipes::Shape( "XX",// + "X#",// + " #"),// + + Recipes::Shape( "XX",// + " #",// + " #")// +}; + +void ToolRecipes::addRecipes( Recipes* r ) +{ + int materialIds[] = {Tile::wood->id, Tile::stoneBrick->id, Item::ironIngot->id, Item::emerald->id, Item::goldIngot->id}; + const int NumMaterials = sizeof(materialIds) / sizeof(int); + const int NumRecipes = sizeof(shapes) / sizeof(RowList); + + Item* map[NumRecipes][NumMaterials] = { + {Item::pickAxe_wood, Item::pickAxe_stone, Item::pickAxe_iron, Item::pickAxe_emerald, Item::pickAxe_gold}, + {Item::shovel_wood, Item::shovel_stone, Item::shovel_iron, Item::shovel_emerald, Item::shovel_gold}, + {Item::hatchet_wood, Item::hatchet_stone, Item::hatchet_iron, Item::hatchet_emerald, Item::hatchet_gold}, + {Item::hoe_wood, Item::hoe_stone, Item::hoe_iron, Item::hoe_emerald, Item::hoe_gold}, + }; + + //const int OVERRIDDEN_MaterialCount = 2; + for (int m = 0; m < NumMaterials; m++) { + int mId = materialIds[m]; + for (int t = 0; t < NumRecipes; t++) { + Item* target = (Item*) map[t][m]; + + if (mId < 256) { // Tile + r->addShapedRecipe( ItemInstance(target), shapes[t], + definition('#', Item::stick, 'X', Tile::tiles[mId]) ); + } else { // Item + r->addShapedRecipe( ItemInstance(target), shapes[t], + definition('#', Item::stick, 'X', Item::items[mId]) ); + } + } + } + + r->addShapedRecipe( ItemInstance(Item::shears), // + " #", // + "# ", // + + definition('#', Item::ironIngot)); +} diff --git a/src/world/item/crafting/ToolRecipes.h b/src/world/item/crafting/ToolRecipes.hpp similarity index 100% rename from src/world/item/crafting/ToolRecipes.h rename to src/world/item/crafting/ToolRecipes.hpp diff --git a/src/world/item/crafting/WeaponRecipes.cpp b/src/world/item/crafting/WeaponRecipes.cpp index 8d98efd..83aacc9 100755 --- a/src/world/item/crafting/WeaponRecipes.cpp +++ b/src/world/item/crafting/WeaponRecipes.cpp @@ -1,49 +1,49 @@ -#include "WeaponRecipes.h" - -static RowList shapes[] = { - Recipes::Shape( "X", // - "X",// - "#"),// -}; - -void WeaponRecipes::addRecipes( Recipes* r ) -{ - int materialIds[] = {Tile::wood->id, Tile::stoneBrick->id, Item::ironIngot->id, Item::emerald->id, Item::goldIngot->id}; - const int NumMaterials = sizeof(materialIds) / sizeof(int); - const int NumRecipes = sizeof(shapes) / sizeof(RowList); - - Item* map[NumRecipes][NumMaterials] = { - {Item::sword_wood, Item::sword_stone, Item::sword_iron, Item::sword_emerald, Item::sword_gold}, - }; - - //const int OVERRIDDEN_MaterialCount = 2; - for (int m = 0; m < NumMaterials; m++) { - int mId = materialIds[m]; - for (int t = 0; t < NumRecipes; t++) { - Item* target = (Item*) map[t][m]; - - if (mId < 256) { // Tile - r->addShapedRecipe( ItemInstance(target), shapes[t], - definition('#', Item::stick, 'X', Tile::tiles[mId]) ); - } else { // Item - r->addShapedRecipe( ItemInstance(target), shapes[t], - definition('#', Item::stick, 'X', Item::items[mId]) ); - } - } - } - - r->addShapedRecipe(ItemInstance(Item::bow, 1), // - " #X", // - "# X", // - " #X", // - definition( 'X', Item::string,// - '#', Item::stick)); - - r->addShapedRecipe(ItemInstance(Item::arrow, 4), // - "X", // - "#", // - "Y", // - definition( 'Y', Item::feather,// - 'X', Item::flint,// - '#', Item::stick)); -} +#include "WeaponRecipes.hpp" + +static RowList shapes[] = { + Recipes::Shape( "X", // + "X",// + "#"),// +}; + +void WeaponRecipes::addRecipes( Recipes* r ) +{ + int materialIds[] = {Tile::wood->id, Tile::stoneBrick->id, Item::ironIngot->id, Item::emerald->id, Item::goldIngot->id}; + const int NumMaterials = sizeof(materialIds) / sizeof(int); + const int NumRecipes = sizeof(shapes) / sizeof(RowList); + + Item* map[NumRecipes][NumMaterials] = { + {Item::sword_wood, Item::sword_stone, Item::sword_iron, Item::sword_emerald, Item::sword_gold}, + }; + + //const int OVERRIDDEN_MaterialCount = 2; + for (int m = 0; m < NumMaterials; m++) { + int mId = materialIds[m]; + for (int t = 0; t < NumRecipes; t++) { + Item* target = (Item*) map[t][m]; + + if (mId < 256) { // Tile + r->addShapedRecipe( ItemInstance(target), shapes[t], + definition('#', Item::stick, 'X', Tile::tiles[mId]) ); + } else { // Item + r->addShapedRecipe( ItemInstance(target), shapes[t], + definition('#', Item::stick, 'X', Item::items[mId]) ); + } + } + } + + r->addShapedRecipe(ItemInstance(Item::bow, 1), // + " #X", // + "# X", // + " #X", // + definition( 'X', Item::string,// + '#', Item::stick)); + + r->addShapedRecipe(ItemInstance(Item::arrow, 4), // + "X", // + "#", // + "Y", // + definition( 'Y', Item::feather,// + 'X', Item::flint,// + '#', Item::stick)); +} diff --git a/src/world/item/crafting/WeaponRecipes.h b/src/world/item/crafting/WeaponRecipes.hpp similarity index 69% rename from src/world/item/crafting/WeaponRecipes.h rename to src/world/item/crafting/WeaponRecipes.hpp index e934b35..43b8310 100755 --- a/src/world/item/crafting/WeaponRecipes.h +++ b/src/world/item/crafting/WeaponRecipes.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.item.crafting; -#include "Recipes.h" -#include "../../level/tile/Tile.h" +#include "Recipes.hpp" +#include "world/level/tile/Tile.hpp" class WeaponRecipes { diff --git a/src/world/level/ChunkPos.h b/src/world/level/ChunkPos.hpp similarity index 95% rename from src/world/level/ChunkPos.h rename to src/world/level/ChunkPos.hpp index d11275d..fe83ec9 100755 --- a/src/world/level/ChunkPos.h +++ b/src/world/level/ChunkPos.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level; -#include "../entity/Entity.h" +#include "world/entity/Entity.hpp" class ChunkPos { public: diff --git a/src/world/level/Explosion.cpp b/src/world/level/Explosion.cpp index 118b4ef..c8b11f5 100755 --- a/src/world/level/Explosion.cpp +++ b/src/world/level/Explosion.cpp @@ -1,164 +1,164 @@ -#include "Explosion.h" - -#include "Level.h" -#include "tile/Tile.h" -#include "../entity/Entity.h" - - -Explosion::Explosion(Level* level, Entity* source, float x, float y, float z, float r) -: level(level), - source(source), - x(x), - y(y), - z(z), - r(r), - fire(false) -{ -} - -void Explosion::explode() -{ - float org = r; - - int size = 16; - for (int xx = 0; xx < size; xx++) - for (int yy = 0; yy < size; yy++) - for (int zz = 0; zz < size; zz++) { - if ((xx != 0 && xx != size - 1) && (yy != 0 && yy != size - 1) && (zz != 0 && zz != size - 1)) continue; - - float xd = xx / (size - 1.0f) * 2 - 1; - float yd = yy / (size - 1.0f) * 2 - 1; - float zd = zz / (size - 1.0f) * 2 - 1; - float d = sqrt(xd * xd + yd * yd + zd * zd); - - xd /= d; - yd /= d; - zd /= d; - - float remainingPower = r * (0.7f + level->random.nextFloat() * 0.6f); - float xp = x; - float yp = y; - float zp = z; - - float stepSize = 0.3f; - while (remainingPower > 0) { - int xt = Mth::floor(xp); - int yt = Mth::floor(yp); - int zt = Mth::floor(zp); - int t = level->getTile(xt, yt, zt); - if (t > 0) { - remainingPower -= (Tile::tiles[t]->getExplosionResistance(source) + 0.3f) * stepSize; - } - if (remainingPower > 0) { - toBlow.insert(TilePos(xt, yt, zt)); - } - - xp += xd * stepSize; - yp += yd * stepSize; - zp += zd * stepSize; - remainingPower -= stepSize * 0.75f; - } - } - - r += r; - int x0 = Mth::floor(x - r - 1); - int x1 = Mth::floor(x + r + 1); - int y0 = Mth::floor(y - r - 1); - int y1 = Mth::floor(y + r + 1); - int z0 = Mth::floor(z - r - 1); - int z1 = Mth::floor(z + r + 1); - EntityList& entities = level->getEntities(source, AABB((float)x0, (float)y0, (float)z0, (float)x1, (float)y1, (float)z1)); - Vec3 center(x, y, z); - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - float dist = e->distanceTo(x, y, z) / r; - if (dist <= 1) { - float xa = e->x - x; - float ya = e->y - y; - float za = e->z - z; - - float ida = Mth::invSqrt(xa * xa + ya * ya + za * za); - - xa *= ida; - ya *= ida; - za *= ida; - - float sp = level->getSeenPercent(center, e->bb); - float pow = (1 - dist) * sp; - e->hurt(source, (int) ((pow * pow + pow) / 2 * 8 * r + 1)); - - float push = pow; - e->xd += xa * push; - e->yd += ya * push; - e->zd += za * push; - } - } - r = org; - - std::vector toBlowArray; - toBlowArray.insert(toBlowArray.end(), toBlow.begin(), toBlow.end()); - - if (fire) { - for (int j = (int)toBlowArray.size() - 1; j >= 0; j--) { - const TilePos& tp = toBlowArray[j]; - int xt = tp.x; - int yt = tp.y; - int zt = tp.z; - int t = level->getTile(xt, yt, zt); - int b = level->getTile(xt, yt - 1, zt); - if (t == 0 && Tile::solid[b] && random.nextInt(3) == 0) { - level->setTileNoUpdate(xt, yt, zt, ((Tile*)Tile::fire)->id); - } - } - } -} - -void Explosion::finalizeExplosion() -{ - level->playSound(x, y, z, "random.explode", 4, (1 + (level->random.nextFloat() - level->random.nextFloat()) * 0.2f) * 0.7f); - //level->addParticle(PARTICLETYPE(hugeexplosion), x, y, z, 0, 0, 0); - - int j = 0; - for (TilePosSet::const_iterator cit = toBlow.begin(); cit != toBlow.end(); ++cit, ++j) { - const TilePos& tp = *cit; - int xt = tp.x; - int yt = tp.y; - int zt = tp.z; - int t = level->getTile(xt, yt, zt); - - do { - if (j & 7) break; - - float xa = xt + level->random.nextFloat(); - float ya = yt + level->random.nextFloat(); - float za = zt + level->random.nextFloat(); - - float xd = xa - x; - float yd = ya - y; - float zd = za - z; - - float invdd = 1.0f / Mth::sqrt(xd * xd + yd * yd + zd * zd); - - xd *= invdd; - yd *= invdd; - zd *= invdd; - - float speed = 0.5f / (r / invdd + 0.1f); - speed *= (level->random.nextFloat() * level->random.nextFloat() + 0.3f); - xd *= speed; - yd *= speed; - zd *= speed; - - level->addParticle(PARTICLETYPE(explode), (xa + x * 1) / 2, (ya + y * 1) / 2, (za + z * 1) / 2, xd, yd, zd); - level->addParticle(PARTICLETYPE(smoke), xa, ya, za, xd, yd, zd); - } while (0); - - if (t > 0) { - if (!level->isClientSide) Tile::tiles[t]->spawnResources(level, xt, yt, zt, level->getData(xt, yt, zt), 0.3f); - if (level->setTileNoUpdate(xt, yt, zt, 0)) - level->updateNeighborsAt(xt, yt, zt, 0); - level->setTileDirty(xt, yt, zt); - if (!level->isClientSide) Tile::tiles[t]->wasExploded(level, xt, yt, zt); - } - } -} +#include "Explosion.hpp" + +#include "Level.hpp" +#include "tile/Tile.hpp" +#include "world/entity/Entity.hpp" + + +Explosion::Explosion(Level* level, Entity* source, float x, float y, float z, float r) +: level(level), + source(source), + x(x), + y(y), + z(z), + r(r), + fire(false) +{ +} + +void Explosion::explode() +{ + float org = r; + + int size = 16; + for (int xx = 0; xx < size; xx++) + for (int yy = 0; yy < size; yy++) + for (int zz = 0; zz < size; zz++) { + if ((xx != 0 && xx != size - 1) && (yy != 0 && yy != size - 1) && (zz != 0 && zz != size - 1)) continue; + + float xd = xx / (size - 1.0f) * 2 - 1; + float yd = yy / (size - 1.0f) * 2 - 1; + float zd = zz / (size - 1.0f) * 2 - 1; + float d = sqrt(xd * xd + yd * yd + zd * zd); + + xd /= d; + yd /= d; + zd /= d; + + float remainingPower = r * (0.7f + level->random.nextFloat() * 0.6f); + float xp = x; + float yp = y; + float zp = z; + + float stepSize = 0.3f; + while (remainingPower > 0) { + int xt = Mth::floor(xp); + int yt = Mth::floor(yp); + int zt = Mth::floor(zp); + int t = level->getTile(xt, yt, zt); + if (t > 0) { + remainingPower -= (Tile::tiles[t]->getExplosionResistance(source) + 0.3f) * stepSize; + } + if (remainingPower > 0) { + toBlow.insert(TilePos(xt, yt, zt)); + } + + xp += xd * stepSize; + yp += yd * stepSize; + zp += zd * stepSize; + remainingPower -= stepSize * 0.75f; + } + } + + r += r; + int x0 = Mth::floor(x - r - 1); + int x1 = Mth::floor(x + r + 1); + int y0 = Mth::floor(y - r - 1); + int y1 = Mth::floor(y + r + 1); + int z0 = Mth::floor(z - r - 1); + int z1 = Mth::floor(z + r + 1); + EntityList& entities = level->getEntities(source, AABB((float)x0, (float)y0, (float)z0, (float)x1, (float)y1, (float)z1)); + Vec3 center(x, y, z); + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + float dist = e->distanceTo(x, y, z) / r; + if (dist <= 1) { + float xa = e->x - x; + float ya = e->y - y; + float za = e->z - z; + + float ida = Mth::invSqrt(xa * xa + ya * ya + za * za); + + xa *= ida; + ya *= ida; + za *= ida; + + float sp = level->getSeenPercent(center, e->bb); + float pow = (1 - dist) * sp; + e->hurt(source, (int) ((pow * pow + pow) / 2 * 8 * r + 1)); + + float push = pow; + e->xd += xa * push; + e->yd += ya * push; + e->zd += za * push; + } + } + r = org; + + std::vector toBlowArray; + toBlowArray.insert(toBlowArray.end(), toBlow.begin(), toBlow.end()); + + if (fire) { + for (int j = (int)toBlowArray.size() - 1; j >= 0; j--) { + const TilePos& tp = toBlowArray[j]; + int xt = tp.x; + int yt = tp.y; + int zt = tp.z; + int t = level->getTile(xt, yt, zt); + int b = level->getTile(xt, yt - 1, zt); + if (t == 0 && Tile::solid[b] && random.nextInt(3) == 0) { + level->setTileNoUpdate(xt, yt, zt, ((Tile*)Tile::fire)->id); + } + } + } +} + +void Explosion::finalizeExplosion() +{ + level->playSound(x, y, z, "random.explode", 4, (1 + (level->random.nextFloat() - level->random.nextFloat()) * 0.2f) * 0.7f); + //level->addParticle(PARTICLETYPE(hugeexplosion), x, y, z, 0, 0, 0); + + int j = 0; + for (TilePosSet::const_iterator cit = toBlow.begin(); cit != toBlow.end(); ++cit, ++j) { + const TilePos& tp = *cit; + int xt = tp.x; + int yt = tp.y; + int zt = tp.z; + int t = level->getTile(xt, yt, zt); + + do { + if (j & 7) break; + + float xa = xt + level->random.nextFloat(); + float ya = yt + level->random.nextFloat(); + float za = zt + level->random.nextFloat(); + + float xd = xa - x; + float yd = ya - y; + float zd = za - z; + + float invdd = 1.0f / Mth::sqrt(xd * xd + yd * yd + zd * zd); + + xd *= invdd; + yd *= invdd; + zd *= invdd; + + float speed = 0.5f / (r / invdd + 0.1f); + speed *= (level->random.nextFloat() * level->random.nextFloat() + 0.3f); + xd *= speed; + yd *= speed; + zd *= speed; + + level->addParticle(PARTICLETYPE(explode), (xa + x * 1) / 2, (ya + y * 1) / 2, (za + z * 1) / 2, xd, yd, zd); + level->addParticle(PARTICLETYPE(smoke), xa, ya, za, xd, yd, zd); + } while (0); + + if (t > 0) { + if (!level->isClientSide) Tile::tiles[t]->spawnResources(level, xt, yt, zt, level->getData(xt, yt, zt), 0.3f); + if (level->setTileNoUpdate(xt, yt, zt, 0)) + level->updateNeighborsAt(xt, yt, zt, 0); + level->setTileDirty(xt, yt, zt); + if (!level->isClientSide) Tile::tiles[t]->wasExploded(level, xt, yt, zt); + } + } +} diff --git a/src/world/level/Explosion.h b/src/world/level/Explosion.hpp similarity index 88% rename from src/world/level/Explosion.h rename to src/world/level/Explosion.hpp index 7181d9a..2f08210 100755 --- a/src/world/level/Explosion.h +++ b/src/world/level/Explosion.hpp @@ -4,8 +4,8 @@ #include -#include "TilePos.h" -#include "../../util/Random.h" +#include "TilePos.hpp" +#include "util/Random.hpp" class Level; class Entity; diff --git a/src/world/level/FoliageColor.h b/src/world/level/FoliageColor.hpp similarity index 100% rename from src/world/level/FoliageColor.h rename to src/world/level/FoliageColor.hpp diff --git a/src/world/level/Level.cpp b/src/world/level/Level.cpp index 96255eb..4a95644 100755 --- a/src/world/level/Level.cpp +++ b/src/world/level/Level.cpp @@ -1,2241 +1,2241 @@ -#include "Level.h" -#include "LevelListener.h" -#include "tile/entity/TileEntity.h" -#include "../entity/player/Player.h" -#include "../entity/EntityEvent.h" - -#include "biome/BiomeSource.h" -#include "chunk/storage/ChunkStorage.h" -#include "chunk/ChunkCache.h" -#include "storage/LevelStorage.h" -#include "Region.h" -#include "Explosion.h" -#include "LevelConstants.h" -#include "pathfinder/PathFinder.h" - -#include "../Facing.h" -#include "../../util/PerfTimer.h" - -#include "tile/LiquidTile.h" - -#include "biome/Biome.h" -#include "MobSpawner.h" -#include "../../network/packet/SetEntityDataPacket.h" -#include "../../network/RakNetInstance.h" -#include "../../network/packet/EntityEventPacket.h" -#include "../../network/packet/SetTimePacket.h" -#include "../entity/monster/Zombie.h" -#include "../inventory/BaseContainerMenu.h" -#include "../Difficulty.h" -#include "../../network/packet/ExplodePacket.h" - -Level::Level(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */) -: levelStorage(levelStorage), - isClientSide(false), - isFindingSpawn(false), - noNeighborUpdate(false), - skyDarken(0), - instaTick(false), - random(1), - _isNew(false), - _chunkSource(NULL), - _randValue(42184323), - _addend(1013904223), - _maxRecurse(0), - _updateLights(true), - _pathFinder(NULL), - _spawnFriendlies(true), - _spawnEnemies(true), - _lastSavedPlayerTime(0), // @attn: @time: clock starts on 0 now, change if not - raknetInstance(0), - updatingTileEntities(false), - allPlayersAreSleeping(false), - _nightMode(false) -{ - _init(levelName, settings, generatorVersion, fixedDimension); -} - -Level::~Level() { - LOGI("Erasing chunk source\n"); - delete _chunkSource; - LOGI("Erasing dimension\n"); - delete dimension; - delete _pathFinder; - - std::set all; - all.insert(entities.begin(), entities.end()); - all.insert(players.begin(), players.end()); - PendingList::iterator it = _pendingPlayerRemovals.begin(); - while (it != _pendingPlayerRemovals.end()) { - all.insert(it->e); - ++it; - } - for (std::set::iterator it = all.begin(); it != all.end(); ++it) - delete *it; - - std::set allTileEntities; - allTileEntities.insert(tileEntities.begin(), tileEntities.end()); - allTileEntities.insert(pendingTileEntities.begin(), pendingTileEntities.end()); - for (std::set::iterator it = allTileEntities.begin(); it != allTileEntities.end(); ++it) - delete *it; -} - -void Level::_init(const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension) { - - isGeneratingTerrain = false; - - LevelData* preparedData = levelStorage->prepareLevel(this); - _isNew = (preparedData == NULL); - - if (preparedData == NULL) { - levelData = LevelData(settings, levelName, generatorVersion); - } else { - levelData = *preparedData; - levelData.setLevelName(levelName); - } - - if (fixedDimension != NULL) { - dimension = fixedDimension; - } else { - dimension = DimensionFactory::createDefaultDimension( &levelData ); - } - - dimension->init(this); - _chunkSource = createChunkSource(); - - _pathFinder = new PathFinder(); - _nightMode = false; - updateSkyBrightness(); -} - -/*protected*/ -ChunkSource* Level::createChunkSource() { - if (!levelStorage) { - printf("no level data, calling dimension->createRandomLevelSource\n"); - return dimension->createRandomLevelSource(); //@note - } - - ChunkStorage* chunkStorage = levelStorage->createChunkStorage(dimension); - return new ChunkCache(this, chunkStorage, dimension->createRandomLevelSource()); -} - -/*public*/ -bool Level::checkAndHandleWater(const AABB& box, const Material* material, Entity* e) { - int x0 = Mth::floor(box.x0); - int x1 = Mth::floor(box.x1 + 1); - - int y0 = Mth::floor(box.y0); - int y1 = Mth::floor(box.y1 + 1); - - int z0 = Mth::floor(box.z0); - int z1 = Mth::floor(box.z1 + 1); - - if (!hasChunksAt(x0, y0, z0, x1, y1, z1)) { - return false; - } - - bool ok = false; - Vec3 current(0,0,0); - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) - for (int z = z0; z < z1; z++) { - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL && tile->material == material) { - float yt0 = y + 1 - LiquidTile::getHeight(getData(x, y, z)); - if (y1 >= yt0) { - ok = true; - tile->handleEntityInside(this, x, y, z, e, current); - } - } - } - float len = current.length(); - if (len > 0) { - const float pow = 0.004f / len; - e->xd += current.x * pow; - e->yd += current.y * pow; - e->zd += current.z * pow; - } - return ok; -} - -/*public*/ -Player* Level::getNearestPlayer(Entity* source, float maxDist) { - return getNearestPlayer(source->x, source->y, source->z, maxDist); -} - -/*public*/ -Player* Level::getNearestPlayer(float x, float y, float z, float maxDist) { - float maxDistSqr = maxDist * maxDist; - float best = -1; - Player* result = NULL; - for (unsigned int i = 0; i < players.size(); i++) { - Player* p = players[i]; - if (p->removed) continue; - float dist = p->distanceToSqr(x, y, z); - if ((maxDist < 0 || dist < maxDistSqr) && (best == -1 || dist < best)) { - best = dist; - result = p; - } - } - return result; -} - -/*public*/ -void Level::tick() { - if (!isClientSide && levelData.getSpawnMobs()) { - static int _mobSpawnTick = 0; - const int MobSpawnInterval = 2; - if (++_mobSpawnTick >= MobSpawnInterval) { - _mobSpawnTick = 0; - TIMER_PUSH("mobSpawner"); - MobSpawner::tick(this, _spawnEnemies && difficulty > Difficulty::PEACEFUL, - _spawnFriendlies && (levelData.getTime() % 400) < MobSpawnInterval); - TIMER_POP(); - } - } - - TIMER_PUSH("chunkSource"); - _chunkSource->tick(); - - updateSkyDarken(); - if(_nightMode) { - long curTime = levelData.getTime(); - if(curTime % TICKS_PER_DAY != MIDDLE_OF_NIGHT_TIME) { - if(curTime % TICKS_PER_DAY < MIDDLE_OF_NIGHT_TIME && (curTime + 20) % TICKS_PER_DAY > MIDDLE_OF_NIGHT_TIME) { - curTime = MIDDLE_OF_NIGHT_TIME; - SetTimePacket packet(curTime); - raknetInstance->send(packet); - } - else { - curTime += 20; - if(curTime % 20 == 0) { - SetTimePacket packet(curTime); - raknetInstance->send(packet); - } - } - setTime(curTime%TICKS_PER_DAY); - } - } - else { - long time = levelData.getTime() + 1; - //if (time % (saveInterval) == 0) { - // save(false, NULL); - //} - levelData.setTime(time); - if ((time & 255) == 0) { - SetTimePacket packet(time); - raknetInstance->send(packet); - } - } - TIMER_POP_PUSH("tickPending"); - tickPendingTicks(false); - - TIMER_POP_PUSH("tickTiles"); - tickTiles(); - - TIMER_POP_PUSH("sendEntityData"); - for (unsigned int i = 0; i < entities.size(); ++i) { - Entity* e = entities[i]; - SynchedEntityData* data = e->getEntityData(); - if (data && data->isDirty()) { - SetEntityDataPacket packet(e->entityId, *data); - raknetInstance->send(packet); - } - } - - //if (!_pendingEntityData.empty()) { - // for (EntityMap::iterator it = _pendingEntityData.begin(); it != _pendingEntityData.end(); ++it) { - // SetEntityDataPacket packet(it->first, it->second->getEntityData()); - // raknetInstance->send(packet); - // } - // _pendingEntityData.clear(); - //} - TIMER_POP(); -} - -/*protected*/ -void Level::tickTiles() { - _chunksToPoll.clear(); - - static const int pollChunkOffsets[] = { - -1,-4, 0,-4, 1,-4, -2,-3, -1,-3, 0,-3, 1,-3, 2,-3, -3,-2, - -2,-2, -1,-2, 0,-2, 1,-2, 2,-2, 3,-2, -4,-1, -3,-1, -2,-1, - -1,-1, 0,-1, 1,-1, 2,-1, 3,-1, 4,-1, -4,0, -3,0, -2,0, -1,0, - 0,0, 1,0, 2,0, 3,0, 4,0, -4,1, -3,1, -2,1, -1,1, 0,1, 1,1, - 2,1, 3,1, 4,1, -3,2, -2,2, -1,2, 0,2, 1,2, 2,2, 3,2, -2,3, - -1,3, 0,3, 1,3, 2,3, -1,4, 0,4, 1,4 - }; - const int pollChunkOffsetsSize = sizeof(pollChunkOffsets) / sizeof(int); - - TIMER_PUSH("buildList"); - //static Stopwatch w; - //w.start(); - for (size_t i = 0; i < players.size(); i++) { - Player* player = players[i]; - int xx = Mth::floor(player->x / 16); - int zz = Mth::floor(player->z / 16); - - for (int i = 0; i < pollChunkOffsetsSize; i += 2) { - const int xp = xx + pollChunkOffsets[i]; - const int zp = zz + pollChunkOffsets[i+1]; - if (xp >= 0 && xp < CHUNK_CACHE_WIDTH && - zp >= 0 && zp < CHUNK_CACHE_WIDTH) - _chunksToPoll.insert(ChunkPos(xp, zp)); - } - } - TIMER_POP(); - - //if (delayUntilNextMoodSound > 0) delayUntilNextMoodSound--; - TIMER_PUSH("loop"); - for (ChunkPosSet::iterator it = _chunksToPoll.begin(); it != _chunksToPoll.end(); ++it) { - const ChunkPos& cp = *it; - int xo = cp.x * 16; - int zo = cp.z * 16; - // LevelSource region = new Region(this, xo, 0, zo, xo + 16, 128, zo + 16); - TIMER_PUSH("getChunk"); - LevelChunk* lc = this->getChunk(cp.x, cp.z); - TIMER_POP_PUSH("tickChunk"); - //lc->tick(); - - //if (delayUntilNextMoodSound == 0) { - // randValue = randValue * 3 + addend; - // int val = (randValue >> 2); - // int x = (val & 15); - // int z = ((val >> 8) & 15); - // int y = ((val >> 16) & 127); - - // int id = lc->getTile(x, y, z); - // x += xo; - // z += zo; - // if (id == 0 && getRawBrightness(x, y, z) <= random.nextInt(8) && getBrightness(LightLayer::Sky, x, y, z) <= 0) { - // Player* player = getNearestPlayer(x + 0.5, y + 0.5, z + 0.5, 8); - // if (player != NULL && player.distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 2 * 2) { - // //this.playSound(x + 0.5, y + 0.5, z + 0.5, "ambient.cave.cave", 0.7f, 0.8f + random.nextFloat() * 0.2f); - // delayUntilNextMoodSound = random.nextInt(20 * 60 * 10) + 20 * 60 * 5; - // } - // } - //} - - TIMER_POP_PUSH("tickTiles"); - for (int i = 0; i < 20; i++) { //@todo: CHUNK_TILE_TICK_COUNT - _randValue = _randValue * 3 + _addend; - int val = (_randValue >> 2); - int x = (val & 15); - int z = ((val >> 8) & 15); - int y = ((val >> 16) & 127); - - int id = lc->getTile(x, y, z); - if (Tile::shouldTick[id]) { - Tile::tiles[id]->tick(this, x + xo, y, z + zo, &random); - } - } - TIMER_POP(); - } - TIMER_POP(); - //w.stop(); - //w.printEvery(30, "ticktiles"); -} - -bool Level::tickPendingTicks(bool force) { - int count = _tickNextTickSet.size(); - if (count > MAX_TICK_TILES_PER_TICK) count = MAX_TICK_TILES_PER_TICK; - for (int i = 0; i < count; i++) { - TickDataSet::iterator td = _tickNextTickSet.begin(); - if (!force && td->delay > levelData.getTime()) { - break; - } - - int r = 8; - if (hasChunksAt(td->x - r, td->y - r, td->z - r, td->x + r, td->y + r, td->z + r)) { - int id = getTile(td->x, td->y, td->z); - if (id == td->tileId && id > 0) { - Tile::tiles[id]->tick(this, td->x, td->y, td->z, &random); - } - } - _tickNextTickSet.erase(td); - } - return _tickNextTickSet.size() != 0; -} - -/*public*/ -void Level::loadPlayer(Player* player, bool doAddPlayer /*= true*/) { - if (player) { - CompoundTag* loadedPlayerTag = levelData.getLoadedPlayerTag(); - if (loadedPlayerTag != NULL) { - player->load(loadedPlayerTag); - levelData.setLoadedPlayerTag(NULL); - } else { - levelData.setLoadedPlayerTo(player); - } - if (doAddPlayer) - addEntity(player); - } - //} catch (Exception e) { - // e.printStackTrace(); - //} -} - -bool Level::findPath(Path* path, Entity* from, Entity* to, float maxDist, bool canOpenDoors, bool avoidWater) { - TIMER_PUSH("pathfind"); - int x = Mth::floor(from->x); - int y = Mth::floor(from->y); - int z = Mth::floor(from->z); - - int r = (int) (maxDist + 16); - int x1 = x - r; - int y1 = y - r; - int z1 = z - r; - int x2 = x + r; - int y2 = y + r; - int z2 = z + r; - //LOGI("trying to move! 1: %ld\n", levelData.getTime()); - Region region(this, x1, y1, z1, x2, y2, z2); - _pathFinder->setLevelSource(®ion); - _pathFinder->canOpenDoors = canOpenDoors; - _pathFinder->avoidWater = avoidWater; - _pathFinder->findPath(path, from, to, maxDist); - TIMER_POP(); - return true; -} - -bool Level::findPath(Path* path, Entity* from, int xBest, int yBest, int zBest, float maxDist, bool canOpenDoors, bool avoidWater) { - TIMER_PUSH("pathfind"); - int x = Mth::floor(from->x); - int y = Mth::floor(from->y); - int z = Mth::floor(from->z); - - int r = (int) (maxDist + 8); - int x1 = x - r; - int y1 = y - r; - int z1 = z - r; - int x2 = x + r; - int y2 = y + r; - int z2 = z + r; - Region region(this, x1, y1, z1, x2, y2, z2); - //LOGI("trying to move! 2: %ld\n", levelData.getTime()); - _pathFinder->setLevelSource(®ion); - _pathFinder->canOpenDoors = canOpenDoors; - _pathFinder->avoidWater = avoidWater; - _pathFinder->findPath(path, from, xBest, yBest, zBest, maxDist); - TIMER_POP(); - return true; -} - -/** -* Sets the initial spawn, created this method so we could do a special -* location for the demo version. -*/ -/*protected*/ -void Level::setInitialSpawn() { - isFindingSpawn = true; - int xSpawn = CHUNK_CACHE_WIDTH * CHUNK_WIDTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; - int ySpawn = 64; - int zSpawn = CHUNK_CACHE_WIDTH * CHUNK_DEPTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; - while (!dimension->isValidSpawn(xSpawn, zSpawn)) { - xSpawn += random.nextInt(32) - random.nextInt(32); - zSpawn += random.nextInt(32) - random.nextInt(32); - - if (xSpawn < 4) xSpawn += 32; - if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 32; - if (zSpawn < 4) zSpawn += 32; - if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 32; - } - levelData.setSpawn(xSpawn, ySpawn, zSpawn); - isFindingSpawn = false; -} - -/*public*/ -void Level::validateSpawn() { - if (levelData.getYSpawn() <= 0) { - levelData.setYSpawn(64); - } - int xSpawn = levelData.getXSpawn(); - int zSpawn = levelData.getZSpawn(); - while (getTopTile(xSpawn, zSpawn) == 0 || getTopTile(xSpawn, zSpawn) == Tile::invisible_bedrock->id) { - xSpawn += random.nextInt(8) - random.nextInt(8); - zSpawn += random.nextInt(8) - random.nextInt(8); - - if (xSpawn < 4) xSpawn += 8; - if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 8; - if (zSpawn < 4) zSpawn += 8; - if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 8; - } - levelData.setXSpawn(xSpawn); - levelData.setZSpawn(zSpawn); -} - -int Level::getTopTile(int x, int z) { - int y = 63; - while (!isEmptyTile(x, y + 1, z)) { - y++; - } - return getTile(x, y, z); -} - -int Level::getTopTileY(int x, int z) { - int y = 63; - while (!isEmptyTile(x, y + 1, z)) { - y++; - } - return y; -} -// -// void clearLoadedPlayerData() { -// } -// -// void save(bool force, ProgressListener progressListener) { -// if (!chunkSource.shouldSave()) return; -// -// if (progressListener != NULL) progressListener.progressStartNoAbort("Saving level"); -// saveLevelData(); -// -// if (progressListener != NULL) progressListener.progressStage("Saving chunks"); -// chunkSource.save(force, progressListener); -// } -// - -//void Level::saveAllChunks() { -// _chunkSource->saveAll(); -//} - -void Level::saveLevelData() { - levelStorage->saveLevelData(levelData, &players); -} - -// bool pauseSave(int step) { -// if (!chunkSource.shouldSave()) return true; -// if (step == 0) saveLevelData(); -// return chunkSource.save(false, NULL); -// } - -//void Level::savePlayerData() { -// levelStorage->savePlayerData(&levelData, players); -//} - -int Level::getTile(int x, int y, int z) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return 0; - //} - if (y < 0) return 0; - if (y >= DEPTH) return 0; - //if (z == 128) { - // int a = 0; - //} - //LOGI("%d ", z); - return getChunk(x >> 4, z >> 4)->getTile(x & 15, y, z & 15); -} - -bool Level::isEmptyTile(int x, int y, int z) { - return getTile(x, y, z) == 0; -} - -bool Level::hasChunkAt(int x, int y, int z) { - if (y < 0 || y >= Level::DEPTH) return false; - return hasChunk(x >> 4, z >> 4); -} - - -bool Level::hasChunksAt(int x, int y, int z, int r) { - return hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r); -} - -bool Level::hasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1) { - if (y1 < 0 || y0 >= Level::DEPTH) return false; - - x0 >>= 4; - z0 >>= 4; - x1 >>= 4; - z1 >>= 4; - - for (int x = x0; x <= x1; x++) - for (int z = z0; z <= z1; z++) - if (!hasChunk(x, z)) return false; - - return true; -} - -bool Level::hasChunk(int x, int z) { - return _chunkSource->hasChunk(x, z); -} - -LevelChunk* Level::getChunkAt(int x, int z) { - return getChunk(x >> 4, z >> 4); -} - -LevelChunk* Level::getChunk(int x, int z) { - return _chunkSource->getChunk(x, z); -} - -bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return false; - //} - if (y < 0) return false; - if (y >= DEPTH) return false; - LevelChunk* c = getChunk(x >> 4, z >> 4); - return c->setTileAndData(x & 15, y, z & 15, tile, data); -} - -bool Level::setTileNoUpdate(int x, int y, int z, int tile) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return false; - //} - if (y < 0) return false; - if (y >= DEPTH) return false; - LevelChunk* c = getChunk(x >> 4, z >> 4); - return c->setTile(x & 15, y, z & 15, tile); -} - -const Material* Level::getMaterial(int x, int y, int z) { - int t = getTile(x, y, z); - if (t == 0) return Material::air; - return Tile::tiles[t]->material; -} - -int Level::getData(int x, int y, int z) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return 0; - //} - if (y < 0) return 0; - if (y >= DEPTH) return 0; - LevelChunk* c = getChunk(x >> 4, z >> 4); - x &= 15; - z &= 15; - return c->getData(x, y, z); -} - -void Level::setData(int x, int y, int z, int data) { - //// @newway - //if (setDataNoUpdate(x, y, z, data)) { - // int t = getTile(x, y, z); - // if (Tile::sendTileData[t]) { - // tileUpdated(x, y, z, t); - // } else { - // updateNeighborsAt(x, y, z, t); - // } - //} - - // @oldway - if (setDataNoUpdate(x, y, z, data)) { - tileUpdated(x, y, z, getTile(x, y, z)); - } -} - -bool Level::setDataNoUpdate(int x, int y, int z, int data) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return false; - //} - if (y < 0) return false; - if (y >= DEPTH) return false; - LevelChunk* c = getChunk(x >> 4, z >> 4); - x &= 15; - z &= 15; - - //return c->setData(x, y, z, data); - - if (c->getData(x, y, z) != data) { - c->setData(x, y, z, data); - return true; - } - return false; -} - -bool Level::setTile(int x, int y, int z, int tile) { - if (setTileNoUpdate(x, y, z, tile)) { - //printf("TILE UPDATED %d, %d, %d\n", x, y, z); - tileUpdated(x, y, z, tile); - return true; - } - return false; -} - -bool Level::setTileAndData(int x, int y, int z, int tile, int data) { - if (setTileAndDataNoUpdate(x, y, z, tile, data)) { - tileUpdated(x, y, z, tile); - return true; - } - return false; -} - -void Level::sendTileUpdated(int x, int y, int z) { - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->tileChanged(x, y, z); - } -} - -/*protected*/ -void Level::tileUpdated(int x, int y, int z, int tile) { - sendTileUpdated(x, y, z); - this->updateNeighborsAt(x, y, z, tile); -} - -void Level::lightColumnChanged(int x, int z, int y0, int y1) { - if (y0 > y1) { - int tmp = y1; - y1 = y0; - y0 = tmp; - } - setTilesDirty(x, y0, z, x, y1, z); -} - -void Level::setTileDirty(int x, int y, int z) { - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->setTilesDirty(x, y, z, x, y, z); - } -} - -void Level::setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1) { - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->setTilesDirty(x0, y0, z0, x1, y1, z1); - } -} - -void Level::swap(int x1, int y1, int z1, int x2, int y2, int z2) { - int t1 = getTile(x1, y1, z1); - int d1 = getData(x1, y1, z1); - int t2 = getTile(x2, y2, z2); - int d2 = getData(x2, y2, z2); - - setTileAndDataNoUpdate(x1, y1, z1, t2, d2); - setTileAndDataNoUpdate(x2, y2, z2, t1, d1); - - updateNeighborsAt(x1, y1, z1, t2); - updateNeighborsAt(x2, y2, z2, t1); -} - -void Level::updateNeighborsAt(int x, int y, int z, int tile) { - neighborChanged(x - 1, y, z, tile); - neighborChanged(x + 1, y, z, tile); - neighborChanged(x, y - 1, z, tile); - neighborChanged(x, y + 1, z, tile); - neighborChanged(x, y, z - 1, tile); - neighborChanged(x, y, z + 1, tile); -} - -/*private*/ void Level::neighborChanged(int x, int y, int z, int type) { - if (noNeighborUpdate || isClientSide) return; - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL) tile->neighborChanged(this, x, y, z, type); -} - -bool Level::canSeeSky(int x, int y, int z) { - return getChunk(x >> 4, z >> 4)->isSkyLit(x & 15, y, z & 15); -} - -int Level::getRawBrightness(int x, int y, int z) { - return getRawBrightness(x, y, z, true); -} - -int Level::getRawBrightness(int x, int y, int z, bool propagate) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return MAX_BRIGHTNESS; - //} - - if (propagate) { - int id = getTile(x, y, z); - if (id == Tile::stoneSlabHalf->id || id == Tile::farmland->id) { - int br = getRawBrightness(x, y + 1, z, false); - int br1 = getRawBrightness(x + 1, y, z, false); - int br2 = getRawBrightness(x - 1, y, z, false); - int br3 = getRawBrightness(x, y, z + 1, false); - int br4 = getRawBrightness(x, y, z - 1, false); - if (br1 > br) br = br1; - if (br2 > br) br = br2; - if (br3 > br) br = br3; - if (br4 > br) br = br4; - return br; - } - } - - if (y < 0) return 0; - if (y >= DEPTH) { - int br = MAX_BRIGHTNESS - skyDarken; - if (br < 0) br = 0; - return br; - } - - LevelChunk* c = getChunk(x >> 4, z >> 4); - x &= 15; - z &= 15; - return c->getRawBrightness(x, y, z, skyDarken); -} - -bool Level::isSkyLit(int x, int y, int z) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return false; - //} - if (y < 0) return false; - if (y >= DEPTH) return true; - if (!hasChunk(x >> 4, z >> 4)) return false; - - LevelChunk* c = getChunk(x >> 4, z >> 4); - x &= 15; - z &= 15; - - return c->isSkyLit(x, y, z); -} - -int Level::getHeightmap(int x, int z) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return 0; - //} - if (!hasChunk(x >> 4, z >> 4)) return 0; - - LevelChunk* c = getChunk(x >> 4, z >> 4); - return c->getHeightmap(x & 15, z & 15); -} - -BiomeSource* Level::getBiomeSource() { - return dimension->biomeSource; -} -Biome* Level::getBiome( int x, int z ) { - return dimension->biomeSource->getBiome(x, z); -} - -void Level::updateLightIfOtherThan(const LightLayer& layer, int x, int y, int z, int expected) { - if (dimension->hasCeiling && (&layer) == &LightLayer::Sky) return; - - if (!hasChunkAt(x, y, z)) return; - - if (&layer == &LightLayer::Sky) { - if (isSkyLit(x, y, z)) expected = 15; - } else if (&layer == &LightLayer::Block) { - int t = getTile(x, y, z); - if (Tile::lightEmission[t] > expected) expected = Tile::lightEmission[t]; - } - - if (getBrightness(layer, x, y, z) != expected) { - updateLight(layer, x, y, z, x, y, z); - } -} - -int Level::getBrightness(const LightLayer& layer, int x, int y, int z) { - if (y < 0 || y >= DEPTH/* || x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE*/) { - return layer.surrounding; - } - int xc = x >> 4; - int zc = z >> 4; - if (!hasChunk(xc, zc)) return 0; - LevelChunk* c = getChunk(xc, zc); - return c->getBrightness(layer, x & 15, y, z & 15); -} - -void Level::setBrightness(const LightLayer& layer, int x, int y, int z, int brightness) { - //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { - // return; - //} - if (y < 0) return; - if (y >= DEPTH) return; - if (!hasChunk(x >> 4, z >> 4)) return; - LevelChunk* c = getChunk(x >> 4, z >> 4); - c->setBrightness(layer, x & 15, y, z & 15, brightness); - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->tileBrightnessChanged(x, y, z); - } -} - -float Level::getBrightness(int x, int y, int z) { - return dimension->brightnessRamp[getRawBrightness(x, y, z)]; -} - -bool Level::isDay() { - return this->skyDarken < 4; -} - -//HitResult Level::clip(const Vec3& a, const Vec3& b) { -// return clip(a, b, false); -//} - -HitResult Level::clip(const Vec3& A, const Vec3& b, bool liquid /*= false*/, bool solidOnly /*= false*/) { - static Stopwatch sw; - //sw.printEvery(1000, "clip"); - SwStartStopper w(sw); - - if (A.x != A.x || A.y != A.y || A.z != A.z) return HitResult(); //@kludge This is actually a way to do it - if (b.x != b.x || b.y != b.y || b.z != b.z) return HitResult(); - - Vec3 a(A); - - int xTile1 = Mth::floor(b.x); - int yTile1 = Mth::floor(b.y); - int zTile1 = Mth::floor(b.z); - - int xTile0 = Mth::floor(a.x); - int yTile0 = Mth::floor(a.y); - int zTile0 = Mth::floor(a.z); - - int maxIterations = 200; - while (maxIterations-- >= 0) { - if (a.x != a.x || a.y != a.y || a.z != a.z) - return HitResult(); - if (xTile0 == xTile1 && yTile0 == yTile1 && zTile0 == zTile1) - return HitResult(); - - float xClip = 999; - float yClip = 999; - float zClip = 999; - - if (xTile1 > xTile0) xClip = xTile0 + 1.000f; - if (xTile1 < xTile0) xClip = xTile0 + 0.000f; - - if (yTile1 > yTile0) yClip = yTile0 + 1.000f; - if (yTile1 < yTile0) yClip = yTile0 + 0.000f; - - if (zTile1 > zTile0) zClip = zTile0 + 1.000f; - if (zTile1 < zTile0) zClip = zTile0 + 0.000f; - - float xDist = 999; - float yDist = 999; - float zDist = 999; - - float xd = b.x - a.x; - float yd = b.y - a.y; - float zd = b.z - a.z; - - if (xClip != 999) xDist = (xClip - a.x) / xd; - if (yClip != 999) yDist = (yClip - a.y) / yd; - if (zClip != 999) zDist = (zClip - a.z) / zd; - - int face = 0; - if (xDist < yDist && xDist < zDist) { - if (xTile1 > xTile0) face = 4; - else face = 5; - - a.x = xClip; - a.y += yd * xDist; - a.z += zd * xDist; - } else if (yDist < zDist) { - if (yTile1 > yTile0) face = 0; - else face = 1; - - a.x += xd * yDist; - a.y = yClip; - a.z += zd * yDist; - } else { - if (zTile1 > zTile0) face = 2; - else face = 3; - - a.x += xd * zDist; - a.y += yd * zDist; - a.z = zClip; - } - - Vec3 tPos(a.x, a.y, a.z); - xTile0 = (int) (tPos.x = (float)Mth::floor(a.x)); - if (face == 5) { - xTile0--; - tPos.x++; - } - yTile0 = (int) (tPos.y = (float)Mth::floor(a.y)); - if (face == 1) { - yTile0--; - tPos.y++; - } - zTile0 = (int) (tPos.z = (float)Mth::floor(a.z)); - if (face == 3) { - zTile0--; - tPos.z++; - } - - int t = getTile(xTile0, yTile0, zTile0); - int data = getData(xTile0, yTile0, zTile0); - Tile* tile = Tile::tiles[t]; - - if (solidOnly && tile != NULL && tile->getAABB(this, xTile0, yTile0, zTile0) == NULL) { - // No collision - } else if (t > 0 && tile->mayPick(data, liquid)) { - if(xTile0 >= 0 && zTile0 >= 0 && xTile0 < LEVEL_WIDTH && zTile0 < LEVEL_WIDTH) { - HitResult r = tile->clip(this, xTile0, yTile0, zTile0, a, b); - if (r.isHit()) return r; - } - } - } - return HitResult(); -} - -void Level::playSound(Entity* entity, const std::string& name, float volume, float pitch) { - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->playSound(name, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); - } -} - -void Level::playSound(float x, float y, float z, const std::string& name, float volume, float pitch) { - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->playSound(name, x, y, z, volume, pitch); - } -} - -void Level::levelEvent(Player* source, int type, int x, int y, int z, int data) { - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->levelEvent(source, type, x, y, z, data); - } -} - -void Level::tileEvent(int x, int y, int z, int b0, int b1) { - int t = getTile(x, y, z); - if (t > 0) Tile::tiles[t]->triggerEvent(this, x, y, z, b0, b1); - - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->tileEvent(x, y, z, b0, b1); - } -} - -// -// void playStreamingMusic(String name, int x, int y, int z) { -// for (unsigned int i = 0; i < listeners.size(); i++) { -// listeners.get(i).playStreamingMusic(name, x, y, z); -// } -// } -// -// void playMusic(float x, float y, float z, String string, float volume) { -// } -// - -void Level::addParticle(const std::string& id, float x, float y, float z, float xd, float yd, float zd, int data /* = 0 */) { - for (unsigned int i = 0; i < _listeners.size(); i++) - _listeners[i]->addParticle(id, x, y, z, xd, yd, zd, data); -} - -void Level::addParticle(ParticleType::Id id, float x, float y, float z, float xd, float yd, float zd, int data /* = 0 */) { - for (unsigned int i = 0; i < _listeners.size(); i++) - _listeners[i]->addParticle(id, x, y, z, xd, yd, zd, data); -} - -bool Level::addEntity(Entity* e) { - Entity* prev = getEntity(e->entityId); - if (prev) - removeEntity(prev); - - int xc = Mth::floor(e->x / 16.f); - int zc = Mth::floor(e->z / 16.f); - - //bool forced = false; - //if (e->isPlayer()) { - // forced = true; - //} - bool forced = true; - - if (forced/* || hasChunk(xc, zc)*/) { - if (e->isPlayer() && std::find(players.begin(), players.end(), e) == players.end()) { - players.push_back( (Player*) e ); - } - getChunk(xc, zc)->addEntity(e); - entities.push_back(e); - entityIdLookup[e->entityId] = e; - entityAdded(e); - return true; - } - - return false; -} - -Entity* Level::getEntity(int entityId) -{ - // TODO: Lookup map - /*for (unsigned int i = 0; i < entities.size(); i++) - { - if (entities[i]->entityId == entityId) - { - return entities[i]; - } - } - return NULL;*/ - EntityMap::const_iterator cit = entityIdLookup.find(entityId); - return (cit != entityIdLookup.end())? cit->second : NULL; -} - -/*protected*/ -void Level::entityAdded(Entity* e) { - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->entityAdded(e); - } -} - -/*protected*/ -void Level::entityRemoved(Entity* e) { - for (unsigned int j = 0; j < _listeners.size(); j++) { - _listeners[j]->entityRemoved(e); - } -} - -Mob* Level::getMob(int entityId) -{ - Entity* entity = getEntity(entityId); - return (entity && entity->isMob())? (Mob*)entity : NULL; -} - -void Level::removeEntity(Entity* e) { - e->remove(); - if (e->isPlayer() && e->reallyRemoveIfPlayer) { - Util::remove(players, (Player*) e); - } -} - -void Level::tileEntityChanged(int x, int y, int z, TileEntity* te) { - if (this->hasChunkAt(x, y, z)) { - getChunkAt(x, z)->markUnsaved(); - } - for (unsigned int i = 0; i < _listeners.size(); i++) { - _listeners[i]->tileEntityChanged(x, y, z, te); - } -} - - -//void Level::removeEntityImmediately(Entity* e) { -// e->remove(); -// -// if (e->isPlayer()) { -// Util::remove(players, (Player*)e); -// } -// -// int xc = e->xChunk; -// int zc = e->zChunk; -// if (e->inChunk && hasChunk(xc, zc)) { -// getChunk(xc, zc)->removeEntity(e); -// } -// -// Util::remove(entities, e); -//} - -Biome::MobSpawnerData Level::getRandomMobSpawnAt(const MobCategory& mobCategory, int x, int y, int z) { - Biome::MobList mobList = _chunkSource->getMobsAt(mobCategory, x, y, z); - if (mobList.empty()) return Biome::MobSpawnerData(); - - Biome::MobSpawnerData* data = (Biome::MobSpawnerData*) WeighedRandom::getRandomItem(&random, mobList); - if (!data) - return Biome::MobSpawnerData(); - return *data; -} - -void Level::addListener(LevelListener* listener) { - _listeners.push_back(listener); -} - -void Level::removeListener(LevelListener* listener) { - ListenerList::iterator it = std::find(_listeners.begin(), _listeners.end(), listener); - _listeners.erase(it); -} - -std::vector& Level::getCubes(const Entity* source, const AABB& box_) { //@attn: check the AABB* new/delete stuff - boxes.clear(); - const AABB* box = &box_; - int x0 = Mth::floor(box->x0); - int x1 = Mth::floor(box->x1 + 1); - int y0 = Mth::floor(box->y0); - int y1 = Mth::floor(box->y1 + 1); - int z0 = Mth::floor(box->z0); - int z1 = Mth::floor(box->z1 + 1); - - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - if (hasChunkAt(x, Level::DEPTH / 2, z)) { - for (int y = y0 - 1; y < y1; y++) { - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL) { - tile->addAABBs(this, x, y, z, box, boxes); - } - } - } - else - { - //int breakPoint = 0; - } - } - /* - float r = 0.25; - List ee = getEntities(source, box.grow(r, r, r)); - for (int i = 0; i < ee.size(); i++) { - AABB collideBox = ee.get(i).getCollideBox(); - if (collideBox != NULL && collideBox.intersects(box)) { - boxes.add(collideBox); - } - - collideBox = source.getCollideAgainstBox(ee.get(i)); - if (collideBox != NULL && collideBox.intersects(box)) { - boxes.add(collideBox); - } - } - */ - - return boxes; -} - -int Level::getSkyDarken(float a) { - float td = getTimeOfDay(a); - - float br = 1 - (Mth::cos(td * Mth::PI * 2) * 2 + 0.5f); - if (br < 0.0f) br = 0.0f; - if (br > 0.80f) br = 0.80f; //@note; was 1.0f - return ((int) (br * 11)); -} - -Vec3 Level::getSkyColor(Entity* source, float a) { - float td = getTimeOfDay(a); - - float br = Mth::cos(td * Mth::PI * 2) * 2 + 0.5f; - if (br < 0.0f) br = 0.0f; - if (br > 0.75f) br = 0.75f; //@note; was 1.0f - -// int xx = Mth::floor(source->x); -// int zz = Mth::floor(source->z); -// float temp = 0.5;//(float) getBiomeSource().getTemperature(xx, zz); - int skyColor = 0x3070ff;//getBiomeSource().getBiome(xx, zz).getSkyColor(temp); - - float r = ((skyColor >> 16) & 0xff) / 255.0f; - float g = ((skyColor >> 8) & 0xff) / 255.0f; - float b = ((skyColor) & 0xff) / 255.0f; - r *= br; - g *= br; - b *= br; - - return Vec3(r, g, b); -} - -Vec3 Level::getCloudColor( float a ) { - float td = getTimeOfDay(a); - - float br = Mth::cos(td * Mth::PI * 2) * 2.0f + 0.5f; - if (br < 0.0f) br = 0.0f; - if (br > 1.0f) br = 1.0f; - long cloudColor = 0xffffff; - float r = ((cloudColor >> 16) & 0xff) / 255.0f; - float g = ((cloudColor >> 8) & 0xff) / 255.0f; - float b = ((cloudColor) & 0xff) / 255.0f; - - float rainLevel = 0;//getRainLevel(a); - if (rainLevel > 0) { - float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.6f; - - float ba = 1 - rainLevel * 0.95f; - r = r * ba + mid * (1 - ba); - g = g * ba + mid * (1 - ba); - b = b * ba + mid * (1 - ba); - } - - r *= br * 0.90f + 0.10f; - g *= br * 0.90f + 0.10f; - b *= br * 0.85f + 0.15f; - - float thunderLevel = 0; //getThunderLevel(a); - if (thunderLevel > 0) { - float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.2f; - - float ba = 1 - thunderLevel * 0.95f; - r = r * ba + mid * (1 - ba); - g = g * ba + mid * (1 - ba); - b = b * ba + mid * (1 - ba); - } - - return Vec3(r, g, b); -} - -float Level::getTimeOfDay(float a) { - return dimension->getTimeOfDay(levelData.getTime(), a); - //int time = 20 * levelData.getTime(); - //float out = dimension->getTimeOfDay(time, a); - //LOGI("getTime: %d, dayTime: %f\n", time, out); - //return out; -} - -float Level::getSunAngle(float a) { - float td = getTimeOfDay(a); - return td * Mth::PI * 2; -} - -//Vec3 Level::getCloudColor(float a) { -// float td = getTimeOfDay(a); -// -// float br = Mth::cos(td * Mth::PI * 2) * 2.0f + 0.5f; -// if (br < 0.f) br = 0; -// if (br > 1.f) br = 1; -// -// float r = ((cloudColor >> 16) & 0xff) / 255.0f; -// float g = ((cloudColor >> 8) & 0xff) / 255.0f; -// float b = ((cloudColor) & 0xff) / 255.0f; -// -// r *= br * 0.90f + 0.10f; -// g *= br * 0.90f + 0.10f; -// b *= br * 0.85f + 0.15f; -// -// return Vec3(r, g, b); -//} - -Vec3 Level::getFogColor(float a) { - float td = getTimeOfDay(a); - return dimension->getFogColor(td, a); -} - -int Level::getTopSolidBlock(int x, int z) { - LevelChunk* levelChunk = getChunkAt(x, z); - - int y = Level::DEPTH - 1; - - while (getMaterial(x, y, z)->blocksMotion() && y > 0) { - y--; - } - - x &= 15; - z &= 15; - - while (y > 0) { - int t = levelChunk->getTile(x, y, z); - if (t == 0 /*|| !(Tile::tiles[t]->material->blocksMotion() || Tile::tiles[t]->material->isLiquid())*/ - || !(Tile::tiles[t]->material->blocksMotion()) - || Tile::tiles[t]->material == Material::leaves) { - y--; - } else { - return y + 1; - } - } - return -1; -} - -int Level::getLightDepth(int x, int z) { - return getChunkAt(x, z)->getHeightmap(x & 15, z & 15); -} - -float Level::getStarBrightness(float a) { - float td = getTimeOfDay(a); - - float br = 1 - (Mth::cos(td * Mth::PI * 2) * 2 + 0.75f); - if (br < 0.f) br = 0; - if (br > 1.f) br = 1; - - return br * br * 0.5f; -} - -void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay) { - TickNextTickData td(x, y, z, tileId); - int r = 8; - if (instaTick) { - if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r, td.z + r)) { - int id = getTile(td.x, td.y, td.z); - if (id == td.tileId && id > 0) { - Tile::tiles[id]->tick(this, td.x, td.y, td.z, &random); - } - } - return; - } - - if (hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { - if (tileId > 0) { - td.setDelay(tickDelay + levelData.getTime()); - } - if (_tickNextTickSet.find(td) == _tickNextTickSet.end()) { - _tickNextTickSet.insert(td); - } - } -} - -void Level::tickEntities() { - TIMER_PUSH("entities"); - - TIMER_PUSH("remove"); - //Util::removeAll(entities, _entitiesToRemove); - // for (int j = 0; j < (int)_entitiesToRemove.size(); j++) { - // Entity* e = _entitiesToRemove[j]; - // int xc = e->xChunk; - // int zc = e->zChunk; - // if (e->inChunk && hasChunk(xc, zc)) { - // getChunk(xc, zc)->removeEntity(e); - // } - // } - // for (int j = 0; j < (int)_entitiesToRemove.size(); j++) { - // entityRemoved(_entitiesToRemove[j]); - // //LOGI("a1 &e@delt: %p", _entitiesToRemove[j]); - // delete _entitiesToRemove[j]; - // //LOGI("a2"); - // } - // _entitiesToRemove.clear(); - - EntityList pendingRemovedEntities; - std::vector zombies; - - TIMER_POP_PUSH("regular"); - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - - if (!e->removed) { - tick(e); - if (e->getEntityTypeId() == MobTypes::Zombie) { - zombies.push_back((Zombie*)e); - ((Zombie*)e)->setUseNewAi(false); // @note: this is set under - } - } - - TIMER_PUSH("remove"); - if (e->removed && (!e->isPlayer() || e->reallyRemoveIfPlayer)) { - int xc = e->xChunk; - int zc = e->zChunk; - if (e->inChunk && hasChunk(xc, zc)) { - getChunk(xc, zc)->removeEntity(e); - } - entityIdLookup.erase(e->entityId); - entities.erase(entities.begin() + (i--)); - entityRemoved(e); - pendingRemovedEntities.push_back(e); - } - TIMER_POP(); - } - - TIMER_POP_PUSH("remove"); - for (unsigned int i = 0; i < pendingRemovedEntities.size(); ++i) { - Entity* e = pendingRemovedEntities[i]; - //if (!e->isPlayer()) // @todo: remove fast as heck - if (e->isPlayer()) - _pendingPlayerRemovals.push_back( PRInfo(e, 16) ); - else - delete e; - - } pendingRemovedEntities.clear(); - - // Yes, I know this is bad, but it's extremely few players - // to remove anyway. - for (int i = (int)_pendingPlayerRemovals.size()-1; i >= 0; --i) { - PRInfo& pr = _pendingPlayerRemovals[i]; - if (--pr.ticks <= 0) { - LOGI("deleting: %p\n", pr.e); - delete pr.e; - _pendingPlayerRemovals.erase(_pendingPlayerRemovals.begin() + i); - } - } - - //setZombieAi(zombies); - - TIMER_POP_PUSH("tileEntities"); - updatingTileEntities = true; - //LOGI("num tile entities %d\n", tileEntities.size()); - for (unsigned int i = 0; i < tileEntities.size(); ++i) { - TileEntity* te = tileEntities[i]; - if (!te->isRemoved() && te->level != NULL) { - if (hasChunkAt(te->x, te->y, te->z)) { - te->tick(); - } - } - - if (/*te->isFinished() || */te->isRemoved()) { - - for (int j = 0; j < 10; ++j) - LOGI("REmoved tile-entity @ %d, %d, %d\n", te->x, te->y, te->z); - - tileEntities.erase(tileEntities.begin() + (i--)); - - if (hasChunk(te->x >> 4, te->z >> 4)) { - LevelChunk* lc = getChunk(te->x >> 4, te->z >> 4); - if (lc != NULL) { - lc->removeTileEntity(te->x & 15, te->y, te->z & 15); - } - } - delete te; - } - } - updatingTileEntities = false; - - TIMER_POP_PUSH("pendingTileEntities"); - if (!pendingTileEntities.empty()) { - for (unsigned int i = 0; i < pendingTileEntities.size(); ++i) { - TileEntity* e = pendingTileEntities[i]; - if (!e->isRemoved()) { - bool found = false; - for (unsigned int j = 0; j < tileEntities.size(); ++j) { - if (tileEntities[j] == e) { - found = true; - break; - } - } - int xx = e->x, yy = e->y, zz = e->z; - - LevelChunk* lc = getChunk(xx >> 4, zz >> 4); - bool has = lc && lc->hasTileEntityAt(e); - if (!found) { - if (!has) tileEntities.push_back(e); - else { - delete e; - e = NULL; - } - } - - if (e && lc) lc->setTileEntity(xx & 15, yy, zz & 15, e); - sendTileUpdated(xx, yy, zz); - } - } - pendingTileEntities.clear(); - } - - - TIMER_POP(); - TIMER_POP(); -} - -class DistanceEntitySorter { - Vec3 c; -public: - DistanceEntitySorter(float x, float y, float z) : c(x, y, z) {} - bool operator() (const Entity* c0, const Entity* c1) { - const float d0 = c.distanceToSqr(c0->x, c0->y, c0->z); - const float d1 = c.distanceToSqr(c1->x, c1->y, c1->z); - return d0 < d1; - } -}; - -void Level::setZombieAi(std::vector& zombies) { - unsigned int size = zombies.size(); - const int NumSmartZombiesPerPlayer = 0; - if (size <= NumSmartZombiesPerPlayer) { - for (unsigned int i = 0; i < size; ++i) - zombies[i]->setUseNewAi(true); - return; - } - - for (unsigned int i = 0; i < players.size(); ++i) { - Player* p = players[i]; - DistanceEntitySorter sorter(p->x, p->y, p->z); - std::nth_element(zombies.begin(), zombies.begin() + NumSmartZombiesPerPlayer, zombies.end(), sorter); - for (int j = 0; j < NumSmartZombiesPerPlayer; ++j) - if (zombies[j]->distanceToSqr(p) < 32*32) - zombies[j]->setUseNewAi(true); - } -} - -void Level::tick(Entity* e) { - tick(e, true); -} - -void Level::tick(Entity* e, bool actual) { - int xc = Mth::floor(e->x); - int zc = Mth::floor(e->z); - int r = 32; - if (actual && !hasChunksAt(xc - r, 0, zc - r, xc + r, 128, zc + r)) { - return; - } - - e->xOld = e->x; - e->yOld = e->y; - e->zOld = e->z; - e->yRotO = e->yRot; - e->xRotO = e->xRot; - - if (actual && e->inChunk) { - e->tick(); - } - - TIMER_PUSH("chunkCheck"); - // SANITY!! - if (e->x != e->x) e->x = e->xOld; // @note: checking for NaN, not sure about Infinite - if (e->y != e->y) e->y = e->yOld; - if (e->z != e->z) e->z = e->zOld; - if (e->xRot != e->xRot) e->xRot = e->xRotO; - if (e->yRot != e->yRot) e->yRot = e->yRotO; - - int xcn = Mth::floor(e->x / 16.0f); - int ycn = Mth::floor(e->y / 16.0f); - int zcn = Mth::floor(e->z / 16.0f); - - if (!e->inChunk || (e->xChunk != xcn || e->yChunk != ycn || e->zChunk != zcn)) { - if (e->inChunk && hasChunk(e->xChunk, e->zChunk)) { - getChunk(e->xChunk, e->zChunk)->removeEntity(e, e->yChunk); - } - - if (hasChunk(xcn, zcn)) { - e->inChunk = true; - getChunk(xcn, zcn)->addEntity(e); - } else { - e->inChunk = false; - } - } - TIMER_POP(); - - // Save player info every n:th second - const float now = getTimeS(); - if (now - _lastSavedPlayerTime >= 30) { - saveLevelData(); - _lastSavedPlayerTime = now; - } -} - -bool Level::isUnobstructed(const AABB& aabb) { - EntityList& entities = getEntities(NULL, aabb); - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - if (!e->removed && e->blocksBuilding) return false; - } - return true; -} - -bool Level::containsAnyLiquid(const AABB& box) { - int x0 = Mth::floor(box.x0); - int x1 = Mth::floor(box.x1 + 1); - int y0 = Mth::floor(box.y0); - int y1 = Mth::floor(box.y1 + 1); - int z0 = Mth::floor(box.z0); - int z1 = Mth::floor(box.z1 + 1); - - if (box.x0 < 0) x0--; - if (box.y0 < 0) y0--; - if (box.z0 < 0) z0--; - - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) - for (int z = z0; z < z1; z++) { - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL && tile->material->isLiquid()) { - return true; - } - } - return false; -} - -bool Level::containsFireTile(const AABB& box) { - int x0 = Mth::floor(box.x0); - int x1 = Mth::floor(box.x1 + 1); - int y0 = Mth::floor(box.y0); - int y1 = Mth::floor(box.y1 + 1); - int z0 = Mth::floor(box.z0); - int z1 = Mth::floor(box.z1 + 1); - - if (hasChunksAt(x0, y0, z0, x1, y1, z1)) { - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) - for (int z = z0; z < z1; z++) { - int t = getTile(x, y, z); - - if (/*t == ((Tile*)(Tile::fire))->id - ||*/ t == Tile::lava->id - || t == Tile::calmLava->id) { - return true; - } - } - } - return false; -} - -bool Level::containsMaterial(const AABB& box, const Material* material) { - int x0 = Mth::floor(box.x0); - int x1 = Mth::floor(box.x1 + 1); - int y0 = Mth::floor(box.y0); - int y1 = Mth::floor(box.y1 + 1); - int z0 = Mth::floor(box.z0); - int z1 = Mth::floor(box.z1 + 1); - - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) - for (int z = z0; z < z1; z++) { - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL && tile->material == material) { - return true; - } - } - return false; -} - -bool Level::containsLiquid(const AABB& box, const Material* material) { - int x0 = Mth::floor(box.x0); - int x1 = Mth::floor(box.x1 + 1); - int y0 = Mth::floor(box.y0); - int y1 = Mth::floor(box.y1 + 1); - int z0 = Mth::floor(box.z0); - int z1 = Mth::floor(box.z1 + 1); - - for (int x = x0; x < x1; x++) - for (int y = y0; y < y1; y++) - for (int z = z0; z < z1; z++) { - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL && tile->material == material) { - int data = getData(x, y, z); - float yh1 = (float)(y + 1); - if (data < 8) { - yh1 = (float)y + 1.0f - (float)data / 8.0f; - } - if (yh1 >= box.y0) { - return true; - } - } - } - return false; -} - -/* in java, this returns an Explosion */ -void Level::explode(Entity* source, float x, float y, float z, float r) { - explode(source, x, y, z, r, false); -} - -/* in java, this returns an Explosion */ -void Level::explode(Entity* source, float x, float y, float z, float r, bool fire) { - if (!isClientSide) { - Explosion explosion(this, source, x, y, z, r); - explosion.fire = fire; - explosion.explode(); - explosion.finalizeExplosion(); - ExplodePacket packet(x, y, z, r, explosion.toBlow); - raknetInstance->send(packet); - } -} - -float Level::getSeenPercent(const Vec3& center, const AABB& bb) { - float xs = 1.0f / ((bb.x1 - bb.x0) * 2 + 1); - float ys = 1.0f / ((bb.y1 - bb.y0) * 2 + 1); - float zs = 1.0f / ((bb.z1 - bb.z0) * 2 + 1); - int hits = 0; - int count = 0; - for (float xx = 0; xx <= 1; xx += xs) - for (float yy = 0; yy <= 1; yy += ys) - for (float zz = 0; zz <= 1; zz += zs) { - float x = bb.x0 + (bb.x1 - bb.x0) * xx; - float y = bb.y0 + (bb.y1 - bb.y0) * yy; - float z = bb.z0 + (bb.z1 - bb.z0) * zz; - if (!clip(Vec3(x, y, z), center).isHit()) hits++; - count++; - } - - return hits / (float) count; -} - -bool Level::isSolidBlockingTile(int x, int y, int z) -{ - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; - return tile->material->isSolidBlocking() && tile->isCubeShaped(); -} - -bool Level::isSolidRenderTile(int x, int y, int z) { - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; - return tile->isSolidRender(); -} - -void Level::extinguishFire(int x, int y, int z, int face) { - switch (face) { - case Facing::DOWN : y--; break; - case Facing::UP : y++; break; - case Facing::NORTH: z--; break; - case Facing::SOUTH: z++; break; - case Facing::WEST : x--; break; - case Facing::EAST : x++; break; - } - - if (getTile(x, y, z) == ((Tile*)Tile::fire)->id) { - //playSound(x + 0.5f, y + 0.5f, z + 0.5f, "random.fizz", 0.5f, 2.6f + (random.nextFloat() - random.nextFloat()) * 0.8f); - setTile(x, y, z, 0); - } -} -// String gatherStats() { -// return "All: " + this.entities.size(); -// } -// -// String gatherChunkSourceStats() { -// return chunkSource.gatherStats(); -// } -// -TileEntity* Level::getTileEntity(int x, int y, int z) { - LevelChunk* lc = getChunk(x >> 4, z >> 4); - if (!lc) return NULL; - - if (TileEntity* tileEntity = lc->getTileEntity(x & 15, y, z & 15)) - return tileEntity; - - for (unsigned int i = 0; i < pendingTileEntities.size(); ++i) { - TileEntity* e = pendingTileEntities[i]; - if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) - return e; - } - return NULL; -} - -void Level::setTileEntity(int x, int y, int z, TileEntity* tileEntity) { - if (!tileEntity || tileEntity->isRemoved()) - return; - - if (updatingTileEntities) { - tileEntity->x = x; - tileEntity->y = y; - tileEntity->z = z; - pendingTileEntities.push_back(tileEntity); - } else { - tileEntities.push_back(tileEntity); - - LevelChunk* lc = getChunk(x >> 4, z >> 4); - if (lc != NULL) lc->setTileEntity(x & 15, y, z & 15, tileEntity); - } -} - -void Level::removeTileEntity(int x, int y, int z) { - TileEntity* te = getTileEntity(x, y, z); - if (te && updatingTileEntities) { - te->setRemoved(); - Util::remove(pendingTileEntities, te); - } else { - LevelChunk* lc = getChunk(x >> 4, z >> 4); - if (lc) lc->removeTileEntity(x & 15, y, z & 15); - - if (te) { - Util::remove(pendingTileEntities, te); - Util::remove(tileEntities, te); - delete te; - } - } -} - - -// -// void forceSave(ProgressListener progressListener) { -// save(true, progressListener); -// } -// - -int Level::getLightsToUpdate() { - return _lightUpdates.size(); -} - -bool Level::updateLights() { - if (_maxRecurse >= 50) { - return false; - } - //static int _MaxSize = 0; - _maxRecurse++; - //try { - int max = 500; - while ((int)_lightUpdates.size() > 0) { - if (--max <= 0) - { - _maxRecurse--; - return true; - } - LightUpdate l = _lightUpdates.back(); - _lightUpdates.pop_back(); - l.update(this); - //if ((int)_lightUpdates.size() > _MaxSize) - //{ - // LOGI("MAX_updsize_light: %d (%d)\n", _lightUpdates.size(), _MaxSize); - // _MaxSize = _lightUpdates.size(); - //} - } - _maxRecurse--; - return false; - //} finally { - //maxRecurse--; - //} -} - -void Level::setUpdateLights(bool doUpdate) { - _updateLights = doUpdate; -} - -void Level::updateLight(const LightLayer& layer, int x0, int y0, int z0, int x1, int y1, int z1) { - updateLight(layer, x0, y0, z0, x1, y1, z1, true); -} - -static int maxLoop = 0; - -void Level::updateLight(const LightLayer& layer, int x0, int y0, int z0, int x1, int y1, int z1, bool join) { - if ((dimension->hasCeiling && &layer == &LightLayer::Sky) || !_updateLights) return; - - maxLoop++; - //if (x0 < -5 || z0 < -5) LOGI("x, z: %d, %d\n", x0, z0); - if (maxLoop == 50) { - maxLoop--; - return; - } - int xm = (x1 + x0) / 2; - int zm = (z1 + z0) / 2; - if (!hasChunkAt(xm, Level::DEPTH / 2, zm)) { - maxLoop--; - return; - } - if (getChunkAt(xm, zm)->isEmpty()) - { - maxLoop--; - return; - } - int count = _lightUpdates.size(); - if (join) { - int toCheck = 5; - if (toCheck > count) toCheck = count; - for (int i = 0; i < toCheck; i++) { - LightUpdate& last = _lightUpdates[_lightUpdates.size() - i - 1]; - if (last.layer == &layer && last.expandToContain(x0, y0, z0, x1, y1, z1)) { - maxLoop--; - return; - } - } - } - _lightUpdates.push_back(LightUpdate(layer, x0, y0, z0, x1, y1, z1)); - int max = 1000000; - if ((int)_lightUpdates.size() > max) { - LOGI("More than %d updates, aborting lighting updates\n", max); - _lightUpdates.clear(); - } - maxLoop--; -} -// -// // int xxo, yyo, zzo; -// -bool Level::updateSkyBrightness() { - int newDark = this->getSkyDarken(1); - if (newDark != skyDarken) { - skyDarken = newDark; - return true; - } - return false; -} - -void Level::setSpawnSettings(bool spawnEnemies, bool spawnFriendlies) { - //this->spawnEnemies = spawnEnemies; - //this->spawnFriendlies = spawnFriendlies; -} - -void Level::animateTick(int xt, int yt, int zt) { - int r = 16; - Random animateRandom; - - for (int i = 0; i < 100; i++) { - int x = xt + random.nextInt(r) - random.nextInt(r); - int y = yt + random.nextInt(r) - random.nextInt(r); - int z = zt + random.nextInt(r) - random.nextInt(r); - int t = getTile(x, y, z); - if (t > 0) { - Tile::tiles[t]->animateTick(this, x, y, z, &animateRandom); - } - } -} - -EntityList& Level::getEntities(Entity* except, const AABB& bb) { - _es.clear(); - int xc0 = Mth::floor((bb.x0 - 2) / 16); - int xc1 = Mth::floor((bb.x1 + 2) / 16); - int zc0 = Mth::floor((bb.z0 - 2) / 16); - int zc1 = Mth::floor((bb.z1 + 2) / 16); - for (int xc = xc0; xc <= xc1; xc++) - for (int zc = zc0; zc <= zc1; zc++) { - if (hasChunk(xc, zc)) { - getChunk(xc, zc)->getEntities(except, bb, _es); - } - } - return _es; -} - -// List getEntitiesOfClass(Class baseClass, AABB bb) { -// int xc0 = Mth.floor((bb.x0 - 2) / 16); -// int xc1 = Mth.floor((bb.x1 + 2) / 16); -// int zc0 = Mth.floor((bb.z0 - 2) / 16); -// int zc1 = Mth.floor((bb.z1 + 2) / 16); -// List es = new ArrayList(); -// for (int xc = xc0; xc <= xc1; xc++) -// for (int zc = zc0; zc <= zc1; zc++) { -// if (hasChunk(xc, zc)) { -// getChunk(xc, zc).getEntitiesOfClass(baseClass, bb, es); -// } -// } -// return es; -// } - -const EntityList& Level::getAllEntities() { - return entities; -} - -// int countInstanceOf(Class clas) { -// int count = 0; -// for (int i = 0; i < entities.size(); i++) { -// Entity e = entities.get(i); -// if (clas.isAssignableFrom(e.getClass())) count++; -// } -// return count; -// } -// -/* -void Level::addEntities(const EntityList& list) { - entities.insert(entities.end(), list.begin(), list.end()); - for (int j = 0; j < (int)list.size(); j++) { - entityAdded(list[j]); - } -} -*/ - -//void Level::removeEntities(const EntityList& list) { -// _entitiesToRemove.insert(_entitiesToRemove.end(), list.begin(), list.end()); -//} - -void Level::prepare() { - while (_chunkSource->tick()) - ; -} - -bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities,unsigned char face) { - int targetType = getTile(x, y, z); - const Tile* targetTile = Tile::tiles[targetType]; - Tile* tile = Tile::tiles[tileId]; - - AABB* aabb = tile->getAABB(this, x, y, z); - if (ignoreEntities) aabb = NULL; - if (aabb != NULL && !isUnobstructed(*aabb)) return false; - if (targetTile == Tile::water || targetTile == Tile::calmWater || targetTile == Tile::lava || targetTile == Tile::calmLava || targetTile == (Tile*)(Tile::fire) || targetTile == Tile::topSnow) targetTile = NULL; - if (tileId > 0 && targetTile == NULL) { - if (tile->mayPlace(this, x, y, z, face)) { - return true; - } - } - - return false; -} - -int Level::getSeaLevel() { - return SEA_LEVEL; -} - -bool Level::getDirectSignal(int x, int y, int z, int dir) { - int t = getTile(x, y, z); - if (t == 0) return false; - return Tile::tiles[t]->getDirectSignal(this, x, y, z, dir); -} - -bool Level::hasDirectSignal(int x, int y, int z) { - if (getDirectSignal(x, y - 1, z, 0)) return true; - if (getDirectSignal(x, y + 1, z, 1)) return true; - if (getDirectSignal(x, y, z - 1, 2)) return true; - if (getDirectSignal(x, y, z + 1, 3)) return true; - if (getDirectSignal(x - 1, y, z, 4)) return true; - if (getDirectSignal(x + 1, y, z, 5)) return true; - return false; -} - -bool Level::getSignal(int x, int y, int z, int dir) { - if (isSolidBlockingTile(x, y, z)) { - return hasDirectSignal(x, y, z); - } - int t = getTile(x, y, z); - if (t == 0) return false; - return Tile::tiles[t]->getSignal(this, x, y, z, dir); -} - -bool Level::hasNeighborSignal(int x, int y, int z) { - if (getSignal(x, y - 1, z, 0)) return true; - if (getSignal(x, y + 1, z, 1)) return true; - if (getSignal(x, y, z - 1, 2)) return true; - if (getSignal(x, y, z + 1, 3)) return true; - if (getSignal(x - 1, y, z, 4)) return true; - if (getSignal(x + 1, y, z, 5)) return true; - return false; -} - -// void checkSession() { -// levelStorage.checkSession(); -// } -// -void Level::setTime(long time) { - this->levelData.setTime(time); -} - -long Level::getSeed() { - return levelData.getSeed(); -} - -long Level::getTime() { - return levelData.getTime(); -} - -Pos Level::getSharedSpawnPos() { - return Pos(levelData.getXSpawn(), levelData.getYSpawn(), levelData.getZSpawn()); -} - -void Level::setSpawnPos(Pos spawnPos) { - levelData.setSpawn(spawnPos.x, spawnPos.y, spawnPos.z); -} - -/* -void Level::ensureAdded(Entity* entity) { - int xc = Mth::floor(entity->x / 16); - int zc = Mth::floor(entity->z / 16); - int r = 2; - for (int x = xc - r; x <= xc + r; x++) { - for (int z = zc - r; z <= zc + r; z++) { - this->getChunk(x, z); - } - } - - if (std::find(entities.begin(), entities.end(), entity) == entities.end()) { - entities.push_back(entity); - } -} -*/ - -bool Level::mayInteract(Player* player, int xt, int yt, int zt) { - return true; -} - -void Level::broadcastEntityEvent(Entity* e, char eventId) { - if (isClientSide) return; - - EntityEventPacket packet(e->entityId, eventId); - raknetInstance->send(packet); -} - -/* -void Level::removeAllPendingEntityRemovals() { - //Util::removeAll(entities, _entitiesToRemove); - // //entities.removeAll(entitiesToRemove); - // for (int j = 0; j < (int)_entitiesToRemove.size(); j++) { - // Entity* e = _entitiesToRemove[j]; - // int xc = e->xChunk; - // int zc = e->zChunk; - // if (e->inChunk && hasChunk(xc, zc)) { - // getChunk(xc, zc)->removeEntity(e); - // } - // } - - // for (unsigned int j = 0; j < _entitiesToRemove.size(); j++) { - // entityRemoved(_entitiesToRemove[j]); - // } - // _entitiesToRemove.clear(); - - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - - if (e->removed) { - int xc = e->xChunk; - int zc = e->zChunk; - if (e->inChunk && hasChunk(xc, zc)) { - getChunk(xc, zc)->removeEntity(e); - } - entities.erase( entities.begin() + (i--) ); - entityRemoved(e); - } - } -} -*/ - -ChunkSource* Level::getChunkSource() { - return _chunkSource; -} - -// void tileEvent(int x, int y, int z, int b0, int b1) { -// int t = getTile(x, y, z); -// if (t > 0) Tile.tiles[t].triggerEvent(this, x, y, z, b0, b1); -// } - -LevelStorage* Level::getLevelStorage() { - return levelStorage; -} - -LevelData* Level::getLevelData() { - return &levelData; -} - -void Level::takePicture( TripodCamera* cam, Entity* e ) -{ - for (unsigned int i = 0; i < _listeners.size(); ++i) - _listeners[i]->takePicture(cam, e); -} - -int Level::getEntitiesOfType( int entityType, const AABB& bb, EntityList& list ) -{ - int xc0 = Mth::floor((bb.x0 - 2) / 16); - int xc1 = Mth::floor((bb.x1 + 2) / 16); - int zc0 = Mth::floor((bb.z0 - 2) / 16); - int zc1 = Mth::floor((bb.z1 + 2) / 16); - int count = -(int)list.size(); - for (int xc = xc0; xc <= xc1; xc++) - for (int zc = zc0; zc <= zc1; zc++) { - if (hasChunk(xc, zc)) { - getChunk(xc, zc)->getEntitiesOfType(entityType, bb, list); - } - } - return list.size() - count; -} - -int Level::getEntitiesOfClass( int type, const AABB& bb, EntityList& list ) { - int xc0 = Mth::floor((bb.x0 - 2) / 16); - int xc1 = Mth::floor((bb.x1 + 2) / 16); - int zc0 = Mth::floor((bb.z0 - 2) / 16); - int zc1 = Mth::floor((bb.z1 + 2) / 16); - int count = -(int)list.size(); - for (int xc = xc0; xc <= xc1; xc++) - for (int zc = zc0; zc <= zc1; zc++) { - if (hasChunk(xc, zc)) { - getChunk(xc, zc)->getEntitiesOfClass(type, bb, list); - } - } - return list.size() - count; -} - -int Level::countInstanceOfType( int typeId ) { - int n = 0; - for (unsigned int i = 0; i < entities.size(); ++i) - if (typeId == entities[i]->getEntityTypeId()) - ++n; - return n; -} - -int Level::countInstanceOfBaseType( int baseTypeId ) { - if (baseTypeId < MobTypes::BaseEnemy || baseTypeId > MobTypes::BaseWaterCreature) { - LOGE("Bad typeId sent to Level::countInstanceOf. Note that only Base types (MobTypes::Base*) are supported for now.\n"); - return -1; - } - - int n = 0; - for (unsigned int i = 0; i < entities.size(); ++i) - if (baseTypeId == entities[i]->getCreatureBaseType()) - ++n; - return n; -} - -void Level::dispatchEntityData( Entity* e ) -{ - if (isClientSide) return; - _pendingEntityData.insert(std::make_pair(e->entityId, e)); -} - -void Level::saveGame() -{ - if (levelStorage) { - levelStorage->saveGame(this); - saveLevelData(); - } -} - -void Level::loadEntities() -{ - if (levelStorage) - levelStorage->loadEntities(this, NULL); -} - -void Level::updateSkyDarken() -{ - if (updateSkyBrightness()) - for (unsigned i = 0; i < _listeners.size(); i++) { - _listeners[i]->skyColorChanged(); - } -} - -void Level::removePlayer( Player* player ) -{ - for (unsigned int i = 0; i < players.size(); ++i) - if (players[i] == player) { - players.erase( players.begin() + i ); - } -} - -int Level::isNightMode() { - return _nightMode; -} - -void Level::setNightMode( bool isNightMode ) { - _nightMode = isNightMode; -} - -bool Level::inRange( int x, int y, int z ) { - return x >= 0 && x < LEVEL_WIDTH - && y >= 0 && y < LEVEL_HEIGHT - && z >= 0 && z < LEVEL_DEPTH; -} - -// -// AdventureSettings -// -AdventureSettings::AdventureSettings() -: doTickTime(true), - noPvP(false), - noPvM(false), - noMvP(false), - immutableWorld(false), - showNameTags(true) -{ -} +#include "Level.hpp" +#include "LevelListener.hpp" +#include "tile/entity/TileEntity.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/EntityEvent.hpp" + +#include "biome/BiomeSource.hpp" +#include "chunk/storage/ChunkStorage.hpp" +#include "chunk/ChunkCache.hpp" +#include "storage/LevelStorage.hpp" +#include "Region.hpp" +#include "Explosion.hpp" +#include "LevelConstants.hpp" +#include "pathfinder/PathFinder.hpp" + +#include "world/Facing.hpp" +#include "util/PerfTimer.hpp" + +#include "tile/LiquidTile.hpp" + +#include "biome/Biome.hpp" +#include "MobSpawner.hpp" +#include "network/packet/SetEntityDataPacket.hpp" +#include "network/RakNetInstance.hpp" +#include "network/packet/EntityEventPacket.hpp" +#include "network/packet/SetTimePacket.hpp" +#include "world/entity/monster/Zombie.hpp" +#include "world/inventory/BaseContainerMenu.hpp" +#include "world/Difficulty.hpp" +#include "network/packet/ExplodePacket.hpp" + +Level::Level(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */) +: levelStorage(levelStorage), + isClientSide(false), + isFindingSpawn(false), + noNeighborUpdate(false), + skyDarken(0), + instaTick(false), + random(1), + _isNew(false), + _chunkSource(NULL), + _randValue(42184323), + _addend(1013904223), + _maxRecurse(0), + _updateLights(true), + _pathFinder(NULL), + _spawnFriendlies(true), + _spawnEnemies(true), + _lastSavedPlayerTime(0), // @attn: @time: clock starts on 0 now, change if not + raknetInstance(0), + updatingTileEntities(false), + allPlayersAreSleeping(false), + _nightMode(false) +{ + _init(levelName, settings, generatorVersion, fixedDimension); +} + +Level::~Level() { + LOGI("Erasing chunk source\n"); + delete _chunkSource; + LOGI("Erasing dimension\n"); + delete dimension; + delete _pathFinder; + + std::set all; + all.insert(entities.begin(), entities.end()); + all.insert(players.begin(), players.end()); + PendingList::iterator it = _pendingPlayerRemovals.begin(); + while (it != _pendingPlayerRemovals.end()) { + all.insert(it->e); + ++it; + } + for (std::set::iterator it = all.begin(); it != all.end(); ++it) + delete *it; + + std::set allTileEntities; + allTileEntities.insert(tileEntities.begin(), tileEntities.end()); + allTileEntities.insert(pendingTileEntities.begin(), pendingTileEntities.end()); + for (std::set::iterator it = allTileEntities.begin(); it != allTileEntities.end(); ++it) + delete *it; +} + +void Level::_init(const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension) { + + isGeneratingTerrain = false; + + LevelData* preparedData = levelStorage->prepareLevel(this); + _isNew = (preparedData == NULL); + + if (preparedData == NULL) { + levelData = LevelData(settings, levelName, generatorVersion); + } else { + levelData = *preparedData; + levelData.setLevelName(levelName); + } + + if (fixedDimension != NULL) { + dimension = fixedDimension; + } else { + dimension = DimensionFactory::createDefaultDimension( &levelData ); + } + + dimension->init(this); + _chunkSource = createChunkSource(); + + _pathFinder = new PathFinder(); + _nightMode = false; + updateSkyBrightness(); +} + +/*protected*/ +ChunkSource* Level::createChunkSource() { + if (!levelStorage) { + printf("no level data, calling dimension->createRandomLevelSource\n"); + return dimension->createRandomLevelSource(); //@note + } + + ChunkStorage* chunkStorage = levelStorage->createChunkStorage(dimension); + return new ChunkCache(this, chunkStorage, dimension->createRandomLevelSource()); +} + +/*public*/ +bool Level::checkAndHandleWater(const AABB& box, const Material* material, Entity* e) { + int x0 = Mth::floor(box.x0); + int x1 = Mth::floor(box.x1 + 1); + + int y0 = Mth::floor(box.y0); + int y1 = Mth::floor(box.y1 + 1); + + int z0 = Mth::floor(box.z0); + int z1 = Mth::floor(box.z1 + 1); + + if (!hasChunksAt(x0, y0, z0, x1, y1, z1)) { + return false; + } + + bool ok = false; + Vec3 current(0,0,0); + for (int x = x0; x < x1; x++) + for (int y = y0; y < y1; y++) + for (int z = z0; z < z1; z++) { + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile != NULL && tile->material == material) { + float yt0 = y + 1 - LiquidTile::getHeight(getData(x, y, z)); + if (y1 >= yt0) { + ok = true; + tile->handleEntityInside(this, x, y, z, e, current); + } + } + } + float len = current.length(); + if (len > 0) { + const float pow = 0.004f / len; + e->xd += current.x * pow; + e->yd += current.y * pow; + e->zd += current.z * pow; + } + return ok; +} + +/*public*/ +Player* Level::getNearestPlayer(Entity* source, float maxDist) { + return getNearestPlayer(source->x, source->y, source->z, maxDist); +} + +/*public*/ +Player* Level::getNearestPlayer(float x, float y, float z, float maxDist) { + float maxDistSqr = maxDist * maxDist; + float best = -1; + Player* result = NULL; + for (unsigned int i = 0; i < players.size(); i++) { + Player* p = players[i]; + if (p->removed) continue; + float dist = p->distanceToSqr(x, y, z); + if ((maxDist < 0 || dist < maxDistSqr) && (best == -1 || dist < best)) { + best = dist; + result = p; + } + } + return result; +} + +/*public*/ +void Level::tick() { + if (!isClientSide && levelData.getSpawnMobs()) { + static int _mobSpawnTick = 0; + const int MobSpawnInterval = 2; + if (++_mobSpawnTick >= MobSpawnInterval) { + _mobSpawnTick = 0; + TIMER_PUSH("mobSpawner"); + MobSpawner::tick(this, _spawnEnemies && difficulty > Difficulty::PEACEFUL, + _spawnFriendlies && (levelData.getTime() % 400) < MobSpawnInterval); + TIMER_POP(); + } + } + + TIMER_PUSH("chunkSource"); + _chunkSource->tick(); + + updateSkyDarken(); + if(_nightMode) { + long curTime = levelData.getTime(); + if(curTime % TICKS_PER_DAY != MIDDLE_OF_NIGHT_TIME) { + if(curTime % TICKS_PER_DAY < MIDDLE_OF_NIGHT_TIME && (curTime + 20) % TICKS_PER_DAY > MIDDLE_OF_NIGHT_TIME) { + curTime = MIDDLE_OF_NIGHT_TIME; + SetTimePacket packet(curTime); + raknetInstance->send(packet); + } + else { + curTime += 20; + if(curTime % 20 == 0) { + SetTimePacket packet(curTime); + raknetInstance->send(packet); + } + } + setTime(curTime%TICKS_PER_DAY); + } + } + else { + long time = levelData.getTime() + 1; + //if (time % (saveInterval) == 0) { + // save(false, NULL); + //} + levelData.setTime(time); + if ((time & 255) == 0) { + SetTimePacket packet(time); + raknetInstance->send(packet); + } + } + TIMER_POP_PUSH("tickPending"); + tickPendingTicks(false); + + TIMER_POP_PUSH("tickTiles"); + tickTiles(); + + TIMER_POP_PUSH("sendEntityData"); + for (unsigned int i = 0; i < entities.size(); ++i) { + Entity* e = entities[i]; + SynchedEntityData* data = e->getEntityData(); + if (data && data->isDirty()) { + SetEntityDataPacket packet(e->entityId, *data); + raknetInstance->send(packet); + } + } + + //if (!_pendingEntityData.empty()) { + // for (EntityMap::iterator it = _pendingEntityData.begin(); it != _pendingEntityData.end(); ++it) { + // SetEntityDataPacket packet(it->first, it->second->getEntityData()); + // raknetInstance->send(packet); + // } + // _pendingEntityData.clear(); + //} + TIMER_POP(); +} + +/*protected*/ +void Level::tickTiles() { + _chunksToPoll.clear(); + + static const int pollChunkOffsets[] = { + -1,-4, 0,-4, 1,-4, -2,-3, -1,-3, 0,-3, 1,-3, 2,-3, -3,-2, + -2,-2, -1,-2, 0,-2, 1,-2, 2,-2, 3,-2, -4,-1, -3,-1, -2,-1, + -1,-1, 0,-1, 1,-1, 2,-1, 3,-1, 4,-1, -4,0, -3,0, -2,0, -1,0, + 0,0, 1,0, 2,0, 3,0, 4,0, -4,1, -3,1, -2,1, -1,1, 0,1, 1,1, + 2,1, 3,1, 4,1, -3,2, -2,2, -1,2, 0,2, 1,2, 2,2, 3,2, -2,3, + -1,3, 0,3, 1,3, 2,3, -1,4, 0,4, 1,4 + }; + const int pollChunkOffsetsSize = sizeof(pollChunkOffsets) / sizeof(int); + + TIMER_PUSH("buildList"); + //static Stopwatch w; + //w.start(); + for (size_t i = 0; i < players.size(); i++) { + Player* player = players[i]; + int xx = Mth::floor(player->x / 16); + int zz = Mth::floor(player->z / 16); + + for (int i = 0; i < pollChunkOffsetsSize; i += 2) { + const int xp = xx + pollChunkOffsets[i]; + const int zp = zz + pollChunkOffsets[i+1]; + if (xp >= 0 && xp < CHUNK_CACHE_WIDTH && + zp >= 0 && zp < CHUNK_CACHE_WIDTH) + _chunksToPoll.insert(ChunkPos(xp, zp)); + } + } + TIMER_POP(); + + //if (delayUntilNextMoodSound > 0) delayUntilNextMoodSound--; + TIMER_PUSH("loop"); + for (ChunkPosSet::iterator it = _chunksToPoll.begin(); it != _chunksToPoll.end(); ++it) { + const ChunkPos& cp = *it; + int xo = cp.x * 16; + int zo = cp.z * 16; + // LevelSource region = new Region(this, xo, 0, zo, xo + 16, 128, zo + 16); + TIMER_PUSH("getChunk"); + LevelChunk* lc = this->getChunk(cp.x, cp.z); + TIMER_POP_PUSH("tickChunk"); + //lc->tick(); + + //if (delayUntilNextMoodSound == 0) { + // randValue = randValue * 3 + addend; + // int val = (randValue >> 2); + // int x = (val & 15); + // int z = ((val >> 8) & 15); + // int y = ((val >> 16) & 127); + + // int id = lc->getTile(x, y, z); + // x += xo; + // z += zo; + // if (id == 0 && getRawBrightness(x, y, z) <= random.nextInt(8) && getBrightness(LightLayer::Sky, x, y, z) <= 0) { + // Player* player = getNearestPlayer(x + 0.5, y + 0.5, z + 0.5, 8); + // if (player != NULL && player.distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 2 * 2) { + // //this.playSound(x + 0.5, y + 0.5, z + 0.5, "ambient.cave.cave", 0.7f, 0.8f + random.nextFloat() * 0.2f); + // delayUntilNextMoodSound = random.nextInt(20 * 60 * 10) + 20 * 60 * 5; + // } + // } + //} + + TIMER_POP_PUSH("tickTiles"); + for (int i = 0; i < 20; i++) { //@todo: CHUNK_TILE_TICK_COUNT + _randValue = _randValue * 3 + _addend; + int val = (_randValue >> 2); + int x = (val & 15); + int z = ((val >> 8) & 15); + int y = ((val >> 16) & 127); + + int id = lc->getTile(x, y, z); + if (Tile::shouldTick[id]) { + Tile::tiles[id]->tick(this, x + xo, y, z + zo, &random); + } + } + TIMER_POP(); + } + TIMER_POP(); + //w.stop(); + //w.printEvery(30, "ticktiles"); +} + +bool Level::tickPendingTicks(bool force) { + int count = _tickNextTickSet.size(); + if (count > MAX_TICK_TILES_PER_TICK) count = MAX_TICK_TILES_PER_TICK; + for (int i = 0; i < count; i++) { + TickDataSet::iterator td = _tickNextTickSet.begin(); + if (!force && td->delay > levelData.getTime()) { + break; + } + + int r = 8; + if (hasChunksAt(td->x - r, td->y - r, td->z - r, td->x + r, td->y + r, td->z + r)) { + int id = getTile(td->x, td->y, td->z); + if (id == td->tileId && id > 0) { + Tile::tiles[id]->tick(this, td->x, td->y, td->z, &random); + } + } + _tickNextTickSet.erase(td); + } + return _tickNextTickSet.size() != 0; +} + +/*public*/ +void Level::loadPlayer(Player* player, bool doAddPlayer /*= true*/) { + if (player) { + CompoundTag* loadedPlayerTag = levelData.getLoadedPlayerTag(); + if (loadedPlayerTag != NULL) { + player->load(loadedPlayerTag); + levelData.setLoadedPlayerTag(NULL); + } else { + levelData.setLoadedPlayerTo(player); + } + if (doAddPlayer) + addEntity(player); + } + //} catch (Exception e) { + // e.printStackTrace(); + //} +} + +bool Level::findPath(Path* path, Entity* from, Entity* to, float maxDist, bool canOpenDoors, bool avoidWater) { + TIMER_PUSH("pathfind"); + int x = Mth::floor(from->x); + int y = Mth::floor(from->y); + int z = Mth::floor(from->z); + + int r = (int) (maxDist + 16); + int x1 = x - r; + int y1 = y - r; + int z1 = z - r; + int x2 = x + r; + int y2 = y + r; + int z2 = z + r; + //LOGI("trying to move! 1: %ld\n", levelData.getTime()); + Region region(this, x1, y1, z1, x2, y2, z2); + _pathFinder->setLevelSource(®ion); + _pathFinder->canOpenDoors = canOpenDoors; + _pathFinder->avoidWater = avoidWater; + _pathFinder->findPath(path, from, to, maxDist); + TIMER_POP(); + return true; +} + +bool Level::findPath(Path* path, Entity* from, int xBest, int yBest, int zBest, float maxDist, bool canOpenDoors, bool avoidWater) { + TIMER_PUSH("pathfind"); + int x = Mth::floor(from->x); + int y = Mth::floor(from->y); + int z = Mth::floor(from->z); + + int r = (int) (maxDist + 8); + int x1 = x - r; + int y1 = y - r; + int z1 = z - r; + int x2 = x + r; + int y2 = y + r; + int z2 = z + r; + Region region(this, x1, y1, z1, x2, y2, z2); + //LOGI("trying to move! 2: %ld\n", levelData.getTime()); + _pathFinder->setLevelSource(®ion); + _pathFinder->canOpenDoors = canOpenDoors; + _pathFinder->avoidWater = avoidWater; + _pathFinder->findPath(path, from, xBest, yBest, zBest, maxDist); + TIMER_POP(); + return true; +} + +/** +* Sets the initial spawn, created this method so we could do a special +* location for the demo version. +*/ +/*protected*/ +void Level::setInitialSpawn() { + isFindingSpawn = true; + int xSpawn = CHUNK_CACHE_WIDTH * CHUNK_WIDTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; + int ySpawn = 64; + int zSpawn = CHUNK_CACHE_WIDTH * CHUNK_DEPTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; + while (!dimension->isValidSpawn(xSpawn, zSpawn)) { + xSpawn += random.nextInt(32) - random.nextInt(32); + zSpawn += random.nextInt(32) - random.nextInt(32); + + if (xSpawn < 4) xSpawn += 32; + if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 32; + if (zSpawn < 4) zSpawn += 32; + if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 32; + } + levelData.setSpawn(xSpawn, ySpawn, zSpawn); + isFindingSpawn = false; +} + +/*public*/ +void Level::validateSpawn() { + if (levelData.getYSpawn() <= 0) { + levelData.setYSpawn(64); + } + int xSpawn = levelData.getXSpawn(); + int zSpawn = levelData.getZSpawn(); + while (getTopTile(xSpawn, zSpawn) == 0 || getTopTile(xSpawn, zSpawn) == Tile::invisible_bedrock->id) { + xSpawn += random.nextInt(8) - random.nextInt(8); + zSpawn += random.nextInt(8) - random.nextInt(8); + + if (xSpawn < 4) xSpawn += 8; + if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 8; + if (zSpawn < 4) zSpawn += 8; + if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 8; + } + levelData.setXSpawn(xSpawn); + levelData.setZSpawn(zSpawn); +} + +int Level::getTopTile(int x, int z) { + int y = 63; + while (!isEmptyTile(x, y + 1, z)) { + y++; + } + return getTile(x, y, z); +} + +int Level::getTopTileY(int x, int z) { + int y = 63; + while (!isEmptyTile(x, y + 1, z)) { + y++; + } + return y; +} +// +// void clearLoadedPlayerData() { +// } +// +// void save(bool force, ProgressListener progressListener) { +// if (!chunkSource.shouldSave()) return; +// +// if (progressListener != NULL) progressListener.progressStartNoAbort("Saving level"); +// saveLevelData(); +// +// if (progressListener != NULL) progressListener.progressStage("Saving chunks"); +// chunkSource.save(force, progressListener); +// } +// + +//void Level::saveAllChunks() { +// _chunkSource->saveAll(); +//} + +void Level::saveLevelData() { + levelStorage->saveLevelData(levelData, &players); +} + +// bool pauseSave(int step) { +// if (!chunkSource.shouldSave()) return true; +// if (step == 0) saveLevelData(); +// return chunkSource.save(false, NULL); +// } + +//void Level::savePlayerData() { +// levelStorage->savePlayerData(&levelData, players); +//} + +int Level::getTile(int x, int y, int z) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return 0; + //} + if (y < 0) return 0; + if (y >= DEPTH) return 0; + //if (z == 128) { + // int a = 0; + //} + //LOGI("%d ", z); + return getChunk(x >> 4, z >> 4)->getTile(x & 15, y, z & 15); +} + +bool Level::isEmptyTile(int x, int y, int z) { + return getTile(x, y, z) == 0; +} + +bool Level::hasChunkAt(int x, int y, int z) { + if (y < 0 || y >= Level::DEPTH) return false; + return hasChunk(x >> 4, z >> 4); +} + + +bool Level::hasChunksAt(int x, int y, int z, int r) { + return hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r); +} + +bool Level::hasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1) { + if (y1 < 0 || y0 >= Level::DEPTH) return false; + + x0 >>= 4; + z0 >>= 4; + x1 >>= 4; + z1 >>= 4; + + for (int x = x0; x <= x1; x++) + for (int z = z0; z <= z1; z++) + if (!hasChunk(x, z)) return false; + + return true; +} + +bool Level::hasChunk(int x, int z) { + return _chunkSource->hasChunk(x, z); +} + +LevelChunk* Level::getChunkAt(int x, int z) { + return getChunk(x >> 4, z >> 4); +} + +LevelChunk* Level::getChunk(int x, int z) { + return _chunkSource->getChunk(x, z); +} + +bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return false; + //} + if (y < 0) return false; + if (y >= DEPTH) return false; + LevelChunk* c = getChunk(x >> 4, z >> 4); + return c->setTileAndData(x & 15, y, z & 15, tile, data); +} + +bool Level::setTileNoUpdate(int x, int y, int z, int tile) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return false; + //} + if (y < 0) return false; + if (y >= DEPTH) return false; + LevelChunk* c = getChunk(x >> 4, z >> 4); + return c->setTile(x & 15, y, z & 15, tile); +} + +const Material* Level::getMaterial(int x, int y, int z) { + int t = getTile(x, y, z); + if (t == 0) return Material::air; + return Tile::tiles[t]->material; +} + +int Level::getData(int x, int y, int z) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return 0; + //} + if (y < 0) return 0; + if (y >= DEPTH) return 0; + LevelChunk* c = getChunk(x >> 4, z >> 4); + x &= 15; + z &= 15; + return c->getData(x, y, z); +} + +void Level::setData(int x, int y, int z, int data) { + //// @newway + //if (setDataNoUpdate(x, y, z, data)) { + // int t = getTile(x, y, z); + // if (Tile::sendTileData[t]) { + // tileUpdated(x, y, z, t); + // } else { + // updateNeighborsAt(x, y, z, t); + // } + //} + + // @oldway + if (setDataNoUpdate(x, y, z, data)) { + tileUpdated(x, y, z, getTile(x, y, z)); + } +} + +bool Level::setDataNoUpdate(int x, int y, int z, int data) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return false; + //} + if (y < 0) return false; + if (y >= DEPTH) return false; + LevelChunk* c = getChunk(x >> 4, z >> 4); + x &= 15; + z &= 15; + + //return c->setData(x, y, z, data); + + if (c->getData(x, y, z) != data) { + c->setData(x, y, z, data); + return true; + } + return false; +} + +bool Level::setTile(int x, int y, int z, int tile) { + if (setTileNoUpdate(x, y, z, tile)) { + //printf("TILE UPDATED %d, %d, %d\n", x, y, z); + tileUpdated(x, y, z, tile); + return true; + } + return false; +} + +bool Level::setTileAndData(int x, int y, int z, int tile, int data) { + if (setTileAndDataNoUpdate(x, y, z, tile, data)) { + tileUpdated(x, y, z, tile); + return true; + } + return false; +} + +void Level::sendTileUpdated(int x, int y, int z) { + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->tileChanged(x, y, z); + } +} + +/*protected*/ +void Level::tileUpdated(int x, int y, int z, int tile) { + sendTileUpdated(x, y, z); + this->updateNeighborsAt(x, y, z, tile); +} + +void Level::lightColumnChanged(int x, int z, int y0, int y1) { + if (y0 > y1) { + int tmp = y1; + y1 = y0; + y0 = tmp; + } + setTilesDirty(x, y0, z, x, y1, z); +} + +void Level::setTileDirty(int x, int y, int z) { + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->setTilesDirty(x, y, z, x, y, z); + } +} + +void Level::setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1) { + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->setTilesDirty(x0, y0, z0, x1, y1, z1); + } +} + +void Level::swap(int x1, int y1, int z1, int x2, int y2, int z2) { + int t1 = getTile(x1, y1, z1); + int d1 = getData(x1, y1, z1); + int t2 = getTile(x2, y2, z2); + int d2 = getData(x2, y2, z2); + + setTileAndDataNoUpdate(x1, y1, z1, t2, d2); + setTileAndDataNoUpdate(x2, y2, z2, t1, d1); + + updateNeighborsAt(x1, y1, z1, t2); + updateNeighborsAt(x2, y2, z2, t1); +} + +void Level::updateNeighborsAt(int x, int y, int z, int tile) { + neighborChanged(x - 1, y, z, tile); + neighborChanged(x + 1, y, z, tile); + neighborChanged(x, y - 1, z, tile); + neighborChanged(x, y + 1, z, tile); + neighborChanged(x, y, z - 1, tile); + neighborChanged(x, y, z + 1, tile); +} + +/*private*/ void Level::neighborChanged(int x, int y, int z, int type) { + if (noNeighborUpdate || isClientSide) return; + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile != NULL) tile->neighborChanged(this, x, y, z, type); +} + +bool Level::canSeeSky(int x, int y, int z) { + return getChunk(x >> 4, z >> 4)->isSkyLit(x & 15, y, z & 15); +} + +int Level::getRawBrightness(int x, int y, int z) { + return getRawBrightness(x, y, z, true); +} + +int Level::getRawBrightness(int x, int y, int z, bool propagate) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return MAX_BRIGHTNESS; + //} + + if (propagate) { + int id = getTile(x, y, z); + if (id == Tile::stoneSlabHalf->id || id == Tile::farmland->id) { + int br = getRawBrightness(x, y + 1, z, false); + int br1 = getRawBrightness(x + 1, y, z, false); + int br2 = getRawBrightness(x - 1, y, z, false); + int br3 = getRawBrightness(x, y, z + 1, false); + int br4 = getRawBrightness(x, y, z - 1, false); + if (br1 > br) br = br1; + if (br2 > br) br = br2; + if (br3 > br) br = br3; + if (br4 > br) br = br4; + return br; + } + } + + if (y < 0) return 0; + if (y >= DEPTH) { + int br = MAX_BRIGHTNESS - skyDarken; + if (br < 0) br = 0; + return br; + } + + LevelChunk* c = getChunk(x >> 4, z >> 4); + x &= 15; + z &= 15; + return c->getRawBrightness(x, y, z, skyDarken); +} + +bool Level::isSkyLit(int x, int y, int z) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return false; + //} + if (y < 0) return false; + if (y >= DEPTH) return true; + if (!hasChunk(x >> 4, z >> 4)) return false; + + LevelChunk* c = getChunk(x >> 4, z >> 4); + x &= 15; + z &= 15; + + return c->isSkyLit(x, y, z); +} + +int Level::getHeightmap(int x, int z) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return 0; + //} + if (!hasChunk(x >> 4, z >> 4)) return 0; + + LevelChunk* c = getChunk(x >> 4, z >> 4); + return c->getHeightmap(x & 15, z & 15); +} + +BiomeSource* Level::getBiomeSource() { + return dimension->biomeSource; +} +Biome* Level::getBiome( int x, int z ) { + return dimension->biomeSource->getBiome(x, z); +} + +void Level::updateLightIfOtherThan(const LightLayer& layer, int x, int y, int z, int expected) { + if (dimension->hasCeiling && (&layer) == &LightLayer::Sky) return; + + if (!hasChunkAt(x, y, z)) return; + + if (&layer == &LightLayer::Sky) { + if (isSkyLit(x, y, z)) expected = 15; + } else if (&layer == &LightLayer::Block) { + int t = getTile(x, y, z); + if (Tile::lightEmission[t] > expected) expected = Tile::lightEmission[t]; + } + + if (getBrightness(layer, x, y, z) != expected) { + updateLight(layer, x, y, z, x, y, z); + } +} + +int Level::getBrightness(const LightLayer& layer, int x, int y, int z) { + if (y < 0 || y >= DEPTH/* || x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE*/) { + return layer.surrounding; + } + int xc = x >> 4; + int zc = z >> 4; + if (!hasChunk(xc, zc)) return 0; + LevelChunk* c = getChunk(xc, zc); + return c->getBrightness(layer, x & 15, y, z & 15); +} + +void Level::setBrightness(const LightLayer& layer, int x, int y, int z, int brightness) { + //if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z > MAX_LEVEL_SIZE) { + // return; + //} + if (y < 0) return; + if (y >= DEPTH) return; + if (!hasChunk(x >> 4, z >> 4)) return; + LevelChunk* c = getChunk(x >> 4, z >> 4); + c->setBrightness(layer, x & 15, y, z & 15, brightness); + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->tileBrightnessChanged(x, y, z); + } +} + +float Level::getBrightness(int x, int y, int z) { + return dimension->brightnessRamp[getRawBrightness(x, y, z)]; +} + +bool Level::isDay() { + return this->skyDarken < 4; +} + +//HitResult Level::clip(const Vec3& a, const Vec3& b) { +// return clip(a, b, false); +//} + +HitResult Level::clip(const Vec3& A, const Vec3& b, bool liquid /*= false*/, bool solidOnly /*= false*/) { + static Stopwatch sw; + //sw.printEvery(1000, "clip"); + SwStartStopper w(sw); + + if (A.x != A.x || A.y != A.y || A.z != A.z) return HitResult(); //@kludge This is actually a way to do it + if (b.x != b.x || b.y != b.y || b.z != b.z) return HitResult(); + + Vec3 a(A); + + int xTile1 = Mth::floor(b.x); + int yTile1 = Mth::floor(b.y); + int zTile1 = Mth::floor(b.z); + + int xTile0 = Mth::floor(a.x); + int yTile0 = Mth::floor(a.y); + int zTile0 = Mth::floor(a.z); + + int maxIterations = 200; + while (maxIterations-- >= 0) { + if (a.x != a.x || a.y != a.y || a.z != a.z) + return HitResult(); + if (xTile0 == xTile1 && yTile0 == yTile1 && zTile0 == zTile1) + return HitResult(); + + float xClip = 999; + float yClip = 999; + float zClip = 999; + + if (xTile1 > xTile0) xClip = xTile0 + 1.000f; + if (xTile1 < xTile0) xClip = xTile0 + 0.000f; + + if (yTile1 > yTile0) yClip = yTile0 + 1.000f; + if (yTile1 < yTile0) yClip = yTile0 + 0.000f; + + if (zTile1 > zTile0) zClip = zTile0 + 1.000f; + if (zTile1 < zTile0) zClip = zTile0 + 0.000f; + + float xDist = 999; + float yDist = 999; + float zDist = 999; + + float xd = b.x - a.x; + float yd = b.y - a.y; + float zd = b.z - a.z; + + if (xClip != 999) xDist = (xClip - a.x) / xd; + if (yClip != 999) yDist = (yClip - a.y) / yd; + if (zClip != 999) zDist = (zClip - a.z) / zd; + + int face = 0; + if (xDist < yDist && xDist < zDist) { + if (xTile1 > xTile0) face = 4; + else face = 5; + + a.x = xClip; + a.y += yd * xDist; + a.z += zd * xDist; + } else if (yDist < zDist) { + if (yTile1 > yTile0) face = 0; + else face = 1; + + a.x += xd * yDist; + a.y = yClip; + a.z += zd * yDist; + } else { + if (zTile1 > zTile0) face = 2; + else face = 3; + + a.x += xd * zDist; + a.y += yd * zDist; + a.z = zClip; + } + + Vec3 tPos(a.x, a.y, a.z); + xTile0 = (int) (tPos.x = (float)Mth::floor(a.x)); + if (face == 5) { + xTile0--; + tPos.x++; + } + yTile0 = (int) (tPos.y = (float)Mth::floor(a.y)); + if (face == 1) { + yTile0--; + tPos.y++; + } + zTile0 = (int) (tPos.z = (float)Mth::floor(a.z)); + if (face == 3) { + zTile0--; + tPos.z++; + } + + int t = getTile(xTile0, yTile0, zTile0); + int data = getData(xTile0, yTile0, zTile0); + Tile* tile = Tile::tiles[t]; + + if (solidOnly && tile != NULL && tile->getAABB(this, xTile0, yTile0, zTile0) == NULL) { + // No collision + } else if (t > 0 && tile->mayPick(data, liquid)) { + if(xTile0 >= 0 && zTile0 >= 0 && xTile0 < LEVEL_WIDTH && zTile0 < LEVEL_WIDTH) { + HitResult r = tile->clip(this, xTile0, yTile0, zTile0, a, b); + if (r.isHit()) return r; + } + } + } + return HitResult(); +} + +void Level::playSound(Entity* entity, const std::string& name, float volume, float pitch) { + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->playSound(name, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); + } +} + +void Level::playSound(float x, float y, float z, const std::string& name, float volume, float pitch) { + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->playSound(name, x, y, z, volume, pitch); + } +} + +void Level::levelEvent(Player* source, int type, int x, int y, int z, int data) { + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->levelEvent(source, type, x, y, z, data); + } +} + +void Level::tileEvent(int x, int y, int z, int b0, int b1) { + int t = getTile(x, y, z); + if (t > 0) Tile::tiles[t]->triggerEvent(this, x, y, z, b0, b1); + + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->tileEvent(x, y, z, b0, b1); + } +} + +// +// void playStreamingMusic(String name, int x, int y, int z) { +// for (unsigned int i = 0; i < listeners.size(); i++) { +// listeners.get(i).playStreamingMusic(name, x, y, z); +// } +// } +// +// void playMusic(float x, float y, float z, String string, float volume) { +// } +// + +void Level::addParticle(const std::string& id, float x, float y, float z, float xd, float yd, float zd, int data /* = 0 */) { + for (unsigned int i = 0; i < _listeners.size(); i++) + _listeners[i]->addParticle(id, x, y, z, xd, yd, zd, data); +} + +void Level::addParticle(ParticleType::Id id, float x, float y, float z, float xd, float yd, float zd, int data /* = 0 */) { + for (unsigned int i = 0; i < _listeners.size(); i++) + _listeners[i]->addParticle(id, x, y, z, xd, yd, zd, data); +} + +bool Level::addEntity(Entity* e) { + Entity* prev = getEntity(e->entityId); + if (prev) + removeEntity(prev); + + int xc = Mth::floor(e->x / 16.f); + int zc = Mth::floor(e->z / 16.f); + + //bool forced = false; + //if (e->isPlayer()) { + // forced = true; + //} + bool forced = true; + + if (forced/* || hasChunk(xc, zc)*/) { + if (e->isPlayer() && std::find(players.begin(), players.end(), e) == players.end()) { + players.push_back( (Player*) e ); + } + getChunk(xc, zc)->addEntity(e); + entities.push_back(e); + entityIdLookup[e->entityId] = e; + entityAdded(e); + return true; + } + + return false; +} + +Entity* Level::getEntity(int entityId) +{ + // TODO: Lookup map + /*for (unsigned int i = 0; i < entities.size(); i++) + { + if (entities[i]->entityId == entityId) + { + return entities[i]; + } + } + return NULL;*/ + EntityMap::const_iterator cit = entityIdLookup.find(entityId); + return (cit != entityIdLookup.end())? cit->second : NULL; +} + +/*protected*/ +void Level::entityAdded(Entity* e) { + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->entityAdded(e); + } +} + +/*protected*/ +void Level::entityRemoved(Entity* e) { + for (unsigned int j = 0; j < _listeners.size(); j++) { + _listeners[j]->entityRemoved(e); + } +} + +Mob* Level::getMob(int entityId) +{ + Entity* entity = getEntity(entityId); + return (entity && entity->isMob())? (Mob*)entity : NULL; +} + +void Level::removeEntity(Entity* e) { + e->remove(); + if (e->isPlayer() && e->reallyRemoveIfPlayer) { + Util::remove(players, (Player*) e); + } +} + +void Level::tileEntityChanged(int x, int y, int z, TileEntity* te) { + if (this->hasChunkAt(x, y, z)) { + getChunkAt(x, z)->markUnsaved(); + } + for (unsigned int i = 0; i < _listeners.size(); i++) { + _listeners[i]->tileEntityChanged(x, y, z, te); + } +} + + +//void Level::removeEntityImmediately(Entity* e) { +// e->remove(); +// +// if (e->isPlayer()) { +// Util::remove(players, (Player*)e); +// } +// +// int xc = e->xChunk; +// int zc = e->zChunk; +// if (e->inChunk && hasChunk(xc, zc)) { +// getChunk(xc, zc)->removeEntity(e); +// } +// +// Util::remove(entities, e); +//} + +Biome::MobSpawnerData Level::getRandomMobSpawnAt(const MobCategory& mobCategory, int x, int y, int z) { + Biome::MobList mobList = _chunkSource->getMobsAt(mobCategory, x, y, z); + if (mobList.empty()) return Biome::MobSpawnerData(); + + Biome::MobSpawnerData* data = (Biome::MobSpawnerData*) WeighedRandom::getRandomItem(&random, mobList); + if (!data) + return Biome::MobSpawnerData(); + return *data; +} + +void Level::addListener(LevelListener* listener) { + _listeners.push_back(listener); +} + +void Level::removeListener(LevelListener* listener) { + ListenerList::iterator it = std::find(_listeners.begin(), _listeners.end(), listener); + _listeners.erase(it); +} + +std::vector& Level::getCubes(const Entity* source, const AABB& box_) { //@attn: check the AABB* new/delete stuff + boxes.clear(); + const AABB* box = &box_; + int x0 = Mth::floor(box->x0); + int x1 = Mth::floor(box->x1 + 1); + int y0 = Mth::floor(box->y0); + int y1 = Mth::floor(box->y1 + 1); + int z0 = Mth::floor(box->z0); + int z1 = Mth::floor(box->z1 + 1); + + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + if (hasChunkAt(x, Level::DEPTH / 2, z)) { + for (int y = y0 - 1; y < y1; y++) { + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile != NULL) { + tile->addAABBs(this, x, y, z, box, boxes); + } + } + } + else + { + //int breakPoint = 0; + } + } + /* + float r = 0.25; + List ee = getEntities(source, box.grow(r, r, r)); + for (int i = 0; i < ee.size(); i++) { + AABB collideBox = ee.get(i).getCollideBox(); + if (collideBox != NULL && collideBox.intersects(box)) { + boxes.add(collideBox); + } + + collideBox = source.getCollideAgainstBox(ee.get(i)); + if (collideBox != NULL && collideBox.intersects(box)) { + boxes.add(collideBox); + } + } + */ + + return boxes; +} + +int Level::getSkyDarken(float a) { + float td = getTimeOfDay(a); + + float br = 1 - (Mth::cos(td * Mth::PI * 2) * 2 + 0.5f); + if (br < 0.0f) br = 0.0f; + if (br > 0.80f) br = 0.80f; //@note; was 1.0f + return ((int) (br * 11)); +} + +Vec3 Level::getSkyColor(Entity* source, float a) { + float td = getTimeOfDay(a); + + float br = Mth::cos(td * Mth::PI * 2) * 2 + 0.5f; + if (br < 0.0f) br = 0.0f; + if (br > 0.75f) br = 0.75f; //@note; was 1.0f + +// int xx = Mth::floor(source->x); +// int zz = Mth::floor(source->z); +// float temp = 0.5;//(float) getBiomeSource().getTemperature(xx, zz); + int skyColor = 0x3070ff;//getBiomeSource().getBiome(xx, zz).getSkyColor(temp); + + float r = ((skyColor >> 16) & 0xff) / 255.0f; + float g = ((skyColor >> 8) & 0xff) / 255.0f; + float b = ((skyColor) & 0xff) / 255.0f; + r *= br; + g *= br; + b *= br; + + return Vec3(r, g, b); +} + +Vec3 Level::getCloudColor( float a ) { + float td = getTimeOfDay(a); + + float br = Mth::cos(td * Mth::PI * 2) * 2.0f + 0.5f; + if (br < 0.0f) br = 0.0f; + if (br > 1.0f) br = 1.0f; + long cloudColor = 0xffffff; + float r = ((cloudColor >> 16) & 0xff) / 255.0f; + float g = ((cloudColor >> 8) & 0xff) / 255.0f; + float b = ((cloudColor) & 0xff) / 255.0f; + + float rainLevel = 0;//getRainLevel(a); + if (rainLevel > 0) { + float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.6f; + + float ba = 1 - rainLevel * 0.95f; + r = r * ba + mid * (1 - ba); + g = g * ba + mid * (1 - ba); + b = b * ba + mid * (1 - ba); + } + + r *= br * 0.90f + 0.10f; + g *= br * 0.90f + 0.10f; + b *= br * 0.85f + 0.15f; + + float thunderLevel = 0; //getThunderLevel(a); + if (thunderLevel > 0) { + float mid = (r * 0.30f + g * 0.59f + b * 0.11f) * 0.2f; + + float ba = 1 - thunderLevel * 0.95f; + r = r * ba + mid * (1 - ba); + g = g * ba + mid * (1 - ba); + b = b * ba + mid * (1 - ba); + } + + return Vec3(r, g, b); +} + +float Level::getTimeOfDay(float a) { + return dimension->getTimeOfDay(levelData.getTime(), a); + //int time = 20 * levelData.getTime(); + //float out = dimension->getTimeOfDay(time, a); + //LOGI("getTime: %d, dayTime: %f\n", time, out); + //return out; +} + +float Level::getSunAngle(float a) { + float td = getTimeOfDay(a); + return td * Mth::PI * 2; +} + +//Vec3 Level::getCloudColor(float a) { +// float td = getTimeOfDay(a); +// +// float br = Mth::cos(td * Mth::PI * 2) * 2.0f + 0.5f; +// if (br < 0.f) br = 0; +// if (br > 1.f) br = 1; +// +// float r = ((cloudColor >> 16) & 0xff) / 255.0f; +// float g = ((cloudColor >> 8) & 0xff) / 255.0f; +// float b = ((cloudColor) & 0xff) / 255.0f; +// +// r *= br * 0.90f + 0.10f; +// g *= br * 0.90f + 0.10f; +// b *= br * 0.85f + 0.15f; +// +// return Vec3(r, g, b); +//} + +Vec3 Level::getFogColor(float a) { + float td = getTimeOfDay(a); + return dimension->getFogColor(td, a); +} + +int Level::getTopSolidBlock(int x, int z) { + LevelChunk* levelChunk = getChunkAt(x, z); + + int y = Level::DEPTH - 1; + + while (getMaterial(x, y, z)->blocksMotion() && y > 0) { + y--; + } + + x &= 15; + z &= 15; + + while (y > 0) { + int t = levelChunk->getTile(x, y, z); + if (t == 0 /*|| !(Tile::tiles[t]->material->blocksMotion() || Tile::tiles[t]->material->isLiquid())*/ + || !(Tile::tiles[t]->material->blocksMotion()) + || Tile::tiles[t]->material == Material::leaves) { + y--; + } else { + return y + 1; + } + } + return -1; +} + +int Level::getLightDepth(int x, int z) { + return getChunkAt(x, z)->getHeightmap(x & 15, z & 15); +} + +float Level::getStarBrightness(float a) { + float td = getTimeOfDay(a); + + float br = 1 - (Mth::cos(td * Mth::PI * 2) * 2 + 0.75f); + if (br < 0.f) br = 0; + if (br > 1.f) br = 1; + + return br * br * 0.5f; +} + +void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay) { + TickNextTickData td(x, y, z, tileId); + int r = 8; + if (instaTick) { + if (hasChunksAt(td.x - r, td.y - r, td.z - r, td.x + r, td.y + r, td.z + r)) { + int id = getTile(td.x, td.y, td.z); + if (id == td.tileId && id > 0) { + Tile::tiles[id]->tick(this, td.x, td.y, td.z, &random); + } + } + return; + } + + if (hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { + if (tileId > 0) { + td.setDelay(tickDelay + levelData.getTime()); + } + if (_tickNextTickSet.find(td) == _tickNextTickSet.end()) { + _tickNextTickSet.insert(td); + } + } +} + +void Level::tickEntities() { + TIMER_PUSH("entities"); + + TIMER_PUSH("remove"); + //Util::removeAll(entities, _entitiesToRemove); + // for (int j = 0; j < (int)_entitiesToRemove.size(); j++) { + // Entity* e = _entitiesToRemove[j]; + // int xc = e->xChunk; + // int zc = e->zChunk; + // if (e->inChunk && hasChunk(xc, zc)) { + // getChunk(xc, zc)->removeEntity(e); + // } + // } + // for (int j = 0; j < (int)_entitiesToRemove.size(); j++) { + // entityRemoved(_entitiesToRemove[j]); + // //LOGI("a1 &e@delt: %p", _entitiesToRemove[j]); + // delete _entitiesToRemove[j]; + // //LOGI("a2"); + // } + // _entitiesToRemove.clear(); + + EntityList pendingRemovedEntities; + std::vector zombies; + + TIMER_POP_PUSH("regular"); + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + + if (!e->removed) { + tick(e); + if (e->getEntityTypeId() == MobTypes::Zombie) { + zombies.push_back((Zombie*)e); + ((Zombie*)e)->setUseNewAi(false); // @note: this is set under + } + } + + TIMER_PUSH("remove"); + if (e->removed && (!e->isPlayer() || e->reallyRemoveIfPlayer)) { + int xc = e->xChunk; + int zc = e->zChunk; + if (e->inChunk && hasChunk(xc, zc)) { + getChunk(xc, zc)->removeEntity(e); + } + entityIdLookup.erase(e->entityId); + entities.erase(entities.begin() + (i--)); + entityRemoved(e); + pendingRemovedEntities.push_back(e); + } + TIMER_POP(); + } + + TIMER_POP_PUSH("remove"); + for (unsigned int i = 0; i < pendingRemovedEntities.size(); ++i) { + Entity* e = pendingRemovedEntities[i]; + //if (!e->isPlayer()) // @todo: remove fast as heck + if (e->isPlayer()) + _pendingPlayerRemovals.push_back( PRInfo(e, 16) ); + else + delete e; + + } pendingRemovedEntities.clear(); + + // Yes, I know this is bad, but it's extremely few players + // to remove anyway. + for (int i = (int)_pendingPlayerRemovals.size()-1; i >= 0; --i) { + PRInfo& pr = _pendingPlayerRemovals[i]; + if (--pr.ticks <= 0) { + LOGI("deleting: %p\n", pr.e); + delete pr.e; + _pendingPlayerRemovals.erase(_pendingPlayerRemovals.begin() + i); + } + } + + //setZombieAi(zombies); + + TIMER_POP_PUSH("tileEntities"); + updatingTileEntities = true; + //LOGI("num tile entities %d\n", tileEntities.size()); + for (unsigned int i = 0; i < tileEntities.size(); ++i) { + TileEntity* te = tileEntities[i]; + if (!te->isRemoved() && te->level != NULL) { + if (hasChunkAt(te->x, te->y, te->z)) { + te->tick(); + } + } + + if (/*te->isFinished() || */te->isRemoved()) { + + for (int j = 0; j < 10; ++j) + LOGI("REmoved tile-entity @ %d, %d, %d\n", te->x, te->y, te->z); + + tileEntities.erase(tileEntities.begin() + (i--)); + + if (hasChunk(te->x >> 4, te->z >> 4)) { + LevelChunk* lc = getChunk(te->x >> 4, te->z >> 4); + if (lc != NULL) { + lc->removeTileEntity(te->x & 15, te->y, te->z & 15); + } + } + delete te; + } + } + updatingTileEntities = false; + + TIMER_POP_PUSH("pendingTileEntities"); + if (!pendingTileEntities.empty()) { + for (unsigned int i = 0; i < pendingTileEntities.size(); ++i) { + TileEntity* e = pendingTileEntities[i]; + if (!e->isRemoved()) { + bool found = false; + for (unsigned int j = 0; j < tileEntities.size(); ++j) { + if (tileEntities[j] == e) { + found = true; + break; + } + } + int xx = e->x, yy = e->y, zz = e->z; + + LevelChunk* lc = getChunk(xx >> 4, zz >> 4); + bool has = lc && lc->hasTileEntityAt(e); + if (!found) { + if (!has) tileEntities.push_back(e); + else { + delete e; + e = NULL; + } + } + + if (e && lc) lc->setTileEntity(xx & 15, yy, zz & 15, e); + sendTileUpdated(xx, yy, zz); + } + } + pendingTileEntities.clear(); + } + + + TIMER_POP(); + TIMER_POP(); +} + +class DistanceEntitySorter { + Vec3 c; +public: + DistanceEntitySorter(float x, float y, float z) : c(x, y, z) {} + bool operator() (const Entity* c0, const Entity* c1) { + const float d0 = c.distanceToSqr(c0->x, c0->y, c0->z); + const float d1 = c.distanceToSqr(c1->x, c1->y, c1->z); + return d0 < d1; + } +}; + +void Level::setZombieAi(std::vector& zombies) { + unsigned int size = zombies.size(); + const int NumSmartZombiesPerPlayer = 0; + if (size <= NumSmartZombiesPerPlayer) { + for (unsigned int i = 0; i < size; ++i) + zombies[i]->setUseNewAi(true); + return; + } + + for (unsigned int i = 0; i < players.size(); ++i) { + Player* p = players[i]; + DistanceEntitySorter sorter(p->x, p->y, p->z); + std::nth_element(zombies.begin(), zombies.begin() + NumSmartZombiesPerPlayer, zombies.end(), sorter); + for (int j = 0; j < NumSmartZombiesPerPlayer; ++j) + if (zombies[j]->distanceToSqr(p) < 32*32) + zombies[j]->setUseNewAi(true); + } +} + +void Level::tick(Entity* e) { + tick(e, true); +} + +void Level::tick(Entity* e, bool actual) { + int xc = Mth::floor(e->x); + int zc = Mth::floor(e->z); + int r = 32; + if (actual && !hasChunksAt(xc - r, 0, zc - r, xc + r, 128, zc + r)) { + return; + } + + e->xOld = e->x; + e->yOld = e->y; + e->zOld = e->z; + e->yRotO = e->yRot; + e->xRotO = e->xRot; + + if (actual && e->inChunk) { + e->tick(); + } + + TIMER_PUSH("chunkCheck"); + // SANITY!! + if (e->x != e->x) e->x = e->xOld; // @note: checking for NaN, not sure about Infinite + if (e->y != e->y) e->y = e->yOld; + if (e->z != e->z) e->z = e->zOld; + if (e->xRot != e->xRot) e->xRot = e->xRotO; + if (e->yRot != e->yRot) e->yRot = e->yRotO; + + int xcn = Mth::floor(e->x / 16.0f); + int ycn = Mth::floor(e->y / 16.0f); + int zcn = Mth::floor(e->z / 16.0f); + + if (!e->inChunk || (e->xChunk != xcn || e->yChunk != ycn || e->zChunk != zcn)) { + if (e->inChunk && hasChunk(e->xChunk, e->zChunk)) { + getChunk(e->xChunk, e->zChunk)->removeEntity(e, e->yChunk); + } + + if (hasChunk(xcn, zcn)) { + e->inChunk = true; + getChunk(xcn, zcn)->addEntity(e); + } else { + e->inChunk = false; + } + } + TIMER_POP(); + + // Save player info every n:th second + const float now = getTimeS(); + if (now - _lastSavedPlayerTime >= 30) { + saveLevelData(); + _lastSavedPlayerTime = now; + } +} + +bool Level::isUnobstructed(const AABB& aabb) { + EntityList& entities = getEntities(NULL, aabb); + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + if (!e->removed && e->blocksBuilding) return false; + } + return true; +} + +bool Level::containsAnyLiquid(const AABB& box) { + int x0 = Mth::floor(box.x0); + int x1 = Mth::floor(box.x1 + 1); + int y0 = Mth::floor(box.y0); + int y1 = Mth::floor(box.y1 + 1); + int z0 = Mth::floor(box.z0); + int z1 = Mth::floor(box.z1 + 1); + + if (box.x0 < 0) x0--; + if (box.y0 < 0) y0--; + if (box.z0 < 0) z0--; + + for (int x = x0; x < x1; x++) + for (int y = y0; y < y1; y++) + for (int z = z0; z < z1; z++) { + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile != NULL && tile->material->isLiquid()) { + return true; + } + } + return false; +} + +bool Level::containsFireTile(const AABB& box) { + int x0 = Mth::floor(box.x0); + int x1 = Mth::floor(box.x1 + 1); + int y0 = Mth::floor(box.y0); + int y1 = Mth::floor(box.y1 + 1); + int z0 = Mth::floor(box.z0); + int z1 = Mth::floor(box.z1 + 1); + + if (hasChunksAt(x0, y0, z0, x1, y1, z1)) { + for (int x = x0; x < x1; x++) + for (int y = y0; y < y1; y++) + for (int z = z0; z < z1; z++) { + int t = getTile(x, y, z); + + if (/*t == ((Tile*)(Tile::fire))->id + ||*/ t == Tile::lava->id + || t == Tile::calmLava->id) { + return true; + } + } + } + return false; +} + +bool Level::containsMaterial(const AABB& box, const Material* material) { + int x0 = Mth::floor(box.x0); + int x1 = Mth::floor(box.x1 + 1); + int y0 = Mth::floor(box.y0); + int y1 = Mth::floor(box.y1 + 1); + int z0 = Mth::floor(box.z0); + int z1 = Mth::floor(box.z1 + 1); + + for (int x = x0; x < x1; x++) + for (int y = y0; y < y1; y++) + for (int z = z0; z < z1; z++) { + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile != NULL && tile->material == material) { + return true; + } + } + return false; +} + +bool Level::containsLiquid(const AABB& box, const Material* material) { + int x0 = Mth::floor(box.x0); + int x1 = Mth::floor(box.x1 + 1); + int y0 = Mth::floor(box.y0); + int y1 = Mth::floor(box.y1 + 1); + int z0 = Mth::floor(box.z0); + int z1 = Mth::floor(box.z1 + 1); + + for (int x = x0; x < x1; x++) + for (int y = y0; y < y1; y++) + for (int z = z0; z < z1; z++) { + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile != NULL && tile->material == material) { + int data = getData(x, y, z); + float yh1 = (float)(y + 1); + if (data < 8) { + yh1 = (float)y + 1.0f - (float)data / 8.0f; + } + if (yh1 >= box.y0) { + return true; + } + } + } + return false; +} + +/* in java, this returns an Explosion */ +void Level::explode(Entity* source, float x, float y, float z, float r) { + explode(source, x, y, z, r, false); +} + +/* in java, this returns an Explosion */ +void Level::explode(Entity* source, float x, float y, float z, float r, bool fire) { + if (!isClientSide) { + Explosion explosion(this, source, x, y, z, r); + explosion.fire = fire; + explosion.explode(); + explosion.finalizeExplosion(); + ExplodePacket packet(x, y, z, r, explosion.toBlow); + raknetInstance->send(packet); + } +} + +float Level::getSeenPercent(const Vec3& center, const AABB& bb) { + float xs = 1.0f / ((bb.x1 - bb.x0) * 2 + 1); + float ys = 1.0f / ((bb.y1 - bb.y0) * 2 + 1); + float zs = 1.0f / ((bb.z1 - bb.z0) * 2 + 1); + int hits = 0; + int count = 0; + for (float xx = 0; xx <= 1; xx += xs) + for (float yy = 0; yy <= 1; yy += ys) + for (float zz = 0; zz <= 1; zz += zs) { + float x = bb.x0 + (bb.x1 - bb.x0) * xx; + float y = bb.y0 + (bb.y1 - bb.y0) * yy; + float z = bb.z0 + (bb.z1 - bb.z0) * zz; + if (!clip(Vec3(x, y, z), center).isHit()) hits++; + count++; + } + + return hits / (float) count; +} + +bool Level::isSolidBlockingTile(int x, int y, int z) +{ + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile == NULL) return false; + return tile->material->isSolidBlocking() && tile->isCubeShaped(); +} + +bool Level::isSolidRenderTile(int x, int y, int z) { + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile == NULL) return false; + return tile->isSolidRender(); +} + +void Level::extinguishFire(int x, int y, int z, int face) { + switch (face) { + case Facing::DOWN : y--; break; + case Facing::UP : y++; break; + case Facing::NORTH: z--; break; + case Facing::SOUTH: z++; break; + case Facing::WEST : x--; break; + case Facing::EAST : x++; break; + } + + if (getTile(x, y, z) == ((Tile*)Tile::fire)->id) { + //playSound(x + 0.5f, y + 0.5f, z + 0.5f, "random.fizz", 0.5f, 2.6f + (random.nextFloat() - random.nextFloat()) * 0.8f); + setTile(x, y, z, 0); + } +} +// String gatherStats() { +// return "All: " + this.entities.size(); +// } +// +// String gatherChunkSourceStats() { +// return chunkSource.gatherStats(); +// } +// +TileEntity* Level::getTileEntity(int x, int y, int z) { + LevelChunk* lc = getChunk(x >> 4, z >> 4); + if (!lc) return NULL; + + if (TileEntity* tileEntity = lc->getTileEntity(x & 15, y, z & 15)) + return tileEntity; + + for (unsigned int i = 0; i < pendingTileEntities.size(); ++i) { + TileEntity* e = pendingTileEntities[i]; + if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) + return e; + } + return NULL; +} + +void Level::setTileEntity(int x, int y, int z, TileEntity* tileEntity) { + if (!tileEntity || tileEntity->isRemoved()) + return; + + if (updatingTileEntities) { + tileEntity->x = x; + tileEntity->y = y; + tileEntity->z = z; + pendingTileEntities.push_back(tileEntity); + } else { + tileEntities.push_back(tileEntity); + + LevelChunk* lc = getChunk(x >> 4, z >> 4); + if (lc != NULL) lc->setTileEntity(x & 15, y, z & 15, tileEntity); + } +} + +void Level::removeTileEntity(int x, int y, int z) { + TileEntity* te = getTileEntity(x, y, z); + if (te && updatingTileEntities) { + te->setRemoved(); + Util::remove(pendingTileEntities, te); + } else { + LevelChunk* lc = getChunk(x >> 4, z >> 4); + if (lc) lc->removeTileEntity(x & 15, y, z & 15); + + if (te) { + Util::remove(pendingTileEntities, te); + Util::remove(tileEntities, te); + delete te; + } + } +} + + +// +// void forceSave(ProgressListener progressListener) { +// save(true, progressListener); +// } +// + +int Level::getLightsToUpdate() { + return _lightUpdates.size(); +} + +bool Level::updateLights() { + if (_maxRecurse >= 50) { + return false; + } + //static int _MaxSize = 0; + _maxRecurse++; + //try { + int max = 500; + while ((int)_lightUpdates.size() > 0) { + if (--max <= 0) + { + _maxRecurse--; + return true; + } + LightUpdate l = _lightUpdates.back(); + _lightUpdates.pop_back(); + l.update(this); + //if ((int)_lightUpdates.size() > _MaxSize) + //{ + // LOGI("MAX_updsize_light: %d (%d)\n", _lightUpdates.size(), _MaxSize); + // _MaxSize = _lightUpdates.size(); + //} + } + _maxRecurse--; + return false; + //} finally { + //maxRecurse--; + //} +} + +void Level::setUpdateLights(bool doUpdate) { + _updateLights = doUpdate; +} + +void Level::updateLight(const LightLayer& layer, int x0, int y0, int z0, int x1, int y1, int z1) { + updateLight(layer, x0, y0, z0, x1, y1, z1, true); +} + +static int maxLoop = 0; + +void Level::updateLight(const LightLayer& layer, int x0, int y0, int z0, int x1, int y1, int z1, bool join) { + if ((dimension->hasCeiling && &layer == &LightLayer::Sky) || !_updateLights) return; + + maxLoop++; + //if (x0 < -5 || z0 < -5) LOGI("x, z: %d, %d\n", x0, z0); + if (maxLoop == 50) { + maxLoop--; + return; + } + int xm = (x1 + x0) / 2; + int zm = (z1 + z0) / 2; + if (!hasChunkAt(xm, Level::DEPTH / 2, zm)) { + maxLoop--; + return; + } + if (getChunkAt(xm, zm)->isEmpty()) + { + maxLoop--; + return; + } + int count = _lightUpdates.size(); + if (join) { + int toCheck = 5; + if (toCheck > count) toCheck = count; + for (int i = 0; i < toCheck; i++) { + LightUpdate& last = _lightUpdates[_lightUpdates.size() - i - 1]; + if (last.layer == &layer && last.expandToContain(x0, y0, z0, x1, y1, z1)) { + maxLoop--; + return; + } + } + } + _lightUpdates.push_back(LightUpdate(layer, x0, y0, z0, x1, y1, z1)); + int max = 1000000; + if ((int)_lightUpdates.size() > max) { + LOGI("More than %d updates, aborting lighting updates\n", max); + _lightUpdates.clear(); + } + maxLoop--; +} +// +// // int xxo, yyo, zzo; +// +bool Level::updateSkyBrightness() { + int newDark = this->getSkyDarken(1); + if (newDark != skyDarken) { + skyDarken = newDark; + return true; + } + return false; +} + +void Level::setSpawnSettings(bool spawnEnemies, bool spawnFriendlies) { + //this->spawnEnemies = spawnEnemies; + //this->spawnFriendlies = spawnFriendlies; +} + +void Level::animateTick(int xt, int yt, int zt) { + int r = 16; + Random animateRandom; + + for (int i = 0; i < 100; i++) { + int x = xt + random.nextInt(r) - random.nextInt(r); + int y = yt + random.nextInt(r) - random.nextInt(r); + int z = zt + random.nextInt(r) - random.nextInt(r); + int t = getTile(x, y, z); + if (t > 0) { + Tile::tiles[t]->animateTick(this, x, y, z, &animateRandom); + } + } +} + +EntityList& Level::getEntities(Entity* except, const AABB& bb) { + _es.clear(); + int xc0 = Mth::floor((bb.x0 - 2) / 16); + int xc1 = Mth::floor((bb.x1 + 2) / 16); + int zc0 = Mth::floor((bb.z0 - 2) / 16); + int zc1 = Mth::floor((bb.z1 + 2) / 16); + for (int xc = xc0; xc <= xc1; xc++) + for (int zc = zc0; zc <= zc1; zc++) { + if (hasChunk(xc, zc)) { + getChunk(xc, zc)->getEntities(except, bb, _es); + } + } + return _es; +} + +// List getEntitiesOfClass(Class baseClass, AABB bb) { +// int xc0 = Mth.floor((bb.x0 - 2) / 16); +// int xc1 = Mth.floor((bb.x1 + 2) / 16); +// int zc0 = Mth.floor((bb.z0 - 2) / 16); +// int zc1 = Mth.floor((bb.z1 + 2) / 16); +// List es = new ArrayList(); +// for (int xc = xc0; xc <= xc1; xc++) +// for (int zc = zc0; zc <= zc1; zc++) { +// if (hasChunk(xc, zc)) { +// getChunk(xc, zc).getEntitiesOfClass(baseClass, bb, es); +// } +// } +// return es; +// } + +const EntityList& Level::getAllEntities() { + return entities; +} + +// int countInstanceOf(Class clas) { +// int count = 0; +// for (int i = 0; i < entities.size(); i++) { +// Entity e = entities.get(i); +// if (clas.isAssignableFrom(e.getClass())) count++; +// } +// return count; +// } +// +/* +void Level::addEntities(const EntityList& list) { + entities.insert(entities.end(), list.begin(), list.end()); + for (int j = 0; j < (int)list.size(); j++) { + entityAdded(list[j]); + } +} +*/ + +//void Level::removeEntities(const EntityList& list) { +// _entitiesToRemove.insert(_entitiesToRemove.end(), list.begin(), list.end()); +//} + +void Level::prepare() { + while (_chunkSource->tick()) + ; +} + +bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities,unsigned char face) { + int targetType = getTile(x, y, z); + const Tile* targetTile = Tile::tiles[targetType]; + Tile* tile = Tile::tiles[tileId]; + + AABB* aabb = tile->getAABB(this, x, y, z); + if (ignoreEntities) aabb = NULL; + if (aabb != NULL && !isUnobstructed(*aabb)) return false; + if (targetTile == Tile::water || targetTile == Tile::calmWater || targetTile == Tile::lava || targetTile == Tile::calmLava || targetTile == (Tile*)(Tile::fire) || targetTile == Tile::topSnow) targetTile = NULL; + if (tileId > 0 && targetTile == NULL) { + if (tile->mayPlace(this, x, y, z, face)) { + return true; + } + } + + return false; +} + +int Level::getSeaLevel() { + return SEA_LEVEL; +} + +bool Level::getDirectSignal(int x, int y, int z, int dir) { + int t = getTile(x, y, z); + if (t == 0) return false; + return Tile::tiles[t]->getDirectSignal(this, x, y, z, dir); +} + +bool Level::hasDirectSignal(int x, int y, int z) { + if (getDirectSignal(x, y - 1, z, 0)) return true; + if (getDirectSignal(x, y + 1, z, 1)) return true; + if (getDirectSignal(x, y, z - 1, 2)) return true; + if (getDirectSignal(x, y, z + 1, 3)) return true; + if (getDirectSignal(x - 1, y, z, 4)) return true; + if (getDirectSignal(x + 1, y, z, 5)) return true; + return false; +} + +bool Level::getSignal(int x, int y, int z, int dir) { + if (isSolidBlockingTile(x, y, z)) { + return hasDirectSignal(x, y, z); + } + int t = getTile(x, y, z); + if (t == 0) return false; + return Tile::tiles[t]->getSignal(this, x, y, z, dir); +} + +bool Level::hasNeighborSignal(int x, int y, int z) { + if (getSignal(x, y - 1, z, 0)) return true; + if (getSignal(x, y + 1, z, 1)) return true; + if (getSignal(x, y, z - 1, 2)) return true; + if (getSignal(x, y, z + 1, 3)) return true; + if (getSignal(x - 1, y, z, 4)) return true; + if (getSignal(x + 1, y, z, 5)) return true; + return false; +} + +// void checkSession() { +// levelStorage.checkSession(); +// } +// +void Level::setTime(long time) { + this->levelData.setTime(time); +} + +long Level::getSeed() { + return levelData.getSeed(); +} + +long Level::getTime() { + return levelData.getTime(); +} + +Pos Level::getSharedSpawnPos() { + return Pos(levelData.getXSpawn(), levelData.getYSpawn(), levelData.getZSpawn()); +} + +void Level::setSpawnPos(Pos spawnPos) { + levelData.setSpawn(spawnPos.x, spawnPos.y, spawnPos.z); +} + +/* +void Level::ensureAdded(Entity* entity) { + int xc = Mth::floor(entity->x / 16); + int zc = Mth::floor(entity->z / 16); + int r = 2; + for (int x = xc - r; x <= xc + r; x++) { + for (int z = zc - r; z <= zc + r; z++) { + this->getChunk(x, z); + } + } + + if (std::find(entities.begin(), entities.end(), entity) == entities.end()) { + entities.push_back(entity); + } +} +*/ + +bool Level::mayInteract(Player* player, int xt, int yt, int zt) { + return true; +} + +void Level::broadcastEntityEvent(Entity* e, char eventId) { + if (isClientSide) return; + + EntityEventPacket packet(e->entityId, eventId); + raknetInstance->send(packet); +} + +/* +void Level::removeAllPendingEntityRemovals() { + //Util::removeAll(entities, _entitiesToRemove); + // //entities.removeAll(entitiesToRemove); + // for (int j = 0; j < (int)_entitiesToRemove.size(); j++) { + // Entity* e = _entitiesToRemove[j]; + // int xc = e->xChunk; + // int zc = e->zChunk; + // if (e->inChunk && hasChunk(xc, zc)) { + // getChunk(xc, zc)->removeEntity(e); + // } + // } + + // for (unsigned int j = 0; j < _entitiesToRemove.size(); j++) { + // entityRemoved(_entitiesToRemove[j]); + // } + // _entitiesToRemove.clear(); + + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + + if (e->removed) { + int xc = e->xChunk; + int zc = e->zChunk; + if (e->inChunk && hasChunk(xc, zc)) { + getChunk(xc, zc)->removeEntity(e); + } + entities.erase( entities.begin() + (i--) ); + entityRemoved(e); + } + } +} +*/ + +ChunkSource* Level::getChunkSource() { + return _chunkSource; +} + +// void tileEvent(int x, int y, int z, int b0, int b1) { +// int t = getTile(x, y, z); +// if (t > 0) Tile.tiles[t].triggerEvent(this, x, y, z, b0, b1); +// } + +LevelStorage* Level::getLevelStorage() { + return levelStorage; +} + +LevelData* Level::getLevelData() { + return &levelData; +} + +void Level::takePicture( TripodCamera* cam, Entity* e ) +{ + for (unsigned int i = 0; i < _listeners.size(); ++i) + _listeners[i]->takePicture(cam, e); +} + +int Level::getEntitiesOfType( int entityType, const AABB& bb, EntityList& list ) +{ + int xc0 = Mth::floor((bb.x0 - 2) / 16); + int xc1 = Mth::floor((bb.x1 + 2) / 16); + int zc0 = Mth::floor((bb.z0 - 2) / 16); + int zc1 = Mth::floor((bb.z1 + 2) / 16); + int count = -(int)list.size(); + for (int xc = xc0; xc <= xc1; xc++) + for (int zc = zc0; zc <= zc1; zc++) { + if (hasChunk(xc, zc)) { + getChunk(xc, zc)->getEntitiesOfType(entityType, bb, list); + } + } + return list.size() - count; +} + +int Level::getEntitiesOfClass( int type, const AABB& bb, EntityList& list ) { + int xc0 = Mth::floor((bb.x0 - 2) / 16); + int xc1 = Mth::floor((bb.x1 + 2) / 16); + int zc0 = Mth::floor((bb.z0 - 2) / 16); + int zc1 = Mth::floor((bb.z1 + 2) / 16); + int count = -(int)list.size(); + for (int xc = xc0; xc <= xc1; xc++) + for (int zc = zc0; zc <= zc1; zc++) { + if (hasChunk(xc, zc)) { + getChunk(xc, zc)->getEntitiesOfClass(type, bb, list); + } + } + return list.size() - count; +} + +int Level::countInstanceOfType( int typeId ) { + int n = 0; + for (unsigned int i = 0; i < entities.size(); ++i) + if (typeId == entities[i]->getEntityTypeId()) + ++n; + return n; +} + +int Level::countInstanceOfBaseType( int baseTypeId ) { + if (baseTypeId < MobTypes::BaseEnemy || baseTypeId > MobTypes::BaseWaterCreature) { + LOGE("Bad typeId sent to Level::countInstanceOf. Note that only Base types (MobTypes::Base*) are supported for now.\n"); + return -1; + } + + int n = 0; + for (unsigned int i = 0; i < entities.size(); ++i) + if (baseTypeId == entities[i]->getCreatureBaseType()) + ++n; + return n; +} + +void Level::dispatchEntityData( Entity* e ) +{ + if (isClientSide) return; + _pendingEntityData.insert(std::make_pair(e->entityId, e)); +} + +void Level::saveGame() +{ + if (levelStorage) { + levelStorage->saveGame(this); + saveLevelData(); + } +} + +void Level::loadEntities() +{ + if (levelStorage) + levelStorage->loadEntities(this, NULL); +} + +void Level::updateSkyDarken() +{ + if (updateSkyBrightness()) + for (unsigned i = 0; i < _listeners.size(); i++) { + _listeners[i]->skyColorChanged(); + } +} + +void Level::removePlayer( Player* player ) +{ + for (unsigned int i = 0; i < players.size(); ++i) + if (players[i] == player) { + players.erase( players.begin() + i ); + } +} + +int Level::isNightMode() { + return _nightMode; +} + +void Level::setNightMode( bool isNightMode ) { + _nightMode = isNightMode; +} + +bool Level::inRange( int x, int y, int z ) { + return x >= 0 && x < LEVEL_WIDTH + && y >= 0 && y < LEVEL_HEIGHT + && z >= 0 && z < LEVEL_DEPTH; +} + +// +// AdventureSettings +// +AdventureSettings::AdventureSettings() +: doTickTime(true), + noPvP(false), + noPvM(false), + noMvP(false), + immutableWorld(false), + showNameTags(true) +{ +} diff --git a/src/world/level/Level.h b/src/world/level/Level.hpp similarity index 97% rename from src/world/level/Level.h rename to src/world/level/Level.hpp index 9827e9c..c09a211 100755 --- a/src/world/level/Level.h +++ b/src/world/level/Level.hpp @@ -5,19 +5,19 @@ #include #include -//#include "world/Difficulty.h" +//#include "world/Difficulty.hpp" -#include "LevelSettings.h" -#include "LevelConstants.h" -#include "ChunkPos.h" -#include "TickNextTickData.h" -#include "storage/LevelData.h" -#include "LightUpdate.h" -#include "LevelSource.h" -#include "../Pos.h" -#include "../../SharedConstants.h" +#include "LevelSettings.hpp" +#include "LevelConstants.hpp" +#include "ChunkPos.hpp" +#include "TickNextTickData.hpp" +#include "storage/LevelData.hpp" +#include "LightUpdate.hpp" +#include "LevelSource.hpp" +#include "world/Pos.hpp" +#include "SharedConstants.hpp" -#include "biome/Biome.h" +#include "biome/Biome.hpp" class BiomeSource; class Dimension; diff --git a/src/world/level/LevelConstants.h b/src/world/level/LevelConstants.hpp similarity index 100% rename from src/world/level/LevelConstants.h rename to src/world/level/LevelConstants.hpp diff --git a/src/world/level/LevelListener.h b/src/world/level/LevelListener.hpp similarity index 97% rename from src/world/level/LevelListener.h rename to src/world/level/LevelListener.hpp index 4c7a281..b6517c3 100755 --- a/src/world/level/LevelListener.h +++ b/src/world/level/LevelListener.hpp @@ -3,7 +3,7 @@ //package net.minecraft.world.level; #include -#include "../entity/EntityTypes.h" +#include "world/entity/EntityTypes.hpp" class Entity; class TripodCamera; diff --git a/src/world/level/LevelSettings.h b/src/world/level/LevelSettings.hpp similarity index 100% rename from src/world/level/LevelSettings.h rename to src/world/level/LevelSettings.hpp diff --git a/src/world/level/LevelSource.h b/src/world/level/LevelSource.hpp similarity index 100% rename from src/world/level/LevelSource.h rename to src/world/level/LevelSource.hpp diff --git a/src/world/level/LightLayer.cpp b/src/world/level/LightLayer.cpp index f8e9295..2bb1866 100755 --- a/src/world/level/LightLayer.cpp +++ b/src/world/level/LightLayer.cpp @@ -1,4 +1,4 @@ -#include "LightLayer.h" - -const LightLayer LightLayer::Sky(15); -const LightLayer LightLayer::Block(0); +#include "LightLayer.hpp" + +const LightLayer LightLayer::Sky(15); +const LightLayer LightLayer::Block(0); diff --git a/src/world/level/LightLayer.h b/src/world/level/LightLayer.hpp similarity index 100% rename from src/world/level/LightLayer.h rename to src/world/level/LightLayer.hpp diff --git a/src/world/level/LightUpdate.cpp b/src/world/level/LightUpdate.cpp index ce26f8d..809bb2a 100755 --- a/src/world/level/LightUpdate.cpp +++ b/src/world/level/LightUpdate.cpp @@ -1,194 +1,194 @@ -#include "Level.h" -#include "LightUpdate.h" -#include "tile/Tile.h" - -//LightUpdate::LightUpdate() -//: -// layer(&LightLayer::Sky), -// x0(0), -// y0(0), -// z0(0), -// x1(1), -// y1(1), -// z1(1) -//{} // for using std::set - -LightUpdate::LightUpdate(const LightUpdate* t) -: - layer(t->layer), - x0(t->x0), - y0(t->y0), - z0(t->z0), - x1(t->x1), - y1(t->y1), - z1(t->z1) -{ - -} - -LightUpdate::LightUpdate(const LightUpdate& t) -: - layer(t.layer), - x0(t.x0), - y0(t.y0), - z0(t.z0), - x1(t.x1), - y1(t.y1), - z1(t.z1) -{ - -} - -LightUpdate::LightUpdate(const LightLayer& _layer, int _x0, int _y0, int _z0, int _x1, int _y1, int _z1) -: - layer(&_layer), - x0(_x0), - y0(_y0), - z0(_z0), - x1(_x1), - y1(_y1), - z1(_z1) -{ -} - -void LightUpdate::operator=(const LightUpdate* t) -{ - layer = t->layer; - x0 = t->x0; - y0 = t->y0; - z0 = t->z0; - x1 = t->x1; - y1 = t->y1; - z1 = t->z1; -} - -void LightUpdate::update(Level* level) -{ - int xd = (x1 - x0) + 1; - int yd = (y1 - y0) + 1; - int zd = (z1 - z0) + 1; - int size = xd * yd * zd; - if (size > 16 * 16 * 128) { - //System.out.println("Light too large, skipping!"); - return; - } - - - int lastxc = 0; - int lastzc = 0; - bool hasLast = false; - bool lastOk = false; - - for (int x = x0; x <= x1; x++) - for (int z = z0; z <= z1; z++) { - int xc = x >> 4; - int zc = z >> 4; - bool ok = false; - - if (hasLast && xc == lastxc && zc == lastzc) { - ok = lastOk; - } else { - ok = level->hasChunksAt(x, 0, z, 1); - if (ok) { - LevelChunk* lc = level->getChunk(x >> 4, z >> 4); - if (lc->isEmpty()) ok = false; - } - lastOk = ok; - lastxc = xc; - lastzc = zc; - } - - if (ok) { - - if (y0 < 0) y0 = 0; - if (y1 >= Level::DEPTH) y1 = Level::DEPTH - 1; - - for (int y = y0; y <= y1; y++) { - int old = level->getBrightness(*layer, x, y, z); - - int target = 0; - int tile = level->getTile(x, y, z); - int block = Tile::lightBlock[tile]; - if (block == 0) block = 1; - int emit = 0; - if (layer == &LightLayer::Sky) { - if (level->isSkyLit(x, y, z)) emit = 15; - } else if (layer == &LightLayer::Block) { - emit = Tile::lightEmission[tile]; - } - - if (block >= 15 && emit == 0) { - target = 0; - } else { - - int d0 = level->getBrightness(*layer, x - 1, y, z); - int d1 = level->getBrightness(*layer, x + 1, y, z); - int d2 = level->getBrightness(*layer, x, y - 1, z); - int d3 = level->getBrightness(*layer, x, y + 1, z); - int d4 = level->getBrightness(*layer, x, y, z - 1); - int d5 = level->getBrightness(*layer, x, y, z + 1); - - target = d0; - if (d1 > target) target = d1; - if (d2 > target) target = d2; - if (d3 > target) target = d3; - if (d4 > target) target = d4; - if (d5 > target) target = d5; - target -= block; - if (target < 0) target = 0; - - if (emit > target) target = emit; - } - - - if (old != target) { - level->setBrightness(*layer, x, y, z, target); - int t = target - 1; - if (t < 0) t = 0; - level->updateLightIfOtherThan(*layer, x - 1, y, z, t); - level->updateLightIfOtherThan(*layer, x, y - 1, z, t); - level->updateLightIfOtherThan(*layer, x, y, z - 1, t); - - if (x + 1 >= x1) level->updateLightIfOtherThan(*layer, x + 1, y, z, t); - if (y + 1 >= y1) level->updateLightIfOtherThan(*layer, x, y + 1, z, t); - if (z + 1 >= z1) level->updateLightIfOtherThan(*layer, x, y, z + 1, t); - } - } - } - } -} - -bool LightUpdate::expandToContain(int _x0, int _y0, int _z0, int _x1, int _y1, int _z1) { - if (_x0 >= x0 && _y0 >= y0 && _z0 >= z0 && _x1 <= x1 && _y1 <= y1 && _z1 <= z1) return true; - - int r = 1; - if (_x0 >= x0 - r && _y0 >= y0 - r && _z0 >= z0 - r && _x1 <= x1 + r && _y1 <= y1 + r && _z1 <= z1 + r) { - int xs = x1 - x0; - int ys = y1 - y0; - int zs = z1 - z0; - - if (_x0 > x0) _x0 = x0; - if (_y0 > y0) _y0 = y0; - if (_z0 > z0) _z0 = z0; - if (_x1 < x1) _x1 = x1; - if (_y1 < y1) _y1 = y1; - if (_z1 < z1) _z1 = z1; - - int _xs = _x1 - _x0; - int _ys = _y1 - _y0; - int _zs = _z1 - _z0; - - int os = xs * ys * zs; - int ns = _xs * _ys * _zs; - if (ns - os <= 2) { - x0 = _x0; - y0 = _y0; - z0 = _z0; - x1 = _x1; - y1 = _y1; - z1 = _z1; - return true; - } - } - return false; +#include "Level.hpp" +#include "LightUpdate.hpp" +#include "tile/Tile.hpp" + +//LightUpdate::LightUpdate() +//: +// layer(&LightLayer::Sky), +// x0(0), +// y0(0), +// z0(0), +// x1(1), +// y1(1), +// z1(1) +//{} // for using std::set + +LightUpdate::LightUpdate(const LightUpdate* t) +: + layer(t->layer), + x0(t->x0), + y0(t->y0), + z0(t->z0), + x1(t->x1), + y1(t->y1), + z1(t->z1) +{ + +} + +LightUpdate::LightUpdate(const LightUpdate& t) +: + layer(t.layer), + x0(t.x0), + y0(t.y0), + z0(t.z0), + x1(t.x1), + y1(t.y1), + z1(t.z1) +{ + +} + +LightUpdate::LightUpdate(const LightLayer& _layer, int _x0, int _y0, int _z0, int _x1, int _y1, int _z1) +: + layer(&_layer), + x0(_x0), + y0(_y0), + z0(_z0), + x1(_x1), + y1(_y1), + z1(_z1) +{ +} + +void LightUpdate::operator=(const LightUpdate* t) +{ + layer = t->layer; + x0 = t->x0; + y0 = t->y0; + z0 = t->z0; + x1 = t->x1; + y1 = t->y1; + z1 = t->z1; +} + +void LightUpdate::update(Level* level) +{ + int xd = (x1 - x0) + 1; + int yd = (y1 - y0) + 1; + int zd = (z1 - z0) + 1; + int size = xd * yd * zd; + if (size > 16 * 16 * 128) { + //System.out.println("Light too large, skipping!"); + return; + } + + + int lastxc = 0; + int lastzc = 0; + bool hasLast = false; + bool lastOk = false; + + for (int x = x0; x <= x1; x++) + for (int z = z0; z <= z1; z++) { + int xc = x >> 4; + int zc = z >> 4; + bool ok = false; + + if (hasLast && xc == lastxc && zc == lastzc) { + ok = lastOk; + } else { + ok = level->hasChunksAt(x, 0, z, 1); + if (ok) { + LevelChunk* lc = level->getChunk(x >> 4, z >> 4); + if (lc->isEmpty()) ok = false; + } + lastOk = ok; + lastxc = xc; + lastzc = zc; + } + + if (ok) { + + if (y0 < 0) y0 = 0; + if (y1 >= Level::DEPTH) y1 = Level::DEPTH - 1; + + for (int y = y0; y <= y1; y++) { + int old = level->getBrightness(*layer, x, y, z); + + int target = 0; + int tile = level->getTile(x, y, z); + int block = Tile::lightBlock[tile]; + if (block == 0) block = 1; + int emit = 0; + if (layer == &LightLayer::Sky) { + if (level->isSkyLit(x, y, z)) emit = 15; + } else if (layer == &LightLayer::Block) { + emit = Tile::lightEmission[tile]; + } + + if (block >= 15 && emit == 0) { + target = 0; + } else { + + int d0 = level->getBrightness(*layer, x - 1, y, z); + int d1 = level->getBrightness(*layer, x + 1, y, z); + int d2 = level->getBrightness(*layer, x, y - 1, z); + int d3 = level->getBrightness(*layer, x, y + 1, z); + int d4 = level->getBrightness(*layer, x, y, z - 1); + int d5 = level->getBrightness(*layer, x, y, z + 1); + + target = d0; + if (d1 > target) target = d1; + if (d2 > target) target = d2; + if (d3 > target) target = d3; + if (d4 > target) target = d4; + if (d5 > target) target = d5; + target -= block; + if (target < 0) target = 0; + + if (emit > target) target = emit; + } + + + if (old != target) { + level->setBrightness(*layer, x, y, z, target); + int t = target - 1; + if (t < 0) t = 0; + level->updateLightIfOtherThan(*layer, x - 1, y, z, t); + level->updateLightIfOtherThan(*layer, x, y - 1, z, t); + level->updateLightIfOtherThan(*layer, x, y, z - 1, t); + + if (x + 1 >= x1) level->updateLightIfOtherThan(*layer, x + 1, y, z, t); + if (y + 1 >= y1) level->updateLightIfOtherThan(*layer, x, y + 1, z, t); + if (z + 1 >= z1) level->updateLightIfOtherThan(*layer, x, y, z + 1, t); + } + } + } + } +} + +bool LightUpdate::expandToContain(int _x0, int _y0, int _z0, int _x1, int _y1, int _z1) { + if (_x0 >= x0 && _y0 >= y0 && _z0 >= z0 && _x1 <= x1 && _y1 <= y1 && _z1 <= z1) return true; + + int r = 1; + if (_x0 >= x0 - r && _y0 >= y0 - r && _z0 >= z0 - r && _x1 <= x1 + r && _y1 <= y1 + r && _z1 <= z1 + r) { + int xs = x1 - x0; + int ys = y1 - y0; + int zs = z1 - z0; + + if (_x0 > x0) _x0 = x0; + if (_y0 > y0) _y0 = y0; + if (_z0 > z0) _z0 = z0; + if (_x1 < x1) _x1 = x1; + if (_y1 < y1) _y1 = y1; + if (_z1 < z1) _z1 = z1; + + int _xs = _x1 - _x0; + int _ys = _y1 - _y0; + int _zs = _z1 - _z0; + + int os = xs * ys * zs; + int ns = _xs * _ys * _zs; + if (ns - os <= 2) { + x0 = _x0; + y0 = _y0; + z0 = _z0; + x1 = _x1; + y1 = _y1; + z1 = _z1; + return true; + } + } + return false; } \ No newline at end of file diff --git a/src/world/level/LightUpdate.h b/src/world/level/LightUpdate.hpp similarity index 90% rename from src/world/level/LightUpdate.h rename to src/world/level/LightUpdate.hpp index 028e6e2..207e5e0 100755 --- a/src/world/level/LightUpdate.h +++ b/src/world/level/LightUpdate.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level; -#include "LightLayer.h" -#include "chunk/LevelChunk.h" +#include "LightLayer.hpp" +#include "chunk/LevelChunk.hpp" class Level; diff --git a/src/world/level/MobSpawner.cpp b/src/world/level/MobSpawner.cpp index 5e5dc90..3330773 100755 --- a/src/world/level/MobSpawner.cpp +++ b/src/world/level/MobSpawner.cpp @@ -1,284 +1,284 @@ -#include "MobSpawner.h" - -#include - -#include "Level.h" -#include "biome/Biome.h" -#include "material/Material.h" -#include "../entity/EntityTypes.h" -#include "../entity/MobFactory.h" -#include "../entity/MobCategory.h" -#include "../entity/player/Player.h" - -//#include "../entity/animal/Sheep.h" -//#include "tile/BedTile.h" - -std::map MobSpawner::chunksToPoll; - -static int _bedEnemies[] = { - MobTypes::Spider, - MobTypes::Zombie, - MobTypes::Skeleton, - MobTypes::PigZombie -}; - -static const std::vector bedEnemies(_bedEnemies, _bedEnemies + sizeof(_bedEnemies) / sizeof(_bedEnemies[0])); - -/*static*/ -int MobSpawner::tick(Level* level, bool spawnEnemies, bool spawnFriendlies) { - - //return 0; - - if (!spawnEnemies && !spawnFriendlies) { - return 0; - } - - chunksToPoll.clear(); - // Add all chunks as a quick-and-dirty test - // (The code above is the same as in the java version) - // This code goes over the whole map one "row" at a time - - // Spawn friendlies == loop over whole map, and disable Monster spawning this tick - if (spawnFriendlies) { - spawnEnemies = false; - for (int i = 0; i < 256; ++i) - chunksToPoll.insert( std::make_pair( ChunkPos(i>>4, i&15), false) ); - - } else { - // Only spawn mobs, check around one player per tick (@todo: optimize the "count instances of"?) - static unsigned int _pid = 0; - if (++_pid >= level->players.size()) _pid = 0; - if (level->players.size()) { - Player* p = level->players[_pid]; - int xx = Mth::floor(p->x / 16); - int zz = Mth::floor(p->z / 16); - int r = 128 / 16; - for (int x = -r; x <= r; x++) - for (int z = -r; z <= r; z++) { - const int cx = xx + x; - const int cz = zz + z; - if (cx >= 0 && cx < 16 && cz >= 0 && cz < 16) - chunksToPoll.insert(std::make_pair(ChunkPos(cx, cz), false )); - } - } - } - - int count = 0; - Pos spawnPos = level->getSharedSpawnPos(); - - for (int i = 0; i < MobCategory::numValues; ++i) { - const MobCategory& mobCategory = *MobCategory::values[i]; - - if ((mobCategory.isFriendly() && !spawnFriendlies) || (!mobCategory.isFriendly() && !spawnEnemies)) - continue; - - int numMobs = level->countInstanceOfBaseType(mobCategory.getBaseClassId()); - if (numMobs > mobCategory.getMaxInstancesPerLevel()) - continue; - //LOGI("NumMobs: %d of Category: %d\n", numMobs, mobCategory.getBaseClassId()); -chunkLoop: - for(std::map::iterator it = chunksToPoll.begin(); it != chunksToPoll.end(); ++it) { - const ChunkPos& cp = it->first; - TilePos start = getRandomPosWithin(level, cp.x * 16, cp.z * 16); - int xStart = start.x; - int yStart = start.y; - int zStart = start.z; - - if (level->isSolidBlockingTile(xStart, yStart, zStart)) continue; - - if (level->getMaterial(xStart, yStart, zStart) != mobCategory.getSpawnPositionMaterial()) continue; - - int clusterSize = 0; - - for (int dd = 0; dd < 3; dd++) { - int x = xStart; - int y = yStart; - int z = zStart; - int ss = 6; - - Biome::MobSpawnerData currentMobType; - int maxCreatureCount = 999; - int currentCreatureCount = 0; - - for (int ll = 0; ll < 4; ll++) { - if (currentCreatureCount > maxCreatureCount) - break; - - x += level->random.nextInt(ss) - level->random.nextInt(ss); - y += level->random.nextInt(1) - level->random.nextInt(1); - z += level->random.nextInt(ss) - level->random.nextInt(ss); - // int y = heightMap[x + z * w] + 1; - - if (isSpawnPositionOk(mobCategory, level, x, y, z)) { - float xx = (float)x + 0.5f; - float yy = (float)y; - float zz = (float)z + 0.5f; - if (level->getNearestPlayer(xx, yy, zz, (float)MIN_SPAWN_DISTANCE) != NULL) { - continue; - } else { - float xd = xx - spawnPos.x; - float yd = yy - spawnPos.y; - float zd = zz - spawnPos.z; - float sd = xd * xd + yd * yd + zd * zd; - if (sd < MIN_SPAWN_DISTANCE * MIN_SPAWN_DISTANCE) { - continue; - } - } - - static Stopwatch sw; - sw.start(); - - if (!currentMobType.isValid()) { - currentMobType = level->getRandomMobSpawnAt(mobCategory, x, y, z); - if (!currentMobType.isValid()) - break; - - // Don't allow monster to spawn (much) more than their defined - // probability weight. - if (&mobCategory == &MobCategory::monster) { - int typeCount = level->countInstanceOfType(currentMobType.mobClassId); - int typeMax = (int)(1.5f * currentMobType.randomWeight * mobCategory.getMaxInstancesPerLevel()) / Biome::defaultTotalEnemyWeight; - //LOGI("Has %d (max %d) of type: %d\n", typeCount, typeMax, currentMobType.mobClassId); - if (typeCount >= typeMax) - break; - } - - maxCreatureCount = currentMobType.minCount + level->random.nextInt(1 + currentMobType.maxCount - currentMobType.minCount); - } - - Mob* tmp = MobFactory::getStaticTestMob(currentMobType.mobClassId, level); - if (!tmp) continue; - - tmp->moveTo(xx, yy, zz, 0, 0); - if (!tmp->canSpawn()) continue; - - Mob* mob = MobFactory::CreateMob(currentMobType.mobClassId, level); - if (!mob) continue; - - if (addMob(level, mob, xx, yy, zz, level->random.nextFloat() * 360, 0, false)) { - ++currentCreatureCount; - if (++clusterSize >= mob->getMaxSpawnClusterSize()) goto chunkLoop; - } - else - delete mob; - - count += clusterSize; - } - } - } - } - } - return count; -} - -/*static*/ -void MobSpawner::postProcessSpawnMobs(Level* level, Biome* biome, int xo, int zo, int cellWidth, int cellHeight, Random* random) { - - //return; - - Biome::MobList mobs = biome->getMobs(MobCategory::creature); - if (mobs.empty()) { - return; - } - - while (random->nextFloat() < biome->getCreatureProbability()) { - - Biome::MobSpawnerData* type = (Biome::MobSpawnerData*) WeighedRandom::getRandomItem(&level->random, mobs); - int count = type->minCount + random->nextInt(1 + type->maxCount - type->minCount); - - int x = xo + random->nextInt(cellWidth); - int z = zo + random->nextInt(cellHeight); - int startX = x, startZ = z; - - for (int c = 0; c < count; c++) { - bool success = false; - for (int attempts = 0; !success && attempts < 4; attempts++) { - // these mobs always spawn at the topmost position - int y = level->getTopSolidBlock(x, z); - if (isSpawnPositionOk(MobCategory::creature, level, x, y, z)) { - - float xx = (float)x + 0.5f; - float yy = (float)y; - float zz = (float)z + 0.5f; - - Mob* mob = MobFactory::CreateMob(type->mobClassId, level); - if (!mob) continue; - - // System.out.println("Placing night mob"); - mob->moveTo(xx, yy, zz, random->nextFloat() * 360, 0); - - level->addEntity(mob); - finalizeMobSettings(mob, level, xx, yy, zz); - success = true; - } - - x += random->nextInt(5) - random->nextInt(5); - z += random->nextInt(5) - random->nextInt(5); - while (x < xo || x >= (xo + cellWidth) || z < zo || z >= (zo + cellWidth)) { - x = startX + random->nextInt(5) - random->nextInt(5); - z = startZ + random->nextInt(5) - random->nextInt(5); - } - } - } - } -} - -/*static*/ -TilePos MobSpawner::getRandomPosWithin(Level* level, int xo, int zo) { - int x = xo + level->random.nextInt(16); - int y = level->random.nextInt(Level::DEPTH); //@note: level->depth); - int z = zo + level->random.nextInt(16); - - return TilePos(x, y, z); -} - -/*static*/ -bool MobSpawner::isSpawnPositionOk(const MobCategory& category, Level* level, int x, int y, int z) { - if (category.getSpawnPositionMaterial() == Material::water) { - return level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z); - } else { - return level->isSolidBlockingTile(x, y - 1, z) && !level->isSolidBlockingTile(x, y, z) && !level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z); - } -} - -/*static*/ -void MobSpawner::finalizeMobSettings(Mob* mob, Level* level, float xx, float yy, float zz) { - // @todo -// if (mob instanceof Spider && level->random->nextInt(100) == 0) { -// Skeleton skeleton = /*new*/ Skeleton(level); -// skeleton.moveTo(xx, yy, zz, mob.yRot, 0); -// level->addEntity(skeleton); -// skeleton.ride(mob); -// } else if (mob instanceof Sheep) { -// ((Sheep) mob).setColor(Sheep.getSheepColor(level->random)); -// } - - if (mob->getEntityTypeId() == MobTypes::Sheep) { - ((Sheep*) mob)->setColor(Sheep::getSheepColor(&level->random)); - } - - makeBabyMob(mob, 0.5f); -} - -/*static*/ -bool MobSpawner::addMob(Level* level, Mob* mob, float xx, float yy, float zz, float yRot, float xRot, bool force) -{ - mob->moveTo(xx, yy, zz, yRot, xRot); - - if (force || mob->canSpawn()) { - level->addEntity(mob); - finalizeMobSettings(mob, level, xx, yy, zz); - return true; - } else { - //LOGI("Couldn't add the entity\n"); - return false; - } -} - -void MobSpawner::makeBabyMob( Mob* mob, float probability ) { - static Random babyRandom(98495119L); - if (MobTypes::BaseCreature == mob->getCreatureBaseType()) { - if (babyRandom.nextFloat() < probability) - ((Animal*)mob)->setAge(-20 * 60 * SharedConstants::TicksPerSecond); - } -} +#include "MobSpawner.hpp" + +#include + +#include "Level.hpp" +#include "biome/Biome.hpp" +#include "material/Material.hpp" +#include "world/entity/EntityTypes.hpp" +#include "world/entity/MobFactory.hpp" +#include "world/entity/MobCategory.hpp" +#include "world/entity/player/Player.hpp" + +//#include "world/entity/animal/Sheep.hpp" +//#include "tile/BedTile.hpp" + +std::map MobSpawner::chunksToPoll; + +static int _bedEnemies[] = { + MobTypes::Spider, + MobTypes::Zombie, + MobTypes::Skeleton, + MobTypes::PigZombie +}; + +static const std::vector bedEnemies(_bedEnemies, _bedEnemies + sizeof(_bedEnemies) / sizeof(_bedEnemies[0])); + +/*static*/ +int MobSpawner::tick(Level* level, bool spawnEnemies, bool spawnFriendlies) { + + //return 0; + + if (!spawnEnemies && !spawnFriendlies) { + return 0; + } + + chunksToPoll.clear(); + // Add all chunks as a quick-and-dirty test + // (The code above is the same as in the java version) + // This code goes over the whole map one "row" at a time + + // Spawn friendlies == loop over whole map, and disable Monster spawning this tick + if (spawnFriendlies) { + spawnEnemies = false; + for (int i = 0; i < 256; ++i) + chunksToPoll.insert( std::make_pair( ChunkPos(i>>4, i&15), false) ); + + } else { + // Only spawn mobs, check around one player per tick (@todo: optimize the "count instances of"?) + static unsigned int _pid = 0; + if (++_pid >= level->players.size()) _pid = 0; + if (level->players.size()) { + Player* p = level->players[_pid]; + int xx = Mth::floor(p->x / 16); + int zz = Mth::floor(p->z / 16); + int r = 128 / 16; + for (int x = -r; x <= r; x++) + for (int z = -r; z <= r; z++) { + const int cx = xx + x; + const int cz = zz + z; + if (cx >= 0 && cx < 16 && cz >= 0 && cz < 16) + chunksToPoll.insert(std::make_pair(ChunkPos(cx, cz), false )); + } + } + } + + int count = 0; + Pos spawnPos = level->getSharedSpawnPos(); + + for (int i = 0; i < MobCategory::numValues; ++i) { + const MobCategory& mobCategory = *MobCategory::values[i]; + + if ((mobCategory.isFriendly() && !spawnFriendlies) || (!mobCategory.isFriendly() && !spawnEnemies)) + continue; + + int numMobs = level->countInstanceOfBaseType(mobCategory.getBaseClassId()); + if (numMobs > mobCategory.getMaxInstancesPerLevel()) + continue; + //LOGI("NumMobs: %d of Category: %d\n", numMobs, mobCategory.getBaseClassId()); +chunkLoop: + for(std::map::iterator it = chunksToPoll.begin(); it != chunksToPoll.end(); ++it) { + const ChunkPos& cp = it->first; + TilePos start = getRandomPosWithin(level, cp.x * 16, cp.z * 16); + int xStart = start.x; + int yStart = start.y; + int zStart = start.z; + + if (level->isSolidBlockingTile(xStart, yStart, zStart)) continue; + + if (level->getMaterial(xStart, yStart, zStart) != mobCategory.getSpawnPositionMaterial()) continue; + + int clusterSize = 0; + + for (int dd = 0; dd < 3; dd++) { + int x = xStart; + int y = yStart; + int z = zStart; + int ss = 6; + + Biome::MobSpawnerData currentMobType; + int maxCreatureCount = 999; + int currentCreatureCount = 0; + + for (int ll = 0; ll < 4; ll++) { + if (currentCreatureCount > maxCreatureCount) + break; + + x += level->random.nextInt(ss) - level->random.nextInt(ss); + y += level->random.nextInt(1) - level->random.nextInt(1); + z += level->random.nextInt(ss) - level->random.nextInt(ss); + // int y = heightMap[x + z * w] + 1; + + if (isSpawnPositionOk(mobCategory, level, x, y, z)) { + float xx = (float)x + 0.5f; + float yy = (float)y; + float zz = (float)z + 0.5f; + if (level->getNearestPlayer(xx, yy, zz, (float)MIN_SPAWN_DISTANCE) != NULL) { + continue; + } else { + float xd = xx - spawnPos.x; + float yd = yy - spawnPos.y; + float zd = zz - spawnPos.z; + float sd = xd * xd + yd * yd + zd * zd; + if (sd < MIN_SPAWN_DISTANCE * MIN_SPAWN_DISTANCE) { + continue; + } + } + + static Stopwatch sw; + sw.start(); + + if (!currentMobType.isValid()) { + currentMobType = level->getRandomMobSpawnAt(mobCategory, x, y, z); + if (!currentMobType.isValid()) + break; + + // Don't allow monster to spawn (much) more than their defined + // probability weight. + if (&mobCategory == &MobCategory::monster) { + int typeCount = level->countInstanceOfType(currentMobType.mobClassId); + int typeMax = (int)(1.5f * currentMobType.randomWeight * mobCategory.getMaxInstancesPerLevel()) / Biome::defaultTotalEnemyWeight; + //LOGI("Has %d (max %d) of type: %d\n", typeCount, typeMax, currentMobType.mobClassId); + if (typeCount >= typeMax) + break; + } + + maxCreatureCount = currentMobType.minCount + level->random.nextInt(1 + currentMobType.maxCount - currentMobType.minCount); + } + + Mob* tmp = MobFactory::getStaticTestMob(currentMobType.mobClassId, level); + if (!tmp) continue; + + tmp->moveTo(xx, yy, zz, 0, 0); + if (!tmp->canSpawn()) continue; + + Mob* mob = MobFactory::CreateMob(currentMobType.mobClassId, level); + if (!mob) continue; + + if (addMob(level, mob, xx, yy, zz, level->random.nextFloat() * 360, 0, false)) { + ++currentCreatureCount; + if (++clusterSize >= mob->getMaxSpawnClusterSize()) goto chunkLoop; + } + else + delete mob; + + count += clusterSize; + } + } + } + } + } + return count; +} + +/*static*/ +void MobSpawner::postProcessSpawnMobs(Level* level, Biome* biome, int xo, int zo, int cellWidth, int cellHeight, Random* random) { + + //return; + + Biome::MobList mobs = biome->getMobs(MobCategory::creature); + if (mobs.empty()) { + return; + } + + while (random->nextFloat() < biome->getCreatureProbability()) { + + Biome::MobSpawnerData* type = (Biome::MobSpawnerData*) WeighedRandom::getRandomItem(&level->random, mobs); + int count = type->minCount + random->nextInt(1 + type->maxCount - type->minCount); + + int x = xo + random->nextInt(cellWidth); + int z = zo + random->nextInt(cellHeight); + int startX = x, startZ = z; + + for (int c = 0; c < count; c++) { + bool success = false; + for (int attempts = 0; !success && attempts < 4; attempts++) { + // these mobs always spawn at the topmost position + int y = level->getTopSolidBlock(x, z); + if (isSpawnPositionOk(MobCategory::creature, level, x, y, z)) { + + float xx = (float)x + 0.5f; + float yy = (float)y; + float zz = (float)z + 0.5f; + + Mob* mob = MobFactory::CreateMob(type->mobClassId, level); + if (!mob) continue; + + // System.out.println("Placing night mob"); + mob->moveTo(xx, yy, zz, random->nextFloat() * 360, 0); + + level->addEntity(mob); + finalizeMobSettings(mob, level, xx, yy, zz); + success = true; + } + + x += random->nextInt(5) - random->nextInt(5); + z += random->nextInt(5) - random->nextInt(5); + while (x < xo || x >= (xo + cellWidth) || z < zo || z >= (zo + cellWidth)) { + x = startX + random->nextInt(5) - random->nextInt(5); + z = startZ + random->nextInt(5) - random->nextInt(5); + } + } + } + } +} + +/*static*/ +TilePos MobSpawner::getRandomPosWithin(Level* level, int xo, int zo) { + int x = xo + level->random.nextInt(16); + int y = level->random.nextInt(Level::DEPTH); //@note: level->depth); + int z = zo + level->random.nextInt(16); + + return TilePos(x, y, z); +} + +/*static*/ +bool MobSpawner::isSpawnPositionOk(const MobCategory& category, Level* level, int x, int y, int z) { + if (category.getSpawnPositionMaterial() == Material::water) { + return level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z); + } else { + return level->isSolidBlockingTile(x, y - 1, z) && !level->isSolidBlockingTile(x, y, z) && !level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z); + } +} + +/*static*/ +void MobSpawner::finalizeMobSettings(Mob* mob, Level* level, float xx, float yy, float zz) { + // @todo +// if (mob instanceof Spider && level->random->nextInt(100) == 0) { +// Skeleton skeleton = /*new*/ Skeleton(level); +// skeleton.moveTo(xx, yy, zz, mob.yRot, 0); +// level->addEntity(skeleton); +// skeleton.ride(mob); +// } else if (mob instanceof Sheep) { +// ((Sheep) mob).setColor(Sheep.getSheepColor(level->random)); +// } + + if (mob->getEntityTypeId() == MobTypes::Sheep) { + ((Sheep*) mob)->setColor(Sheep::getSheepColor(&level->random)); + } + + makeBabyMob(mob, 0.5f); +} + +/*static*/ +bool MobSpawner::addMob(Level* level, Mob* mob, float xx, float yy, float zz, float yRot, float xRot, bool force) +{ + mob->moveTo(xx, yy, zz, yRot, xRot); + + if (force || mob->canSpawn()) { + level->addEntity(mob); + finalizeMobSettings(mob, level, xx, yy, zz); + return true; + } else { + //LOGI("Couldn't add the entity\n"); + return false; + } +} + +void MobSpawner::makeBabyMob( Mob* mob, float probability ) { + static Random babyRandom(98495119L); + if (MobTypes::BaseCreature == mob->getCreatureBaseType()) { + if (babyRandom.nextFloat() < probability) + ((Animal*)mob)->setAge(-20 * 60 * SharedConstants::TicksPerSecond); + } +} diff --git a/src/world/level/MobSpawner.h b/src/world/level/MobSpawner.hpp similarity index 100% rename from src/world/level/MobSpawner.h rename to src/world/level/MobSpawner.hpp diff --git a/src/world/level/Region.cpp b/src/world/level/Region.cpp index c501912..2c9b91a 100755 --- a/src/world/level/Region.cpp +++ b/src/world/level/Region.cpp @@ -1,140 +1,140 @@ -#include "Region.h" -#include "chunk/LevelChunk.h" -#include "material/Material.h" -#include "tile/Tile.h" -#include "Level.h" - -Region::Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2) { - this->level = level; - - xc1 = x1 >> 4; - zc1 = z1 >> 4; - int xc2 = x2 >> 4; - int zc2 = z2 >> 4; - - size_x = xc2 - xc1 + 1; - size_z = zc2 - zc1 + 1; - chunks = new LevelChunk**[size_x]; - for (int i = 0; i < size_x; ++i) - chunks[i] = new LevelChunk*[size_z]; - - for (int xc = xc1; xc <= xc2; xc++) { - for (int zc = zc1; zc <= zc2; zc++) { - chunks[xc - xc1][zc - zc1] = level->getChunk(xc, zc); - } - } -} - -Region::~Region() { - for (int i = 0 ; i < size_x; ++i) - delete[] chunks[i]; - delete[] chunks; -} - -int Region::getTile(int x, int y, int z) { - if (y < 0) return 0; - if (y >= Level::DEPTH) return 0; - - int xc = (x >> 4) - xc1; - int zc = (z >> 4) - zc1; - - if (xc < 0 || xc >= size_x || zc < 0 || zc >= size_z) { - return 0; - } - - LevelChunk* lc = chunks[xc][zc]; - if (lc == NULL) return 0; - - return lc->getTile(x & 15, y, z & 15); -} - -bool Region::isEmptyTile( int x, int y, int z ) -{ - //return getTile(x, y, z) == 0; //@todo? - return Tile::tiles[getTile(x, y, z)] == NULL; -} - -//TileEntity getTileEntity(int x, int y, int z) { -// int xc = (x >> 4) - xc1; -// int zc = (z >> 4) - zc1; - -// return chunks[xc][zc].getTileEntity(x & 15, y, z & 15); -//} - -float Region::getBrightness(int x, int y, int z) { - return level->dimension->brightnessRamp[getRawBrightness(x, y, z)]; -} - -int Region::getRawBrightness(int x, int y, int z) { - return getRawBrightness(x, y, z, true); -} - -int Region::getRawBrightness(int x, int y, int z, bool propagate) { - if (x < -Level::MAX_LEVEL_SIZE || z < -Level::MAX_LEVEL_SIZE || x >= Level::MAX_LEVEL_SIZE || z > Level::MAX_LEVEL_SIZE) { - return Level::MAX_BRIGHTNESS; - } - - if (propagate) { - int id = getTile(x, y, z); - if (id == Tile::stoneSlabHalf->id || id == Tile::farmland->id) { - int br = getRawBrightness(x, y + 1, z, false); - int br1 = getRawBrightness(x + 1, y, z, false); - int br2 = getRawBrightness(x - 1, y, z, false); - int br3 = getRawBrightness(x, y, z + 1, false); - int br4 = getRawBrightness(x, y, z - 1, false); - if (br1 > br) br = br1; - if (br2 > br) br = br2; - if (br3 > br) br = br3; - if (br4 > br) br = br4; - return br; - } - } - - if (y < 0) return 0; - if (y >= Level::DEPTH) { - int br = Level::MAX_BRIGHTNESS - level->skyDarken; - if (br < 0) br = 0; - return br; - } - - int xc = (x >> 4) - xc1; - int zc = (z >> 4) - zc1; - - return chunks[xc][zc]->getRawBrightness(x & 15, y, z & 15, level->skyDarken); -} - -int Region::getData(int x, int y, int z) { - if (y < 0) return 0; - if (y >= Level::DEPTH) return 0; - int xc = (x >> 4) - xc1; - int zc = (z >> 4) - zc1; - - return chunks[xc][zc]->getData(x & 15, y, z & 15); -} - -const Material* Region::getMaterial(int x, int y, int z) { - int t = getTile(x, y, z); - if (t == 0) return Material::air; - return Tile::tiles[t]->material; -} - -bool Region::isSolidBlockingTile(int x, int y, int z) -{ - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; - return tile->material->isSolidBlocking() && tile->isCubeShaped(); -} - -bool Region::isSolidRenderTile(int x, int y, int z) { - Tile* tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; - return tile->isSolidRender(); -} - -Biome* Region::getBiome( int x, int z ) { - return level->getBiome(x, z); -} - -//BiomeSource getBiomeSource() { -// return level.getBiomeSource(); -//} +#include "Region.hpp" +#include "chunk/LevelChunk.hpp" +#include "material/Material.hpp" +#include "tile/Tile.hpp" +#include "Level.hpp" + +Region::Region(Level* level, int x1, int y1, int z1, int x2, int y2, int z2) { + this->level = level; + + xc1 = x1 >> 4; + zc1 = z1 >> 4; + int xc2 = x2 >> 4; + int zc2 = z2 >> 4; + + size_x = xc2 - xc1 + 1; + size_z = zc2 - zc1 + 1; + chunks = new LevelChunk**[size_x]; + for (int i = 0; i < size_x; ++i) + chunks[i] = new LevelChunk*[size_z]; + + for (int xc = xc1; xc <= xc2; xc++) { + for (int zc = zc1; zc <= zc2; zc++) { + chunks[xc - xc1][zc - zc1] = level->getChunk(xc, zc); + } + } +} + +Region::~Region() { + for (int i = 0 ; i < size_x; ++i) + delete[] chunks[i]; + delete[] chunks; +} + +int Region::getTile(int x, int y, int z) { + if (y < 0) return 0; + if (y >= Level::DEPTH) return 0; + + int xc = (x >> 4) - xc1; + int zc = (z >> 4) - zc1; + + if (xc < 0 || xc >= size_x || zc < 0 || zc >= size_z) { + return 0; + } + + LevelChunk* lc = chunks[xc][zc]; + if (lc == NULL) return 0; + + return lc->getTile(x & 15, y, z & 15); +} + +bool Region::isEmptyTile( int x, int y, int z ) +{ + //return getTile(x, y, z) == 0; //@todo? + return Tile::tiles[getTile(x, y, z)] == NULL; +} + +//TileEntity getTileEntity(int x, int y, int z) { +// int xc = (x >> 4) - xc1; +// int zc = (z >> 4) - zc1; + +// return chunks[xc][zc].getTileEntity(x & 15, y, z & 15); +//} + +float Region::getBrightness(int x, int y, int z) { + return level->dimension->brightnessRamp[getRawBrightness(x, y, z)]; +} + +int Region::getRawBrightness(int x, int y, int z) { + return getRawBrightness(x, y, z, true); +} + +int Region::getRawBrightness(int x, int y, int z, bool propagate) { + if (x < -Level::MAX_LEVEL_SIZE || z < -Level::MAX_LEVEL_SIZE || x >= Level::MAX_LEVEL_SIZE || z > Level::MAX_LEVEL_SIZE) { + return Level::MAX_BRIGHTNESS; + } + + if (propagate) { + int id = getTile(x, y, z); + if (id == Tile::stoneSlabHalf->id || id == Tile::farmland->id) { + int br = getRawBrightness(x, y + 1, z, false); + int br1 = getRawBrightness(x + 1, y, z, false); + int br2 = getRawBrightness(x - 1, y, z, false); + int br3 = getRawBrightness(x, y, z + 1, false); + int br4 = getRawBrightness(x, y, z - 1, false); + if (br1 > br) br = br1; + if (br2 > br) br = br2; + if (br3 > br) br = br3; + if (br4 > br) br = br4; + return br; + } + } + + if (y < 0) return 0; + if (y >= Level::DEPTH) { + int br = Level::MAX_BRIGHTNESS - level->skyDarken; + if (br < 0) br = 0; + return br; + } + + int xc = (x >> 4) - xc1; + int zc = (z >> 4) - zc1; + + return chunks[xc][zc]->getRawBrightness(x & 15, y, z & 15, level->skyDarken); +} + +int Region::getData(int x, int y, int z) { + if (y < 0) return 0; + if (y >= Level::DEPTH) return 0; + int xc = (x >> 4) - xc1; + int zc = (z >> 4) - zc1; + + return chunks[xc][zc]->getData(x & 15, y, z & 15); +} + +const Material* Region::getMaterial(int x, int y, int z) { + int t = getTile(x, y, z); + if (t == 0) return Material::air; + return Tile::tiles[t]->material; +} + +bool Region::isSolidBlockingTile(int x, int y, int z) +{ + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile == NULL) return false; + return tile->material->isSolidBlocking() && tile->isCubeShaped(); +} + +bool Region::isSolidRenderTile(int x, int y, int z) { + Tile* tile = Tile::tiles[getTile(x, y, z)]; + if (tile == NULL) return false; + return tile->isSolidRender(); +} + +Biome* Region::getBiome( int x, int z ) { + return level->getBiome(x, z); +} + +//BiomeSource getBiomeSource() { +// return level.getBiomeSource(); +//} diff --git a/src/world/level/Region.h b/src/world/level/Region.hpp similarity index 96% rename from src/world/level/Region.h rename to src/world/level/Region.hpp index d136fe1..8b7200c 100755 --- a/src/world/level/Region.h +++ b/src/world/level/Region.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level; -#include "LevelSource.h" +#include "LevelSource.hpp" class Level; class Material; diff --git a/src/world/level/TickNextTickData.cpp b/src/world/level/TickNextTickData.cpp index de26a37..2c8fe3d 100755 --- a/src/world/level/TickNextTickData.cpp +++ b/src/world/level/TickNextTickData.cpp @@ -1,29 +1,29 @@ -#include "TickNextTickData.h" - -long TickNextTickData::C = 0; - -TickNextTickData::TickNextTickData(int x_, int y_, int z_, int tileId_) - : x(x_), y(y_), z(z_), tileId(tileId_), c(++C) -{ -} - -bool TickNextTickData::operator==(const TickNextTickData& t) const { - return x == t.x && y == t.y && z == t.z && tileId == t.tileId; -} - -int TickNextTickData::hashCode() const { - return (((x * 128 * 1024) + (z * 128) + y) * 256) + tileId; -} - -TickNextTickData* TickNextTickData::setDelay(long l) { - this->delay = l; - return this; -} - -bool TickNextTickData::operator<(const TickNextTickData& tnd) const { - if (delay < tnd.delay) return true; - if (delay > tnd.delay) return false; - if (c < tnd.c) return true; - if (c > tnd.c) return false; - return false; -} +#include "TickNextTickData.hpp" + +long TickNextTickData::C = 0; + +TickNextTickData::TickNextTickData(int x_, int y_, int z_, int tileId_) + : x(x_), y(y_), z(z_), tileId(tileId_), c(++C) +{ +} + +bool TickNextTickData::operator==(const TickNextTickData& t) const { + return x == t.x && y == t.y && z == t.z && tileId == t.tileId; +} + +int TickNextTickData::hashCode() const { + return (((x * 128 * 1024) + (z * 128) + y) * 256) + tileId; +} + +TickNextTickData* TickNextTickData::setDelay(long l) { + this->delay = l; + return this; +} + +bool TickNextTickData::operator<(const TickNextTickData& tnd) const { + if (delay < tnd.delay) return true; + if (delay > tnd.delay) return false; + if (c < tnd.c) return true; + if (c > tnd.c) return false; + return false; +} diff --git a/src/world/level/TickNextTickData.h b/src/world/level/TickNextTickData.hpp similarity index 100% rename from src/world/level/TickNextTickData.h rename to src/world/level/TickNextTickData.hpp diff --git a/src/world/level/TilePos.h b/src/world/level/TilePos.hpp similarity index 100% rename from src/world/level/TilePos.h rename to src/world/level/TilePos.hpp diff --git a/src/world/level/biome/Biome.cpp b/src/world/level/biome/Biome.cpp index d0a842a..2b03653 100755 --- a/src/world/level/biome/Biome.cpp +++ b/src/world/level/biome/Biome.cpp @@ -1,229 +1,229 @@ -#include "BiomeInclude.h" - -#include "../levelgen/feature/TreeFeature.h" -#include "../levelgen/feature/TallgrassFeature.h" - -#include "../../entity/EntityTypes.h" -#include "../../entity/MobCategory.h" -#include "../../level/tile/TallGrass.h" - -Biome* Biome::rainForest = NULL; -Biome* Biome::swampland = NULL; -Biome* Biome::seasonalForest = NULL; -Biome* Biome::forest = NULL; -Biome* Biome::savanna = NULL; -Biome* Biome::shrubland = NULL; -Biome* Biome::taiga = NULL; -Biome* Biome::desert = NULL; -Biome* Biome::plains = NULL; -Biome* Biome::iceDesert = NULL; -Biome* Biome::tundra = NULL; - -/*static*/ -Biome::MobList Biome::_emptyMobList; -int Biome::defaultTotalEnemyWeight = 0; -int Biome::defaultTotalFriendlyWeight = 0; - -/*static*/ -Biome* Biome::map[64*64]; - -Biome::Biome() -: topMaterial(((Tile*)Tile::grass)->id), - material(((Tile*)Tile::dirt)->id), - leafColor(0x4EE031) -{ - _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Sheep, 12, 2, 3)); - _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Pig, 10, 1, 3)); - _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Chicken, 10, 2, 4)); - _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Cow, 8, 2, 3)); - - _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Spider, 8, 2, 3)); - _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Zombie, 12, 2, 4)); - _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Skeleton, 6, 1, 3)); - _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Creeper, 4, 1, 1)); - //_enemies.insert(_enemies.end(), MobSpawnerData(Slime.class, 10, 4, 4)); - //_enemies.insert(_enemies.end(), MobSpawnerData(EnderMan.class, 1, 1, 4)); - - // wolves are added to forests and taigas - // _friendlies.insert(_friendlies.end(), new MobSpawnerData(Wolf.class, 2)); - - //_waterFriendlies.insert(_waterFriendlies.end(), (new MobSpawnerData(Squid.class, 10, 4, 4)); - - // - // Sum up the weights - // - defaultTotalEnemyWeight = 0; - for (MobList::const_iterator cit = _enemies.begin(); cit != _enemies.end(); ++cit) - defaultTotalEnemyWeight += cit->randomWeight; - - defaultTotalFriendlyWeight = 0; - for (MobList::const_iterator cit = _friendlies.begin(); cit != _friendlies.end(); ++cit) - defaultTotalFriendlyWeight += cit->randomWeight; -} - -Biome* Biome::setName( const std::string& name ) -{ - this->name = name; - return this; -} - -Biome* Biome::setLeafColor( int leafColor ) -{ - this->leafColor = leafColor; - return this; -} - -Biome* Biome::setColor( int color ) -{ - this->color = color; - return this; -} - -Biome* Biome::setSnowCovered() -{ - return this; -} - -Biome* Biome::clearMobs( bool friendlies /*= true*/, bool waterFriendlies /*= true*/, bool enemies /*= true*/ ) -{ - if (friendlies) _friendlies.clear(); - if (waterFriendlies) _waterFriendlies.clear(); - if (enemies) _enemies.clear(); - return this; -} - - -/*static*/ -void Biome::recalc() -{ - for (int a = 0; a < 64; a++) { - for (int b = 0; b < 64; b++) { - map[a + b * 64] = _getBiome(a / 63.0f, b / 63.0f); - } - } - - Biome::desert->topMaterial = Biome::desert->material = (char) Tile::sand->id; - Biome::iceDesert->topMaterial = Biome::iceDesert->material = (char) Tile::sand->id; -} - -/*static*/ -void Biome::initBiomes() { - rainForest = (new RainforestBiome())->setColor(0x08FA36)->setName("Rainforest")->setLeafColor(0x1FF458); - swampland = (new SwampBiome())->setColor(0x07F9B2)->setName("Swampland")->setLeafColor(0x8BAF48); - seasonalForest = (new Biome())->setColor(0x9BE023)->setName("Seasonal Forest"); - forest = (new ForestBiome())->setColor(0x056621)->setName("Forest")->setLeafColor(0x4EBA31); - savanna = (new FlatBiome())->setColor(0xD9E023)->setName("Savanna"); - shrubland = (new Biome())->setColor(0xA1AD20)->setName("Shrubland"); - taiga = (new TaigaBiome())->setColor(0x2EB153)->setName("Taiga")->setSnowCovered()->setLeafColor(0x7BB731); - desert = (new FlatBiome())->setColor(0xFA9418)->clearMobs(true, true, false)->setName("Desert"); - plains = (new FlatBiome())->setColor(0xFFD910)->setName("Plains"); - iceDesert = (new FlatBiome())->setColor(0xFFED93)->clearMobs(true, false, false)->setName("Ice Desert")->setSnowCovered()->setLeafColor(0xC4D339); - tundra = (new Biome())->setColor(0x57EBF9)->setName("Tundra")->setSnowCovered()->setLeafColor(0xC4D339); - - recalc(); -} -/*static*/ -void Biome::teardownBiomes() { - delete rainForest; rainForest= NULL; - delete swampland; swampland = NULL; - delete seasonalForest; seasonalForest = NULL; - delete forest; forest = NULL; - delete savanna; savanna = NULL; - delete shrubland; shrubland = NULL; - delete taiga; taiga = NULL; - delete desert; desert = NULL; - delete plains; plains = NULL; - delete iceDesert; iceDesert = NULL; - delete tundra; tundra = NULL; -} - -Feature* Biome::getTreeFeature( Random* random ) -{ - if (random->nextInt(10) == 0) { - //return /*new*/ BasicTree(); - } - return new TreeFeature(false); -} -Feature* Biome::getGrassFeature( Random* random ) { - return new TallgrassFeature(Tile::tallgrass->id, TallGrass::TALL_GRASS); -} - -Biome* Biome::getBiome( float temperature, float downfall ) -{ - int a = (int) (temperature * 63); - int b = (int) (downfall * 63); - - //printf("Getting biome: %s\n", map[a + b * 64]->name.c_str()); - - return map[a + b * 64]; -} - -Biome* Biome::_getBiome( float temperature, float downfall ) -{ - downfall *= (temperature); - if (temperature < 0.10f) { - return Biome::tundra; - } else if (downfall < 0.20f) { - if (temperature < 0.50f) { - return Biome::tundra; - } else if (temperature < 0.95f) { - return Biome::savanna; - } else { - return Biome::desert; - } - } else if (downfall > 0.5f && temperature < 0.7f) { - return Biome::swampland; - } else if (temperature < 0.50f) { - return Biome::taiga; - } else if (temperature < 0.97f) { - if (downfall < 0.35f) { - return Biome::shrubland; - } else { - return Biome::forest; - } - } else { - if (downfall < 0.45f) { - return Biome::plains; - } else if (downfall < 0.90f) { - return Biome::seasonalForest; - } else { - return Biome::rainForest; - } - } -} - -float Biome::adjustScale( float scale ) -{ - return scale; -} - -float Biome::adjustDepth( float depth ) -{ - return depth; -} - -int Biome::getSkyColor( float temp ) -{ -// temp /= 3.f; -// if (temp < -1) temp = -1; -// if (temp > 1) temp = 1; - return 0x80808080; - //return Color.getHSBColor(224 / 360.0f - temp * 0.05f, 0.50f + temp * 0.1f, 1.0f).getRGB(); -} - -Biome::MobList& Biome::getMobs(const MobCategory& category) -{ - if (&category == &MobCategory::monster) - return _enemies; - if (&category == &MobCategory::creature) - return _friendlies; - if (&category == &MobCategory::waterCreature) - return _waterFriendlies; - - LOGE("Unknown MobCategory!"); - return _emptyMobList; -} - -float Biome::getCreatureProbability() { - return 0.08f; -} +#include "BiomeInclude.hpp" + +#include "world/level/levelgen/feature/TreeFeature.hpp" +#include "world/level/levelgen/feature/TallgrassFeature.hpp" + +#include "world/entity/EntityTypes.hpp" +#include "world/entity/MobCategory.hpp" +#include "world/level/tile/TallGrass.hpp" + +Biome* Biome::rainForest = NULL; +Biome* Biome::swampland = NULL; +Biome* Biome::seasonalForest = NULL; +Biome* Biome::forest = NULL; +Biome* Biome::savanna = NULL; +Biome* Biome::shrubland = NULL; +Biome* Biome::taiga = NULL; +Biome* Biome::desert = NULL; +Biome* Biome::plains = NULL; +Biome* Biome::iceDesert = NULL; +Biome* Biome::tundra = NULL; + +/*static*/ +Biome::MobList Biome::_emptyMobList; +int Biome::defaultTotalEnemyWeight = 0; +int Biome::defaultTotalFriendlyWeight = 0; + +/*static*/ +Biome* Biome::map[64*64]; + +Biome::Biome() +: topMaterial(((Tile*)Tile::grass)->id), + material(((Tile*)Tile::dirt)->id), + leafColor(0x4EE031) +{ + _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Sheep, 12, 2, 3)); + _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Pig, 10, 1, 3)); + _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Chicken, 10, 2, 4)); + _friendlies.insert(_friendlies.end(), MobSpawnerData(MobTypes::Cow, 8, 2, 3)); + + _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Spider, 8, 2, 3)); + _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Zombie, 12, 2, 4)); + _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Skeleton, 6, 1, 3)); + _enemies.insert(_enemies.end(), MobSpawnerData(MobTypes::Creeper, 4, 1, 1)); + //_enemies.insert(_enemies.end(), MobSpawnerData(Slime.class, 10, 4, 4)); + //_enemies.insert(_enemies.end(), MobSpawnerData(EnderMan.class, 1, 1, 4)); + + // wolves are added to forests and taigas + // _friendlies.insert(_friendlies.end(), new MobSpawnerData(Wolf.class, 2)); + + //_waterFriendlies.insert(_waterFriendlies.end(), (new MobSpawnerData(Squid.class, 10, 4, 4)); + + // + // Sum up the weights + // + defaultTotalEnemyWeight = 0; + for (MobList::const_iterator cit = _enemies.begin(); cit != _enemies.end(); ++cit) + defaultTotalEnemyWeight += cit->randomWeight; + + defaultTotalFriendlyWeight = 0; + for (MobList::const_iterator cit = _friendlies.begin(); cit != _friendlies.end(); ++cit) + defaultTotalFriendlyWeight += cit->randomWeight; +} + +Biome* Biome::setName( const std::string& name ) +{ + this->name = name; + return this; +} + +Biome* Biome::setLeafColor( int leafColor ) +{ + this->leafColor = leafColor; + return this; +} + +Biome* Biome::setColor( int color ) +{ + this->color = color; + return this; +} + +Biome* Biome::setSnowCovered() +{ + return this; +} + +Biome* Biome::clearMobs( bool friendlies /*= true*/, bool waterFriendlies /*= true*/, bool enemies /*= true*/ ) +{ + if (friendlies) _friendlies.clear(); + if (waterFriendlies) _waterFriendlies.clear(); + if (enemies) _enemies.clear(); + return this; +} + + +/*static*/ +void Biome::recalc() +{ + for (int a = 0; a < 64; a++) { + for (int b = 0; b < 64; b++) { + map[a + b * 64] = _getBiome(a / 63.0f, b / 63.0f); + } + } + + Biome::desert->topMaterial = Biome::desert->material = (char) Tile::sand->id; + Biome::iceDesert->topMaterial = Biome::iceDesert->material = (char) Tile::sand->id; +} + +/*static*/ +void Biome::initBiomes() { + rainForest = (new RainforestBiome())->setColor(0x08FA36)->setName("Rainforest")->setLeafColor(0x1FF458); + swampland = (new SwampBiome())->setColor(0x07F9B2)->setName("Swampland")->setLeafColor(0x8BAF48); + seasonalForest = (new Biome())->setColor(0x9BE023)->setName("Seasonal Forest"); + forest = (new ForestBiome())->setColor(0x056621)->setName("Forest")->setLeafColor(0x4EBA31); + savanna = (new FlatBiome())->setColor(0xD9E023)->setName("Savanna"); + shrubland = (new Biome())->setColor(0xA1AD20)->setName("Shrubland"); + taiga = (new TaigaBiome())->setColor(0x2EB153)->setName("Taiga")->setSnowCovered()->setLeafColor(0x7BB731); + desert = (new FlatBiome())->setColor(0xFA9418)->clearMobs(true, true, false)->setName("Desert"); + plains = (new FlatBiome())->setColor(0xFFD910)->setName("Plains"); + iceDesert = (new FlatBiome())->setColor(0xFFED93)->clearMobs(true, false, false)->setName("Ice Desert")->setSnowCovered()->setLeafColor(0xC4D339); + tundra = (new Biome())->setColor(0x57EBF9)->setName("Tundra")->setSnowCovered()->setLeafColor(0xC4D339); + + recalc(); +} +/*static*/ +void Biome::teardownBiomes() { + delete rainForest; rainForest= NULL; + delete swampland; swampland = NULL; + delete seasonalForest; seasonalForest = NULL; + delete forest; forest = NULL; + delete savanna; savanna = NULL; + delete shrubland; shrubland = NULL; + delete taiga; taiga = NULL; + delete desert; desert = NULL; + delete plains; plains = NULL; + delete iceDesert; iceDesert = NULL; + delete tundra; tundra = NULL; +} + +Feature* Biome::getTreeFeature( Random* random ) +{ + if (random->nextInt(10) == 0) { + //return /*new*/ BasicTree(); + } + return new TreeFeature(false); +} +Feature* Biome::getGrassFeature( Random* random ) { + return new TallgrassFeature(Tile::tallgrass->id, TallGrass::TALL_GRASS); +} + +Biome* Biome::getBiome( float temperature, float downfall ) +{ + int a = (int) (temperature * 63); + int b = (int) (downfall * 63); + + //printf("Getting biome: %s\n", map[a + b * 64]->name.c_str()); + + return map[a + b * 64]; +} + +Biome* Biome::_getBiome( float temperature, float downfall ) +{ + downfall *= (temperature); + if (temperature < 0.10f) { + return Biome::tundra; + } else if (downfall < 0.20f) { + if (temperature < 0.50f) { + return Biome::tundra; + } else if (temperature < 0.95f) { + return Biome::savanna; + } else { + return Biome::desert; + } + } else if (downfall > 0.5f && temperature < 0.7f) { + return Biome::swampland; + } else if (temperature < 0.50f) { + return Biome::taiga; + } else if (temperature < 0.97f) { + if (downfall < 0.35f) { + return Biome::shrubland; + } else { + return Biome::forest; + } + } else { + if (downfall < 0.45f) { + return Biome::plains; + } else if (downfall < 0.90f) { + return Biome::seasonalForest; + } else { + return Biome::rainForest; + } + } +} + +float Biome::adjustScale( float scale ) +{ + return scale; +} + +float Biome::adjustDepth( float depth ) +{ + return depth; +} + +int Biome::getSkyColor( float temp ) +{ +// temp /= 3.f; +// if (temp < -1) temp = -1; +// if (temp > 1) temp = 1; + return 0x80808080; + //return Color.getHSBColor(224 / 360.0f - temp * 0.05f, 0.50f + temp * 0.1f, 1.0f).getRGB(); +} + +Biome::MobList& Biome::getMobs(const MobCategory& category) +{ + if (&category == &MobCategory::monster) + return _enemies; + if (&category == &MobCategory::creature) + return _friendlies; + if (&category == &MobCategory::waterCreature) + return _waterFriendlies; + + LOGE("Unknown MobCategory!"); + return _emptyMobList; +} + +float Biome::getCreatureProbability() { + return 0.08f; +} diff --git a/src/world/level/biome/Biome.h b/src/world/level/biome/Biome.hpp similarity index 98% rename from src/world/level/biome/Biome.h rename to src/world/level/biome/Biome.hpp index 6e48093..b9e278f 100755 --- a/src/world/level/biome/Biome.h +++ b/src/world/level/biome/Biome.hpp @@ -5,7 +5,7 @@ #include #include -#include "../../../util/WeighedRandom.h" +#include "util/WeighedRandom.hpp" class Feature; class MobCategory; diff --git a/src/world/level/biome/BiomeInclude.h b/src/world/level/biome/BiomeInclude.h deleted file mode 100755 index d50d4f0..0000000 --- a/src/world/level/biome/BiomeInclude.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "Biome.h" -#include "FlatBiome.h" -#include "ForestBiome.h" -#include "RainforestBiome.h" -#include "SwampBiome.h" -#include "TaigaBiome.h" - diff --git a/src/world/level/biome/BiomeInclude.hpp b/src/world/level/biome/BiomeInclude.hpp new file mode 100755 index 0000000..a67a38a --- /dev/null +++ b/src/world/level/biome/BiomeInclude.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "Biome.hpp" +#include "FlatBiome.hpp" +#include "ForestBiome.hpp" +#include "RainforestBiome.hpp" +#include "SwampBiome.hpp" +#include "TaigaBiome.hpp" + diff --git a/src/world/level/biome/BiomeSource.cpp b/src/world/level/biome/BiomeSource.cpp index ab7c3a4..9d66ef6 100755 --- a/src/world/level/biome/BiomeSource.cpp +++ b/src/world/level/biome/BiomeSource.cpp @@ -1,178 +1,178 @@ -#include "BiomeSource.h" -#include "Biome.h" -#include "../Level.h" -#include "../ChunkPos.h" - -const float BiomeSource::zoom = 2 * 1; - -const float BiomeSource::tempScale = zoom / 80.0f; -const float BiomeSource::downfallScale = zoom / 40.0f; -const float BiomeSource::noiseScale = 1 / 4.0f; - -BiomeSource::BiomeSource() -: temperatureMap(NULL), - downfallMap(NULL), - noiseMap(NULL), - lenTemperatures(0), - lenDownfalls(0), - lenNoises(0), - lenBiomes(0), - temperatures(NULL), - downfalls(NULL), - noises(NULL), - biomes(NULL) -{ - biomes = new Biome*[16*16]; -} - -BiomeSource::BiomeSource( Level* level ) -: rndTemperature(level->getSeed() * 9871), - rndDownfall(level->getSeed() * 39811), - rndNoise(level->getSeed() * 543321), - lenTemperatures(0), - lenDownfalls(0), - lenNoises(0), - lenBiomes(0), - temperatures(NULL), - downfalls(NULL), - noises(NULL), - biomes(NULL) -{ - temperatureMap = new PerlinSimplexNoise(&rndTemperature, 4); - downfallMap = new PerlinSimplexNoise(&rndDownfall, 4); - noiseMap = new PerlinSimplexNoise(&rndNoise, 2); - - biomes = new Biome*[16*16]; - temperatures = new float[16*16]; -} - -BiomeSource::~BiomeSource() { - LOGI("Deleting biome maps...\n"); - delete temperatureMap; - delete downfallMap; - delete noiseMap; - - LOGI("Deleting biome data arrays...\n"); - delete[] temperatures; - delete[] downfalls; - delete[] noises; - delete[] biomes; -} - -Biome* BiomeSource::getBiome( const ChunkPos& chunk ) -{ - return getBiome(chunk.x << 4, chunk.z << 4); -} - -Biome* BiomeSource::getBiome( int x, int z ) -{ - return getBiomeBlock(x, z, 1, 1)[0]; -} - -//float BiomeSource::getTemperature( int x, int z ) -//{ -// temperatures = temperatureMap->getRegion(temperatures, x, z, 1, 1, tempScale, tempScale, 0.5f); -// return temperatures[0]; -//} - -Biome** BiomeSource::getBiomeBlock( int x, int z, int w, int h ) -{ - biomes = getBiomeBlock(biomes, x, z, w, h); - return biomes; -} - -Biome** BiomeSource::getBiomeBlock( Biome** biomes__, int x, int z, int w, int h ) -{ - //for (int i = 0; i < w*h; ++i) biomes__[i] = Biome::tundra; - //const int size = w * h; - //if (lenBiomes < size) { - // //printf("changing to size: %d (was %d). %d, %d (%d, %d)\n", size, lenBiomes, x, z, w, h); - // if (biomes) delete[] biomes; - // biomes = new Biome*[size]; - // lenBiomes = size; - //} - - temperatures = temperatureMap->getRegion(temperatures, x, z, w, w, tempScale, tempScale, 0.25f); - downfalls = downfallMap->getRegion(downfalls, x, z, w, w, downfallScale, downfallScale, 0.3333f); - noises = noiseMap->getRegion(noises, x, z, w, w, noiseScale, noiseScale, 0.588f); - - int pp = 0; - for (int yy = 0; yy < w; yy++) { - for (int xx = 0; xx < h; xx++) { - float noise = (noises[pp] * 1.1f + 0.5f); - - float split2 = 0.01f; - float split1 = 1 - split2; - float temperature = (temperatures[pp] * 0.15f + 0.7f) * split1 + noise * split2; - split2 = 0.002f; - split1 = 1 - split2; - float downfall = (downfalls[pp] * 0.15f + 0.5f) * split1 + noise * split2; - temperature = 1 - ((1 - temperature) * (1 - temperature)); - if (temperature < 0) temperature = 0; - if (downfall < 0) downfall = 0; - if (temperature > 1) temperature = 1; - if (downfall > 1) downfall = 1; - - temperatures[pp] = temperature; - downfalls[pp] = downfall; - // System.out.println(downfall); - biomes[pp++] = Biome::getBiome(temperature, downfall); - } - } - - return biomes; -} - -float* BiomeSource::getTemperatureBlock( /*float* temperatures__, */int x, int z, int w, int h ) -{ - //LOGI("gTempBlock: 1\n"); - //const int size = w * h; - //if (lenTemperatures < size) { - // if (temperatures) delete[] temperatures; - // temperatures = new float[size]; - // lenTemperatures = size; - //} - - float * ot = temperatures; - temperatures = temperatureMap->getRegion(temperatures, x, z, w, h, tempScale, tempScale, 0.25f); - noises = noiseMap->getRegion(noises, x, z, w, h, noiseScale, noiseScale, 0.588f); - - if (ot != temperatures) { - LOGI("tmp ptr changed\n"); - } - - int pp = 0; - for (int yy = 0; yy < w; yy++) { - for (int xx = 0; xx < h; xx++) { - float noise = (noises[pp] * 1.1f + 0.5f); - - float split2 = 0.01f; - float split1 = 1 - split2; - float temperature = (temperatures[pp] * 0.15f + 0.7f) * split1 + noise * split2; - temperature = 1 - ((1 - temperature) * (1 - temperature)); - - if (temperature < 0) temperature = 0; - if (temperature > 1) temperature = 1; - - temperatures[pp] = temperature; - pp++; - } - } - - // System.out.println(min+", "+max); - - return temperatures; -} - -//float* BiomeSource::getDownfallBlock( /*float* downfalls__,*/ int x, int z, int w, int h ) -//{ -// //const int size = w * h; -// //if (lenDownfalls < size) { -// // delete[] downfalls; -// // downfalls = new float[size]; -// // lenDownfalls = size; -// //} -// -// downfalls = downfallMap->getRegion(downfalls, x, z, w, w, downfallScale, downfallScale, 0.5f); -// return downfalls; -//} +#include "BiomeSource.hpp" +#include "Biome.hpp" +#include "world/level/Level.hpp" +#include "world/level/ChunkPos.hpp" + +const float BiomeSource::zoom = 2 * 1; + +const float BiomeSource::tempScale = zoom / 80.0f; +const float BiomeSource::downfallScale = zoom / 40.0f; +const float BiomeSource::noiseScale = 1 / 4.0f; + +BiomeSource::BiomeSource() +: temperatureMap(NULL), + downfallMap(NULL), + noiseMap(NULL), + lenTemperatures(0), + lenDownfalls(0), + lenNoises(0), + lenBiomes(0), + temperatures(NULL), + downfalls(NULL), + noises(NULL), + biomes(NULL) +{ + biomes = new Biome*[16*16]; +} + +BiomeSource::BiomeSource( Level* level ) +: rndTemperature(level->getSeed() * 9871), + rndDownfall(level->getSeed() * 39811), + rndNoise(level->getSeed() * 543321), + lenTemperatures(0), + lenDownfalls(0), + lenNoises(0), + lenBiomes(0), + temperatures(NULL), + downfalls(NULL), + noises(NULL), + biomes(NULL) +{ + temperatureMap = new PerlinSimplexNoise(&rndTemperature, 4); + downfallMap = new PerlinSimplexNoise(&rndDownfall, 4); + noiseMap = new PerlinSimplexNoise(&rndNoise, 2); + + biomes = new Biome*[16*16]; + temperatures = new float[16*16]; +} + +BiomeSource::~BiomeSource() { + LOGI("Deleting biome maps...\n"); + delete temperatureMap; + delete downfallMap; + delete noiseMap; + + LOGI("Deleting biome data arrays...\n"); + delete[] temperatures; + delete[] downfalls; + delete[] noises; + delete[] biomes; +} + +Biome* BiomeSource::getBiome( const ChunkPos& chunk ) +{ + return getBiome(chunk.x << 4, chunk.z << 4); +} + +Biome* BiomeSource::getBiome( int x, int z ) +{ + return getBiomeBlock(x, z, 1, 1)[0]; +} + +//float BiomeSource::getTemperature( int x, int z ) +//{ +// temperatures = temperatureMap->getRegion(temperatures, x, z, 1, 1, tempScale, tempScale, 0.5f); +// return temperatures[0]; +//} + +Biome** BiomeSource::getBiomeBlock( int x, int z, int w, int h ) +{ + biomes = getBiomeBlock(biomes, x, z, w, h); + return biomes; +} + +Biome** BiomeSource::getBiomeBlock( Biome** biomes__, int x, int z, int w, int h ) +{ + //for (int i = 0; i < w*h; ++i) biomes__[i] = Biome::tundra; + //const int size = w * h; + //if (lenBiomes < size) { + // //printf("changing to size: %d (was %d). %d, %d (%d, %d)\n", size, lenBiomes, x, z, w, h); + // if (biomes) delete[] biomes; + // biomes = new Biome*[size]; + // lenBiomes = size; + //} + + temperatures = temperatureMap->getRegion(temperatures, x, z, w, w, tempScale, tempScale, 0.25f); + downfalls = downfallMap->getRegion(downfalls, x, z, w, w, downfallScale, downfallScale, 0.3333f); + noises = noiseMap->getRegion(noises, x, z, w, w, noiseScale, noiseScale, 0.588f); + + int pp = 0; + for (int yy = 0; yy < w; yy++) { + for (int xx = 0; xx < h; xx++) { + float noise = (noises[pp] * 1.1f + 0.5f); + + float split2 = 0.01f; + float split1 = 1 - split2; + float temperature = (temperatures[pp] * 0.15f + 0.7f) * split1 + noise * split2; + split2 = 0.002f; + split1 = 1 - split2; + float downfall = (downfalls[pp] * 0.15f + 0.5f) * split1 + noise * split2; + temperature = 1 - ((1 - temperature) * (1 - temperature)); + if (temperature < 0) temperature = 0; + if (downfall < 0) downfall = 0; + if (temperature > 1) temperature = 1; + if (downfall > 1) downfall = 1; + + temperatures[pp] = temperature; + downfalls[pp] = downfall; + // System.out.println(downfall); + biomes[pp++] = Biome::getBiome(temperature, downfall); + } + } + + return biomes; +} + +float* BiomeSource::getTemperatureBlock( /*float* temperatures__, */int x, int z, int w, int h ) +{ + //LOGI("gTempBlock: 1\n"); + //const int size = w * h; + //if (lenTemperatures < size) { + // if (temperatures) delete[] temperatures; + // temperatures = new float[size]; + // lenTemperatures = size; + //} + + float * ot = temperatures; + temperatures = temperatureMap->getRegion(temperatures, x, z, w, h, tempScale, tempScale, 0.25f); + noises = noiseMap->getRegion(noises, x, z, w, h, noiseScale, noiseScale, 0.588f); + + if (ot != temperatures) { + LOGI("tmp ptr changed\n"); + } + + int pp = 0; + for (int yy = 0; yy < w; yy++) { + for (int xx = 0; xx < h; xx++) { + float noise = (noises[pp] * 1.1f + 0.5f); + + float split2 = 0.01f; + float split1 = 1 - split2; + float temperature = (temperatures[pp] * 0.15f + 0.7f) * split1 + noise * split2; + temperature = 1 - ((1 - temperature) * (1 - temperature)); + + if (temperature < 0) temperature = 0; + if (temperature > 1) temperature = 1; + + temperatures[pp] = temperature; + pp++; + } + } + + // System.out.println(min+", "+max); + + return temperatures; +} + +//float* BiomeSource::getDownfallBlock( /*float* downfalls__,*/ int x, int z, int w, int h ) +//{ +// //const int size = w * h; +// //if (lenDownfalls < size) { +// // delete[] downfalls; +// // downfalls = new float[size]; +// // lenDownfalls = size; +// //} +// +// downfalls = downfallMap->getRegion(downfalls, x, z, w, w, downfallScale, downfallScale, 0.5f); +// return downfalls; +//} diff --git a/src/world/level/biome/BiomeSource.h b/src/world/level/biome/BiomeSource.hpp similarity index 94% rename from src/world/level/biome/BiomeSource.h rename to src/world/level/biome/BiomeSource.hpp index 607f8d9..c939bc0 100755 --- a/src/world/level/biome/BiomeSource.h +++ b/src/world/level/biome/BiomeSource.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.biome; -#include "../../../util/Random.h" -#include "../levelgen/synth/PerlinNoise.h" +#include "util/Random.hpp" +#include "world/level/levelgen/synth/PerlinNoise.hpp" typedef PerlinNoise PerlinSimplexNoise; class Level; diff --git a/src/world/level/biome/FlatBiome.h b/src/world/level/biome/FlatBiome.hpp similarity index 81% rename from src/world/level/biome/FlatBiome.h rename to src/world/level/biome/FlatBiome.hpp index 977c546..d0d9fc9 100755 --- a/src/world/level/biome/FlatBiome.h +++ b/src/world/level/biome/FlatBiome.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.biome; -#include "Biome.h" +#include "Biome.hpp" class FlatBiome: public Biome { }; diff --git a/src/world/level/biome/ForestBiome.h b/src/world/level/biome/ForestBiome.hpp similarity index 73% rename from src/world/level/biome/ForestBiome.h rename to src/world/level/biome/ForestBiome.hpp index 09b9139..ab436ac 100755 --- a/src/world/level/biome/ForestBiome.h +++ b/src/world/level/biome/ForestBiome.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.biome; -#include "Biome.h" -#include "../levelgen/feature/TreeFeature.h" -#include "../levelgen/feature/BirchFeature.h" +#include "Biome.hpp" +#include "world/level/levelgen/feature/TreeFeature.hpp" +#include "world/level/levelgen/feature/BirchFeature.hpp" class ForestBiome: public Biome { diff --git a/src/world/level/biome/RainforestBiome.h b/src/world/level/biome/RainforestBiome.hpp similarity index 73% rename from src/world/level/biome/RainforestBiome.h rename to src/world/level/biome/RainforestBiome.hpp index 9f7ed1d..9fd512a 100755 --- a/src/world/level/biome/RainforestBiome.h +++ b/src/world/level/biome/RainforestBiome.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.biome; -#include "Biome.h" -#include "../../../util/Random.h" -#include "../levelgen/feature/TreeFeature.h" +#include "Biome.hpp" +#include "util/Random.hpp" +#include "world/level/levelgen/feature/TreeFeature.hpp" class RainforestBiome: public Biome { diff --git a/src/world/level/biome/SwampBiome.h b/src/world/level/biome/SwampBiome.hpp similarity index 82% rename from src/world/level/biome/SwampBiome.h rename to src/world/level/biome/SwampBiome.hpp index f8489fa..c11c1ff 100755 --- a/src/world/level/biome/SwampBiome.h +++ b/src/world/level/biome/SwampBiome.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.biome; -#include "Biome.h" +#include "Biome.hpp" class SwampBiome: public Biome { }; diff --git a/src/world/level/biome/TaigaBiome.h b/src/world/level/biome/TaigaBiome.hpp similarity index 63% rename from src/world/level/biome/TaigaBiome.h rename to src/world/level/biome/TaigaBiome.hpp index ed3b4e7..6628970 100755 --- a/src/world/level/biome/TaigaBiome.h +++ b/src/world/level/biome/TaigaBiome.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.biome; -#include "Biome.h" -#include "../../../util/Random.h" -#include "../levelgen/feature/PineFeature.h" -#include "../levelgen/feature/SpruceFeature.h" +#include "Biome.hpp" +#include "util/Random.hpp" +#include "world/level/levelgen/feature/PineFeature.hpp" +#include "world/level/levelgen/feature/SpruceFeature.hpp" class TaigaBiome: public Biome { diff --git a/src/world/level/chunk/ChunkCache.h b/src/world/level/chunk/ChunkCache.hpp similarity index 97% rename from src/world/level/chunk/ChunkCache.h rename to src/world/level/chunk/ChunkCache.hpp index 1a1f00c..2934141 100755 --- a/src/world/level/chunk/ChunkCache.h +++ b/src/world/level/chunk/ChunkCache.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.chunk; -#include "ChunkSource.h" -#include "storage/ChunkStorage.h" -#include "EmptyLevelChunk.h" -#include "../Level.h" -#include "../LevelConstants.h" +#include "ChunkSource.hpp" +#include "storage/ChunkStorage.hpp" +#include "EmptyLevelChunk.hpp" +#include "world/level/Level.hpp" +#include "world/level/LevelConstants.hpp" class ChunkCache: public ChunkSource { //static const int CHUNK_CACHE_WIDTH = CHUNK_CACHE_WIDTH; // WAS 32; diff --git a/src/world/level/chunk/ChunkSource.h b/src/world/level/chunk/ChunkSource.hpp similarity index 95% rename from src/world/level/chunk/ChunkSource.h rename to src/world/level/chunk/ChunkSource.hpp index bb6e23e..9fb34d7 100755 --- a/src/world/level/chunk/ChunkSource.h +++ b/src/world/level/chunk/ChunkSource.hpp @@ -3,7 +3,7 @@ //package net.minecraft.world.level.chunk; #include -#include "../biome/Biome.h" +#include "world/level/biome/Biome.hpp" class ProgressListener; class LevelChunk; diff --git a/src/world/level/chunk/DataLayer.h b/src/world/level/chunk/DataLayer.hpp similarity index 100% rename from src/world/level/chunk/DataLayer.h rename to src/world/level/chunk/DataLayer.hpp diff --git a/src/world/level/chunk/EmptyLevelChunk.h b/src/world/level/chunk/EmptyLevelChunk.hpp similarity index 94% rename from src/world/level/chunk/EmptyLevelChunk.h rename to src/world/level/chunk/EmptyLevelChunk.hpp index 1b274a2..910ec57 100755 --- a/src/world/level/chunk/EmptyLevelChunk.h +++ b/src/world/level/chunk/EmptyLevelChunk.hpp @@ -4,14 +4,14 @@ /* import java.util.* */ -//#include "world/entity/Entity.h" +//#include "world/entity/Entity.hpp" /* import net.minecraft.world.level.* */ -//#include "world/level/tile/entity/TileEntity.h" -//#include "world/phys/AABB.h" +//#include "world/level/tile/entity/TileEntity.hpp" +//#include "world/phys/AABB.hpp" -#include "LevelChunk.h" -#include "../tile/Tile.h" -#include "../Level.h" +#include "LevelChunk.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/Level.hpp" class EmptyLevelChunk: public LevelChunk { diff --git a/src/world/level/chunk/LevelChunk.cpp b/src/world/level/chunk/LevelChunk.cpp index bb373fb..fda436c 100755 --- a/src/world/level/chunk/LevelChunk.cpp +++ b/src/world/level/chunk/LevelChunk.cpp @@ -1,713 +1,713 @@ -#include "LevelChunk.h" -#include "../LightLayer.h" -#include "../tile/Tile.h" -#include "../Level.h" -#include "../dimension/Dimension.h" -#include "../../phys/AABB.h" -#include "../../entity/Entity.h" -#include "../TilePos.h" -#include "../tile/entity/TileEntity.h" -#include "../tile/EntityTile.h" -#include "../LevelConstants.h" - -/*static*/ -bool LevelChunk::touchedSky = false; - -LevelChunk::LevelChunk( Level* level, int x, int z ) -: level(level), - x(x), - z(z), - xt(x * CHUNK_WIDTH), - zt(z * CHUNK_DEPTH) -{ - init(); -} - -LevelChunk::LevelChunk( Level* level, unsigned char* blocks, int x, int z ) -: level(level), - x(x), - z(z), - xt(x * CHUNK_WIDTH), - zt(z * CHUNK_DEPTH), - blocks(blocks), - data(ChunkBlockCount), - skyLight(ChunkBlockCount), - blockLight(ChunkBlockCount), - blocksLength(ChunkBlockCount) -{ - init(); -} - -LevelChunk::~LevelChunk() -{ - //delete blocks; -} - -void LevelChunk::init() -{ - terrainPopulated = false; - dontSave = false; - unsaved = false; - lastSaveHadEntities = false; - createdFromSave = false; - lastSaveTime = 0; - memset(heightmap, 0, 256); - memset(updateMap, 0, 256); -} - -/*public*/ -bool LevelChunk::setTileAndData(int x, int y, int z, int tile_, int data_) { - - int tile = tile_ & 0xff; - - int oldHeight = heightmap[z << 4 | x]; - - int old = blocks[x << 11 | z << 7 | y]; - if (old == tile && data.get(x, y, z) == data_) return false; - int xOffs = xt + x; - int zOffs = zt + z; - blocks[x << 11 | z << 7 | y] = (unsigned char) tile; - if (old != 0) { - if (!level->isClientSide) { - Tile::tiles[old]->onRemove(level, xOffs, y, zOffs); - } else if (old != tile && Tile::isEntityTile[old]) { - level->removeTileEntity(xOffs, y, zOffs); - } - } - data.set(x, y, z, data_); - - if (!level->dimension->hasCeiling) { - if (Tile::lightBlock[tile] != 0) { - if (y >= oldHeight) { - recalcHeight(x, y + 1, z); - } - } else { - if (y == oldHeight - 1) { - recalcHeight(x, y, z); - } - } - level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs); - } - - level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs); - lightGaps(x, z); - - if (!level->isClientSide && tile != 0) { - Tile::tiles[tile]->onPlace(level, xOffs, y, zOffs); - } - - this->unsaved = true; - this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift)); - return true; -} - - -/*public*/ -bool LevelChunk::setTile(int x, int y, int z, int tile_) { - - int tile = tile_ & 0xff; - int oldHeight = heightmap[z << 4 | x] & 0xff; - - int old = blocks[x << 11 | z << 7 | y] & 0xff; - if (old == tile_) return false; - int xOffs = xt + x; - int zOffs = zt + z; - blocks[x << 11 | z << 7 | y] = (unsigned char) (tile & 0xff); - if (old != 0) { - Tile::tiles[old]->onRemove(level, xOffs, y, zOffs); - } - data.set(x, y, z, 0); - - if (Tile::lightBlock[tile & 0xff] != 0) { - if (y >= oldHeight) { - recalcHeight(x, y + 1, z); - } - } else { - if (y == oldHeight - 1) { - recalcHeight(x, y, z); - } - } - - level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs); - level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs); - lightGaps(x, z); - - if (tile_ != 0) { - if (!level->isClientSide) Tile::tiles[tile_]->onPlace(level, xOffs, y, zOffs); - } - - this->unsaved = true; - this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift)); - return true; -} - -void LevelChunk::setTileRaw(int x, int y, int z, int tile) { - blocks[x << 11 | z << 7 | y] = tile; -} - -/*public*/ -int LevelChunk::getData(int x, int y, int z) { - return data.get(x, y, z); -} - -/*public*/ -void LevelChunk::recalcHeightmapOnly() { - int min = Level::DEPTH - 1; - for (int x = 0; x < 16; x++) - for (int z = 0; z < 16; z++) { - int y = Level::DEPTH - 1; - int p = x << 11 | z << 7; - while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0) - y--; - heightmap[z << 4 | x] = (char) y; - if (y < min) min = y; - } - - this->minHeight = min; - //this->unsaved = true; -} - -/*public?*/ -void LevelChunk::recalcHeightmap() { - int min = Level::DEPTH - 1; - for (int x = 0; x < 16; x++) - for (int z = 0; z < 16; z++) { - int y = Level::DEPTH - 1; - int p = x << 11 | z << 7; - while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0) - y--; - heightmap[z << 4 | x] = (char) y; - if (y < min) min = y; - - if (!level->dimension->hasCeiling) { - int br = Level::MAX_BRIGHTNESS; - int yy = Level::DEPTH - 1; - do { - br -= Tile::lightBlock[blocks[p + yy] & 0xff]; - if (br > 0) { - skyLight.set(x, yy, z, br); - } - yy--; - } while (yy > 0 && br > 0); - - } - } - - this->minHeight = min; - - for (int x = 0; x < 16; x++) - for (int z = 0; z < 16; z++) { - lightGaps(x, z); - } - - //this->unsaved = true; -} - -/*private*/ -void LevelChunk::recalcHeight(int x, int yStart, int z) { - int yOld = heightmap[z << 4 | x] & 0xff; - int y = yOld; - if (yStart > yOld) y = yStart; - - int p = x << 11 | z << 7; - while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0) - y--; - if (y == yOld) return; - - const int xOffs = xt + x; - const int zOffs = zt + z; - level->lightColumnChanged(xOffs, zOffs, y, yOld); - heightmap[z << 4 | x] = (char) y; - - if (y < minHeight) { - minHeight = y; - } else { - int min = Level::DEPTH - 1; - for (int _x = 0; _x < 16; _x++) - for (int _z = 0; _z < 16; _z++) { - if ((heightmap[_z << 4 | _x] & 0xff) < min) min = (heightmap[_z << 4 | _x] & 0xff); - } - this->minHeight = min; - } - - if (y < yOld) { - for (int yy = y; yy < yOld; yy++) { - skyLight.set(x, yy, z, 15); - } - } else { - level->updateLight(LightLayer::Sky, xOffs, yOld, zOffs, xOffs, y, zOffs); - for (int yy = yOld; yy < y; yy++) { - skyLight.set(x, yy, z, 0); - } - } - - int br = 15; - int y0 = y; - while (y > 0 && br > 0) { - y--; - int block = Tile::lightBlock[getTile(x, y, z)]; - if (block == 0) block = 1; - br -= block; - if (br < 0) br = 0; - skyLight.set(x, y, z, br); - } - while (y > 0 && Tile::lightBlock[getTile(x, y - 1, z)] == 0) - y--; - if (y != y0) { - level->updateLight(LightLayer::Sky, xOffs - 1, y, zOffs - 1, xOffs + 1, y0, zOffs + 1); - } - - //this->unsaved = true; -} - -/*public*/ -void LevelChunk::skyBrightnessChanged() { -// int x0 = xt; -// int y0 = this->minHeight - 16; -// int z0 = zt; -// int x1 = xt + 16; -// int y1 = Level::DEPTH - 1; -// int z1 = zt + 16; - - //level->setTilesDirty(x0, y0, z0, x1, y1, z1); -} - -/*public*/ -bool LevelChunk::shouldSave(bool force) { - if (dontSave) return false; - /* - if (force) { - if (lastSaveHadEntities && level->getTime() != lastSaveTime) return true; - } else { - if (lastSaveHadEntities && level->getTime() >= lastSaveTime + 20 * 30) return true; - } - */ - - return unsaved; -} - -/*public*/ -void LevelChunk::setBlocks(unsigned char* newBlocks, int sub) { //@byte[] - LOGI("LevelChunk::setBlocks\n"); - for (int i = 0; i < 128 * 16 * 4; i++) { - blocks[sub * 128 * 16 * 4 + i] = newBlocks[i]; - } - - for (int x = sub * 4; x < sub * 4 + 4; x++) { - for (int z = 0; z < 16; z++) { - recalcHeight(x, 0, z); - } - } - - level->updateLight(LightLayer::Sky, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16); - level->updateLight(LightLayer::Block, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16); - - //for (int x = sub * 4; x < sub * 4 + 4; x++) { - // for (int z = 0; z < 16; z++) { - // lightGaps(x, z); - // } - //} - level->setTilesDirty(xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt); -} - -/*public*/ -Random LevelChunk::getRandom(long l) { - return /*new*/ Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l); -} - -/*private*/ -void LevelChunk::lightGap( int x, int z, int source ) -{ - int height = level->getHeightmap(x, z); - if (height > source) { - level->updateLight(LightLayer::Sky, x, source, z, x, height, z); - } else if (height < source) { - level->updateLight(LightLayer::Sky, x, height, z, x, source, z); - } -} - -void LevelChunk::clearUpdateMap() -{ - memset(updateMap, 0x0, 256); - unsaved = false; -} - -void LevelChunk::deleteBlockData() -{ - delete [] blocks; - blocks = NULL; -} - -bool LevelChunk::isAt( int x, int z ) -{ - return x == this->x && z == this->z; -} - -int LevelChunk::getHeightmap( int x, int z ) -{ - return heightmap[z << 4 | x] & 0xff; -} - -void LevelChunk::recalcBlockLights() -{ - -} - -void LevelChunk::lightGaps( int x, int z ) -{ - int height = getHeightmap(x, z); - - int xOffs = xt + x; - int zOffs = zt + z; - lightGap(xOffs - 1, zOffs, height); - lightGap(xOffs + 1, zOffs, height); - lightGap(xOffs, zOffs - 1, height); - lightGap(xOffs, zOffs + 1, height); -} - -int LevelChunk::getTile( int x, int y, int z ) -{ - return blocks[x << 11 | z << 7 | y] & 0xff; -} - -void LevelChunk::setData( int x, int y, int z, int val ) -{ - //this->unsaved = true; - data.set(x, y, z, val); -} - -int LevelChunk::getBrightness( const LightLayer& layer, int x, int y, int z ) -{ - if (&layer == &LightLayer::Sky) return skyLight.get(x, y, z); - else if (&layer == &LightLayer::Block) return blockLight.get(x, y, z); - else return 0; -} - -void LevelChunk::setBrightness( const LightLayer& layer, int x, int y, int z, int brightness ) -{ - //this->unsaved = true; - if (&layer == &LightLayer::Sky) skyLight.set(x, y, z, brightness); - else if (&layer == &LightLayer::Block) blockLight.set(x, y, z, brightness); - else return; -} - -int LevelChunk::getRawBrightness( int x, int y, int z, int skyDampen ) -{ - int light = skyLight.get(x, y, z); - if (light > 0) LevelChunk::touchedSky = true; - light -= skyDampen; - int block = blockLight.get(x, y, z); - if (block > light) light = block; - - return light; -} - -void LevelChunk::addEntity( Entity* e ) -{ - lastSaveHadEntities = true; - - int xc = Mth::floor(e->x / 16); - int zc = Mth::floor(e->z / 16); - if (xc != this->x || zc != this->z) { - LOGE("ERR: WRONG LOCATION : %d, %d, %d, %d", xc, x, zc, z); - //Thread.dumpStack(); - } - int yc = Mth::floor(e->y / 16); - if (yc < 0) yc = 0; - if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1; - e->inChunk = true; - e->xChunk = x; - e->yChunk = yc; - e->zChunk = z; - entityBlocks[yc].push_back(e); -} - -void LevelChunk::removeEntity( Entity* e ) -{ - removeEntity(e, e->yChunk); -} - -void LevelChunk::removeEntity( Entity* e, int yc ) -{ - if (yc < 0) yc = 0; - if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1; - - EntityList::iterator newEnd = std::remove( entityBlocks[yc].begin(), entityBlocks[yc].end(), e); - entityBlocks[yc].erase(newEnd, entityBlocks[yc].end()); -} - -bool LevelChunk::isSkyLit( int x, int y, int z ) -{ - return y >= (heightmap[z << 4 | x] & 0xff); -} - -void LevelChunk::load() -{ - loaded = true; - /* level->tileEntityList.addAll(tileEntities.values()); - for (int i = 0; i < entityBlocks.length; i++) { - level->addEntities(entityBlocks[i]); - } - */ -} - -void LevelChunk::unload() -{ - loaded = false; - /* level->tileEntityList.removeAll(tileEntities.values()); - for (int i = 0; i < entityBlocks.length; i++) { - level->removeEntities(entityBlocks[i]); - } - */ -} - -void LevelChunk::markUnsaved() -{ - this->unsaved = true; -} - -void LevelChunk::getEntities( Entity* except, const AABB& bb, std::vector& es ) -{ - int yc0 = Mth::floor((bb.y0 - 2) / 16); - int yc1 = Mth::floor((bb.y1 + 2) / 16); - if (yc0 < 0) yc0 = 0; - if (yc1 >= EntityBlocksArraySize) yc1 = EntityBlocksArraySize - 1; - for (int yc = yc0; yc <= yc1; yc++) { - std::vector& entities = entityBlocks[yc]; - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - if (e != except && e->bb.intersects(bb)){ - es.push_back(e); - } - } - } -} - -void LevelChunk::getEntitiesOfType( int entityType, const AABB& bb, EntityList& list ) -{ - int yc0 = Mth::floor((bb.y0 - 2) / 16); - int yc1 = Mth::floor((bb.y1 + 2) / 16); - if (yc0 < 0) { - yc0 = 0; - } else if (yc0 >= EntityBlocksArraySize) { - yc0 = EntityBlocksArraySize - 1; - } - if (yc1 >= EntityBlocksArraySize) { - yc1 = EntityBlocksArraySize - 1; - } else if (yc1 < 0) { - yc1 = 0; - } - for (int yc = yc0; yc <= yc1; yc++) { - std::vector& entities = entityBlocks[yc]; - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - if (e->getEntityTypeId() == entityType) - list.push_back(e); - //if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e); - } - } -} - -void LevelChunk::getEntitiesOfClass( int type, const AABB& bb, EntityList& list ) -{ - int yc0 = Mth::floor((bb.y0 - 2) / 16); - int yc1 = Mth::floor((bb.y1 + 2) / 16); - if (yc0 < 0) { - yc0 = 0; - } else if (yc0 >= EntityBlocksArraySize) { - yc0 = EntityBlocksArraySize - 1; - } - if (yc1 >= EntityBlocksArraySize) { - yc1 = EntityBlocksArraySize - 1; - } else if (yc1 < 0) { - yc1 = 0; - } - for (int yc = yc0; yc <= yc1; yc++) { - std::vector& entities = entityBlocks[yc]; - for (unsigned int i = 0; i < entities.size(); i++) { - Entity* e = entities[i]; - if (e->getCreatureBaseType() == type) - list.push_back(e); - //if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e); - } - } -} - -int LevelChunk::countEntities() -{ - int entityCount = 0; - for (int yc = 0; yc < EntityBlocksArraySize; yc++) { - entityCount += entityBlocks[yc].size(); - } - return entityCount; -} - -//@note: @todo @te Verify -TileEntity* LevelChunk::getTileEntity(int x, int y, int z) { - TilePos pos(x, y, z); - TEMap::iterator cit = tileEntities.find(pos); - TileEntity* tileEntity = NULL; - //bool ex = cit != tileEntities.end(); - //LOGI("Getting tile entity @ %d, %d, %d. Already existing? %d (%p)\n", x, y, z, ex, ex?cit->second:0); - if (cit == tileEntities.end()) - { - int t = getTile(x, y, z); - if (t <= 0 || !Tile::isEntityTile[t]) - return NULL; - - if (tileEntity == NULL) { - tileEntity = ((EntityTile*) Tile::tiles[t])->newTileEntity(); - level->setTileEntity(xt + x, y, zt + z, tileEntity); - } - // @attn @bug @fix: Don't go via level->setTileEntity since we - // know this tile is loaded if we are here - //cit = tileEntities.find(pos); - //tileEntity = (cit != tileEntities.end())? cit->second : NULL; - } - else { - tileEntity = cit->second; - } - if (tileEntity != NULL && tileEntity->isRemoved()) { - tileEntities.erase(cit); - return NULL; - } - - return tileEntity; -} - -bool LevelChunk::hasTileEntityAt( int x, int y, int z ) -{ - return tileEntities.find(TilePos(x, y, z)) != tileEntities.end(); -} -bool LevelChunk::hasTileEntityAt( TileEntity* te ) -{ - return tileEntities.find(TilePos(te->x & 15, te->y, te->z & 15)) != tileEntities.end(); -} - -void LevelChunk::addTileEntity(TileEntity* te) { - - int xx = te->x - xt; - int yy = te->y; - int zz = te->z - zt; - setTileEntity(xx, yy, zz, te); - if (loaded) { - level->tileEntities.push_back(te); - } -} - -void LevelChunk::setTileEntity(int x, int y, int z, TileEntity* tileEntity) -{ - tileEntity->setLevelAndPos(level, xt + x, y, zt + z); - int t = getTile(x, y, z); - if (t == 0 || !Tile::isEntityTile[t]) { - LOGW("Attempted to place a tile entity where there was no entity tile! %d, %d, %d\n", - tileEntity->x, tileEntity->y, tileEntity->z); - return; - } - - tileEntity->clearRemoved(); - tileEntities.insert(std::make_pair(TilePos(x, y, z), tileEntity)); -} - -void LevelChunk::removeTileEntity(int x, int y, int z) { - if (loaded) { - TilePos pos(x, y, z); - TEMap::iterator cit = tileEntities.find(pos); - if (cit != tileEntities.end()) { - cit->second->setRemoved(); - - if (!level->isClientSide) { - for (unsigned int i = 0; i < level->players.size(); ++i) { - level->players[i]->tileEntityDestroyed(cit->second->runningId); - } - } - tileEntities.erase(cit); - } - } -} - - -int LevelChunk::getBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p ) -{ - int len = y1 - y0; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = x << 11 | z << 7 | y0; - memcpy(data + p, blocks + slot, len); //System.arraycopy(blocks, slot, data, p, len); - p += len; - } - - len = (y1 - y0) / 2; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = (x << 11 | z << 7 | y0) >> 1; - memcpy(data + p, this->data.data + slot, len); //System.arraycopy(this->data.data, slot, data, p, len); - p += len; - } - - //len = (y1 - y0) / 2; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = (x << 11 | z << 7 | y0) >> 1; - memcpy(data + p, blockLight.data + slot, len); //System.arraycopy(blockLight.data, slot, data, p, len); - p += len; - } - - //len = (y1 - y0) / 2; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = (x << 11 | z << 7 | y0) >> 1; - memcpy(data + p, skyLight.data + slot, len); //System.arraycopy(skyLight.data, slot, data, p, len); - p += len; - } - - return p; -} - -int LevelChunk::setBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p ) -{ - int len = y1 - y0; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = x << 11 | z << 7 | y0; - memcpy(blocks + slot, data + p, len); //System.arraycopy(data, p, blocks, slot, len); - p += len; - } - - recalcHeightmapOnly(); - - len = (y1 - y0) / 2; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = (x << 11 | z << 7 | y0) >> 1; - memcpy(this->data.data + slot, data + p, len); //System.arraycopy(data, p, this->data.data, slot, len); - p += len; - } - - //len = (y1 - y0) / 2; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = (x << 11 | z << 7 | y0) >> 1; - memcpy(blockLight.data + slot, data + p, len); //System.arraycopy(data, p, blockLight.data, slot, len); - p += len; - } - - //len = (y1 - y0) / 2; - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) { - int slot = (x << 11 | z << 7 | y0) >> 1; - memcpy(skyLight.data + slot, data + p, len); //System.arraycopy(data, p, skyLight.data, slot, len); - p += len; - } - - return p; -} - -bool LevelChunk::isEmpty() -{ - return false; -} - -const LevelChunk::TEMap& LevelChunk::getTileEntityMap() const { - return tileEntities; -} +#include "LevelChunk.hpp" +#include "world/level/LightLayer.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/Level.hpp" +#include "world/level/dimension/Dimension.hpp" +#include "world/phys/AABB.hpp" +#include "world/entity/Entity.hpp" +#include "world/level/TilePos.hpp" +#include "world/level/tile/entity/TileEntity.hpp" +#include "world/level/tile/EntityTile.hpp" +#include "world/level/LevelConstants.hpp" + +/*static*/ +bool LevelChunk::touchedSky = false; + +LevelChunk::LevelChunk( Level* level, int x, int z ) +: level(level), + x(x), + z(z), + xt(x * CHUNK_WIDTH), + zt(z * CHUNK_DEPTH) +{ + init(); +} + +LevelChunk::LevelChunk( Level* level, unsigned char* blocks, int x, int z ) +: level(level), + x(x), + z(z), + xt(x * CHUNK_WIDTH), + zt(z * CHUNK_DEPTH), + blocks(blocks), + data(ChunkBlockCount), + skyLight(ChunkBlockCount), + blockLight(ChunkBlockCount), + blocksLength(ChunkBlockCount) +{ + init(); +} + +LevelChunk::~LevelChunk() +{ + //delete blocks; +} + +void LevelChunk::init() +{ + terrainPopulated = false; + dontSave = false; + unsaved = false; + lastSaveHadEntities = false; + createdFromSave = false; + lastSaveTime = 0; + memset(heightmap, 0, 256); + memset(updateMap, 0, 256); +} + +/*public*/ +bool LevelChunk::setTileAndData(int x, int y, int z, int tile_, int data_) { + + int tile = tile_ & 0xff; + + int oldHeight = heightmap[z << 4 | x]; + + int old = blocks[x << 11 | z << 7 | y]; + if (old == tile && data.get(x, y, z) == data_) return false; + int xOffs = xt + x; + int zOffs = zt + z; + blocks[x << 11 | z << 7 | y] = (unsigned char) tile; + if (old != 0) { + if (!level->isClientSide) { + Tile::tiles[old]->onRemove(level, xOffs, y, zOffs); + } else if (old != tile && Tile::isEntityTile[old]) { + level->removeTileEntity(xOffs, y, zOffs); + } + } + data.set(x, y, z, data_); + + if (!level->dimension->hasCeiling) { + if (Tile::lightBlock[tile] != 0) { + if (y >= oldHeight) { + recalcHeight(x, y + 1, z); + } + } else { + if (y == oldHeight - 1) { + recalcHeight(x, y, z); + } + } + level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs); + } + + level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs); + lightGaps(x, z); + + if (!level->isClientSide && tile != 0) { + Tile::tiles[tile]->onPlace(level, xOffs, y, zOffs); + } + + this->unsaved = true; + this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift)); + return true; +} + + +/*public*/ +bool LevelChunk::setTile(int x, int y, int z, int tile_) { + + int tile = tile_ & 0xff; + int oldHeight = heightmap[z << 4 | x] & 0xff; + + int old = blocks[x << 11 | z << 7 | y] & 0xff; + if (old == tile_) return false; + int xOffs = xt + x; + int zOffs = zt + z; + blocks[x << 11 | z << 7 | y] = (unsigned char) (tile & 0xff); + if (old != 0) { + Tile::tiles[old]->onRemove(level, xOffs, y, zOffs); + } + data.set(x, y, z, 0); + + if (Tile::lightBlock[tile & 0xff] != 0) { + if (y >= oldHeight) { + recalcHeight(x, y + 1, z); + } + } else { + if (y == oldHeight - 1) { + recalcHeight(x, y, z); + } + } + + level->updateLight(LightLayer::Sky, xOffs, y, zOffs, xOffs, y, zOffs); + level->updateLight(LightLayer::Block, xOffs, y, zOffs, xOffs, y, zOffs); + lightGaps(x, z); + + if (tile_ != 0) { + if (!level->isClientSide) Tile::tiles[tile_]->onPlace(level, xOffs, y, zOffs); + } + + this->unsaved = true; + this->updateMap[x | (z << 4)] |= (1 << (y >> UpdateMapBitShift)); + return true; +} + +void LevelChunk::setTileRaw(int x, int y, int z, int tile) { + blocks[x << 11 | z << 7 | y] = tile; +} + +/*public*/ +int LevelChunk::getData(int x, int y, int z) { + return data.get(x, y, z); +} + +/*public*/ +void LevelChunk::recalcHeightmapOnly() { + int min = Level::DEPTH - 1; + for (int x = 0; x < 16; x++) + for (int z = 0; z < 16; z++) { + int y = Level::DEPTH - 1; + int p = x << 11 | z << 7; + while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0) + y--; + heightmap[z << 4 | x] = (char) y; + if (y < min) min = y; + } + + this->minHeight = min; + //this->unsaved = true; +} + +/*public?*/ +void LevelChunk::recalcHeightmap() { + int min = Level::DEPTH - 1; + for (int x = 0; x < 16; x++) + for (int z = 0; z < 16; z++) { + int y = Level::DEPTH - 1; + int p = x << 11 | z << 7; + while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0) + y--; + heightmap[z << 4 | x] = (char) y; + if (y < min) min = y; + + if (!level->dimension->hasCeiling) { + int br = Level::MAX_BRIGHTNESS; + int yy = Level::DEPTH - 1; + do { + br -= Tile::lightBlock[blocks[p + yy] & 0xff]; + if (br > 0) { + skyLight.set(x, yy, z, br); + } + yy--; + } while (yy > 0 && br > 0); + + } + } + + this->minHeight = min; + + for (int x = 0; x < 16; x++) + for (int z = 0; z < 16; z++) { + lightGaps(x, z); + } + + //this->unsaved = true; +} + +/*private*/ +void LevelChunk::recalcHeight(int x, int yStart, int z) { + int yOld = heightmap[z << 4 | x] & 0xff; + int y = yOld; + if (yStart > yOld) y = yStart; + + int p = x << 11 | z << 7; + while (y > 0 && Tile::lightBlock[blocks[p + y - 1] & 0xff] == 0) + y--; + if (y == yOld) return; + + const int xOffs = xt + x; + const int zOffs = zt + z; + level->lightColumnChanged(xOffs, zOffs, y, yOld); + heightmap[z << 4 | x] = (char) y; + + if (y < minHeight) { + minHeight = y; + } else { + int min = Level::DEPTH - 1; + for (int _x = 0; _x < 16; _x++) + for (int _z = 0; _z < 16; _z++) { + if ((heightmap[_z << 4 | _x] & 0xff) < min) min = (heightmap[_z << 4 | _x] & 0xff); + } + this->minHeight = min; + } + + if (y < yOld) { + for (int yy = y; yy < yOld; yy++) { + skyLight.set(x, yy, z, 15); + } + } else { + level->updateLight(LightLayer::Sky, xOffs, yOld, zOffs, xOffs, y, zOffs); + for (int yy = yOld; yy < y; yy++) { + skyLight.set(x, yy, z, 0); + } + } + + int br = 15; + int y0 = y; + while (y > 0 && br > 0) { + y--; + int block = Tile::lightBlock[getTile(x, y, z)]; + if (block == 0) block = 1; + br -= block; + if (br < 0) br = 0; + skyLight.set(x, y, z, br); + } + while (y > 0 && Tile::lightBlock[getTile(x, y - 1, z)] == 0) + y--; + if (y != y0) { + level->updateLight(LightLayer::Sky, xOffs - 1, y, zOffs - 1, xOffs + 1, y0, zOffs + 1); + } + + //this->unsaved = true; +} + +/*public*/ +void LevelChunk::skyBrightnessChanged() { +// int x0 = xt; +// int y0 = this->minHeight - 16; +// int z0 = zt; +// int x1 = xt + 16; +// int y1 = Level::DEPTH - 1; +// int z1 = zt + 16; + + //level->setTilesDirty(x0, y0, z0, x1, y1, z1); +} + +/*public*/ +bool LevelChunk::shouldSave(bool force) { + if (dontSave) return false; + /* + if (force) { + if (lastSaveHadEntities && level->getTime() != lastSaveTime) return true; + } else { + if (lastSaveHadEntities && level->getTime() >= lastSaveTime + 20 * 30) return true; + } + */ + + return unsaved; +} + +/*public*/ +void LevelChunk::setBlocks(unsigned char* newBlocks, int sub) { //@byte[] + LOGI("LevelChunk::setBlocks\n"); + for (int i = 0; i < 128 * 16 * 4; i++) { + blocks[sub * 128 * 16 * 4 + i] = newBlocks[i]; + } + + for (int x = sub * 4; x < sub * 4 + 4; x++) { + for (int z = 0; z < 16; z++) { + recalcHeight(x, 0, z); + } + } + + level->updateLight(LightLayer::Sky, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16); + level->updateLight(LightLayer::Block, xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt + 16); + + //for (int x = sub * 4; x < sub * 4 + 4; x++) { + // for (int z = 0; z < 16; z++) { + // lightGaps(x, z); + // } + //} + level->setTilesDirty(xt + sub * 4, 0, zt, xt + sub * 4 + 4, 128, zt); +} + +/*public*/ +Random LevelChunk::getRandom(long l) { + return /*new*/ Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l); +} + +/*private*/ +void LevelChunk::lightGap( int x, int z, int source ) +{ + int height = level->getHeightmap(x, z); + if (height > source) { + level->updateLight(LightLayer::Sky, x, source, z, x, height, z); + } else if (height < source) { + level->updateLight(LightLayer::Sky, x, height, z, x, source, z); + } +} + +void LevelChunk::clearUpdateMap() +{ + memset(updateMap, 0x0, 256); + unsaved = false; +} + +void LevelChunk::deleteBlockData() +{ + delete [] blocks; + blocks = NULL; +} + +bool LevelChunk::isAt( int x, int z ) +{ + return x == this->x && z == this->z; +} + +int LevelChunk::getHeightmap( int x, int z ) +{ + return heightmap[z << 4 | x] & 0xff; +} + +void LevelChunk::recalcBlockLights() +{ + +} + +void LevelChunk::lightGaps( int x, int z ) +{ + int height = getHeightmap(x, z); + + int xOffs = xt + x; + int zOffs = zt + z; + lightGap(xOffs - 1, zOffs, height); + lightGap(xOffs + 1, zOffs, height); + lightGap(xOffs, zOffs - 1, height); + lightGap(xOffs, zOffs + 1, height); +} + +int LevelChunk::getTile( int x, int y, int z ) +{ + return blocks[x << 11 | z << 7 | y] & 0xff; +} + +void LevelChunk::setData( int x, int y, int z, int val ) +{ + //this->unsaved = true; + data.set(x, y, z, val); +} + +int LevelChunk::getBrightness( const LightLayer& layer, int x, int y, int z ) +{ + if (&layer == &LightLayer::Sky) return skyLight.get(x, y, z); + else if (&layer == &LightLayer::Block) return blockLight.get(x, y, z); + else return 0; +} + +void LevelChunk::setBrightness( const LightLayer& layer, int x, int y, int z, int brightness ) +{ + //this->unsaved = true; + if (&layer == &LightLayer::Sky) skyLight.set(x, y, z, brightness); + else if (&layer == &LightLayer::Block) blockLight.set(x, y, z, brightness); + else return; +} + +int LevelChunk::getRawBrightness( int x, int y, int z, int skyDampen ) +{ + int light = skyLight.get(x, y, z); + if (light > 0) LevelChunk::touchedSky = true; + light -= skyDampen; + int block = blockLight.get(x, y, z); + if (block > light) light = block; + + return light; +} + +void LevelChunk::addEntity( Entity* e ) +{ + lastSaveHadEntities = true; + + int xc = Mth::floor(e->x / 16); + int zc = Mth::floor(e->z / 16); + if (xc != this->x || zc != this->z) { + LOGE("ERR: WRONG LOCATION : %d, %d, %d, %d", xc, x, zc, z); + //Thread.dumpStack(); + } + int yc = Mth::floor(e->y / 16); + if (yc < 0) yc = 0; + if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1; + e->inChunk = true; + e->xChunk = x; + e->yChunk = yc; + e->zChunk = z; + entityBlocks[yc].push_back(e); +} + +void LevelChunk::removeEntity( Entity* e ) +{ + removeEntity(e, e->yChunk); +} + +void LevelChunk::removeEntity( Entity* e, int yc ) +{ + if (yc < 0) yc = 0; + if (yc >= EntityBlocksArraySize) yc = EntityBlocksArraySize - 1; + + EntityList::iterator newEnd = std::remove( entityBlocks[yc].begin(), entityBlocks[yc].end(), e); + entityBlocks[yc].erase(newEnd, entityBlocks[yc].end()); +} + +bool LevelChunk::isSkyLit( int x, int y, int z ) +{ + return y >= (heightmap[z << 4 | x] & 0xff); +} + +void LevelChunk::load() +{ + loaded = true; + /* level->tileEntityList.addAll(tileEntities.values()); + for (int i = 0; i < entityBlocks.length; i++) { + level->addEntities(entityBlocks[i]); + } + */ +} + +void LevelChunk::unload() +{ + loaded = false; + /* level->tileEntityList.removeAll(tileEntities.values()); + for (int i = 0; i < entityBlocks.length; i++) { + level->removeEntities(entityBlocks[i]); + } + */ +} + +void LevelChunk::markUnsaved() +{ + this->unsaved = true; +} + +void LevelChunk::getEntities( Entity* except, const AABB& bb, std::vector& es ) +{ + int yc0 = Mth::floor((bb.y0 - 2) / 16); + int yc1 = Mth::floor((bb.y1 + 2) / 16); + if (yc0 < 0) yc0 = 0; + if (yc1 >= EntityBlocksArraySize) yc1 = EntityBlocksArraySize - 1; + for (int yc = yc0; yc <= yc1; yc++) { + std::vector& entities = entityBlocks[yc]; + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + if (e != except && e->bb.intersects(bb)){ + es.push_back(e); + } + } + } +} + +void LevelChunk::getEntitiesOfType( int entityType, const AABB& bb, EntityList& list ) +{ + int yc0 = Mth::floor((bb.y0 - 2) / 16); + int yc1 = Mth::floor((bb.y1 + 2) / 16); + if (yc0 < 0) { + yc0 = 0; + } else if (yc0 >= EntityBlocksArraySize) { + yc0 = EntityBlocksArraySize - 1; + } + if (yc1 >= EntityBlocksArraySize) { + yc1 = EntityBlocksArraySize - 1; + } else if (yc1 < 0) { + yc1 = 0; + } + for (int yc = yc0; yc <= yc1; yc++) { + std::vector& entities = entityBlocks[yc]; + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + if (e->getEntityTypeId() == entityType) + list.push_back(e); + //if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e); + } + } +} + +void LevelChunk::getEntitiesOfClass( int type, const AABB& bb, EntityList& list ) +{ + int yc0 = Mth::floor((bb.y0 - 2) / 16); + int yc1 = Mth::floor((bb.y1 + 2) / 16); + if (yc0 < 0) { + yc0 = 0; + } else if (yc0 >= EntityBlocksArraySize) { + yc0 = EntityBlocksArraySize - 1; + } + if (yc1 >= EntityBlocksArraySize) { + yc1 = EntityBlocksArraySize - 1; + } else if (yc1 < 0) { + yc1 = 0; + } + for (int yc = yc0; yc <= yc1; yc++) { + std::vector& entities = entityBlocks[yc]; + for (unsigned int i = 0; i < entities.size(); i++) { + Entity* e = entities[i]; + if (e->getCreatureBaseType() == type) + list.push_back(e); + //if (baseClass.isAssignableFrom(e.getClass()) && e.bb.intersects(bb)) es.add(e); + } + } +} + +int LevelChunk::countEntities() +{ + int entityCount = 0; + for (int yc = 0; yc < EntityBlocksArraySize; yc++) { + entityCount += entityBlocks[yc].size(); + } + return entityCount; +} + +//@note: @todo @te Verify +TileEntity* LevelChunk::getTileEntity(int x, int y, int z) { + TilePos pos(x, y, z); + TEMap::iterator cit = tileEntities.find(pos); + TileEntity* tileEntity = NULL; + //bool ex = cit != tileEntities.end(); + //LOGI("Getting tile entity @ %d, %d, %d. Already existing? %d (%p)\n", x, y, z, ex, ex?cit->second:0); + if (cit == tileEntities.end()) + { + int t = getTile(x, y, z); + if (t <= 0 || !Tile::isEntityTile[t]) + return NULL; + + if (tileEntity == NULL) { + tileEntity = ((EntityTile*) Tile::tiles[t])->newTileEntity(); + level->setTileEntity(xt + x, y, zt + z, tileEntity); + } + // @attn @bug @fix: Don't go via level->setTileEntity since we + // know this tile is loaded if we are here + //cit = tileEntities.find(pos); + //tileEntity = (cit != tileEntities.end())? cit->second : NULL; + } + else { + tileEntity = cit->second; + } + if (tileEntity != NULL && tileEntity->isRemoved()) { + tileEntities.erase(cit); + return NULL; + } + + return tileEntity; +} + +bool LevelChunk::hasTileEntityAt( int x, int y, int z ) +{ + return tileEntities.find(TilePos(x, y, z)) != tileEntities.end(); +} +bool LevelChunk::hasTileEntityAt( TileEntity* te ) +{ + return tileEntities.find(TilePos(te->x & 15, te->y, te->z & 15)) != tileEntities.end(); +} + +void LevelChunk::addTileEntity(TileEntity* te) { + + int xx = te->x - xt; + int yy = te->y; + int zz = te->z - zt; + setTileEntity(xx, yy, zz, te); + if (loaded) { + level->tileEntities.push_back(te); + } +} + +void LevelChunk::setTileEntity(int x, int y, int z, TileEntity* tileEntity) +{ + tileEntity->setLevelAndPos(level, xt + x, y, zt + z); + int t = getTile(x, y, z); + if (t == 0 || !Tile::isEntityTile[t]) { + LOGW("Attempted to place a tile entity where there was no entity tile! %d, %d, %d\n", + tileEntity->x, tileEntity->y, tileEntity->z); + return; + } + + tileEntity->clearRemoved(); + tileEntities.insert(std::make_pair(TilePos(x, y, z), tileEntity)); +} + +void LevelChunk::removeTileEntity(int x, int y, int z) { + if (loaded) { + TilePos pos(x, y, z); + TEMap::iterator cit = tileEntities.find(pos); + if (cit != tileEntities.end()) { + cit->second->setRemoved(); + + if (!level->isClientSide) { + for (unsigned int i = 0; i < level->players.size(); ++i) { + level->players[i]->tileEntityDestroyed(cit->second->runningId); + } + } + tileEntities.erase(cit); + } + } +} + + +int LevelChunk::getBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p ) +{ + int len = y1 - y0; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = x << 11 | z << 7 | y0; + memcpy(data + p, blocks + slot, len); //System.arraycopy(blocks, slot, data, p, len); + p += len; + } + + len = (y1 - y0) / 2; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = (x << 11 | z << 7 | y0) >> 1; + memcpy(data + p, this->data.data + slot, len); //System.arraycopy(this->data.data, slot, data, p, len); + p += len; + } + + //len = (y1 - y0) / 2; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = (x << 11 | z << 7 | y0) >> 1; + memcpy(data + p, blockLight.data + slot, len); //System.arraycopy(blockLight.data, slot, data, p, len); + p += len; + } + + //len = (y1 - y0) / 2; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = (x << 11 | z << 7 | y0) >> 1; + memcpy(data + p, skyLight.data + slot, len); //System.arraycopy(skyLight.data, slot, data, p, len); + p += len; + } + + return p; +} + +int LevelChunk::setBlocksAndData( unsigned char* data, int x0, int y0, int z0, int x1, int y1, int z1, int p ) +{ + int len = y1 - y0; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = x << 11 | z << 7 | y0; + memcpy(blocks + slot, data + p, len); //System.arraycopy(data, p, blocks, slot, len); + p += len; + } + + recalcHeightmapOnly(); + + len = (y1 - y0) / 2; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = (x << 11 | z << 7 | y0) >> 1; + memcpy(this->data.data + slot, data + p, len); //System.arraycopy(data, p, this->data.data, slot, len); + p += len; + } + + //len = (y1 - y0) / 2; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = (x << 11 | z << 7 | y0) >> 1; + memcpy(blockLight.data + slot, data + p, len); //System.arraycopy(data, p, blockLight.data, slot, len); + p += len; + } + + //len = (y1 - y0) / 2; + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) { + int slot = (x << 11 | z << 7 | y0) >> 1; + memcpy(skyLight.data + slot, data + p, len); //System.arraycopy(data, p, skyLight.data, slot, len); + p += len; + } + + return p; +} + +bool LevelChunk::isEmpty() +{ + return false; +} + +const LevelChunk::TEMap& LevelChunk::getTileEntityMap() const { + return tileEntities; +} diff --git a/src/world/level/chunk/LevelChunk.h b/src/world/level/chunk/LevelChunk.hpp similarity index 96% rename from src/world/level/chunk/LevelChunk.h rename to src/world/level/chunk/LevelChunk.hpp index 20e2438..316102a 100755 --- a/src/world/level/chunk/LevelChunk.h +++ b/src/world/level/chunk/LevelChunk.hpp @@ -5,10 +5,10 @@ #include #include #include -#include "DataLayer.h" -#include "../LevelConstants.h" -#include "../../../util/Random.h" -#include "../TilePos.h" +#include "DataLayer.hpp" +#include "world/level/LevelConstants.hpp" +#include "util/Random.hpp" +#include "world/level/TilePos.hpp" class Level; class Entity; diff --git a/src/world/level/chunk/storage/ChunkStorage.h b/src/world/level/chunk/storage/ChunkStorage.hpp similarity index 100% rename from src/world/level/chunk/storage/ChunkStorage.h rename to src/world/level/chunk/storage/ChunkStorage.hpp diff --git a/src/world/level/chunk/storage/MemoryChunkStorage.h b/src/world/level/chunk/storage/MemoryChunkStorage.hpp similarity index 80% rename from src/world/level/chunk/storage/MemoryChunkStorage.h rename to src/world/level/chunk/storage/MemoryChunkStorage.hpp index 74443ea..206d5b9 100755 --- a/src/world/level/chunk/storage/MemoryChunkStorage.h +++ b/src/world/level/chunk/storage/MemoryChunkStorage.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.chunk.storage; -#include "ChunkStorage.h" +#include "ChunkStorage.hpp" class MemoryChunkStorage: public ChunkStorage {}; diff --git a/src/world/level/dimension/Dimension.cpp b/src/world/level/dimension/Dimension.cpp index 1345c07..6ac137e 100755 --- a/src/world/level/dimension/Dimension.cpp +++ b/src/world/level/dimension/Dimension.cpp @@ -1,140 +1,140 @@ -#include "Dimension.h" -#include "NormalDayCycleDimension.h" - -//#include "../levelgen/SimpleLevelSource.h" -#include "../levelgen/RandomLevelSource.h" -#include "../Level.h" -#include "../biome/BiomeSource.h" -#include "../chunk/ChunkSource.h" -#include "../tile/Tile.h" -#include "../../../util/Mth.h" - - -Dimension::Dimension() -: foggy(false), - ultraWarm(false), - hasCeiling(false), - biomeSource(NULL), - id(0) -{ -} - -Dimension::~Dimension() -{ - delete biomeSource; -} - -void Dimension::init( Level* level ) -{ - this->level = level; - init(); - updateLightRamp(); -} - -void Dimension::init() -{ - biomeSource = new BiomeSource(level); -} - -/*virtual*/ -bool Dimension::isValidSpawn(int x, int z) { - int topTile = level->getTopTile(x, z); - - if (topTile == Tile::invisible_bedrock->id) - return false; - - //if (topTile != Tile::sand->id) return false; - if (!Tile::tiles[topTile]->isSolidRender()) return false; - - return true; -} - -float Dimension::getTimeOfDay(long time, float a) { - return 1; -} - -ChunkSource* Dimension::createRandomLevelSource() { - return new RandomLevelSource( - level, - level->getSeed(), - level->getLevelData()->getGeneratorVersion(), - !level->isClientSide && level->getLevelData()->getSpawnMobs()); - //return new PerformanceTestChunkSource(level); -} - - -void Dimension::updateLightRamp() -{ - float ambientLight = 0.05f; - for (int i = 0; i <= 15; /*Level::MAX_BRIGHTNESS;*/ i++) { - float v = (1 - i / (float) (16 /*Level::MAX_BRIGHTNESS*/)); - // Boosted ambient lightning by ten times. - brightnessRamp[i] = ((1 - v) / (v * 3 + 1)) * (1 - ambientLight) + ambientLight * 3; - } -} - -float* Dimension::getSunriseColor( float td, float a ) -{ - float span = 0.4f; - float tt = Mth::cos(td * Mth::PI * 2) - 0.0f; - float mid = -0.0f; - if (tt >= mid - span && tt <= mid + span) { - float aa = ((tt - mid) / span) * 0.5f + 0.5f; - float mix = 1 - (((1 - Mth::sin(aa * Mth::PI))) * 0.99f); - mix = mix * mix; - sunriseCol[0] = (aa * 0.3f + 0.7f); - sunriseCol[1] = (aa * aa * 0.7f + 0.2f); - sunriseCol[2] = (aa * aa * 0.0f + 0.2f); - sunriseCol[3] = mix; - return sunriseCol; - } - return NULL; -} - -Vec3 Dimension::getFogColor( float td, float a ) -{ - float br = Mth::cos(td * Mth::PI * 2) * 2 + 0.5f; - if (br < 0.0f) br = 0.0f; - if (br > 1.0f) br = 1.0f; - - float r = ((fogColor >> 16) & 0xff) / 255.0f; - float g = ((fogColor >> 8) & 0xff) / 255.0f; - float b = ((fogColor) & 0xff) / 255.0f; - r *= br * 0.94f + 0.06f; - g *= br * 0.94f + 0.06f; - b *= br * 0.91f + 0.09f; - return Vec3(r, g, b); - //return Vec3(0.752941f, 0.847059f, 1); -} - -bool Dimension::mayRespawn() -{ - return true; -} - -Dimension* Dimension::getNew( int id ) -{ - if (id == NORMAL) return new Dimension(); - if (id == NORMAL_DAYCYCLE) return new NormalDayCycleDimension(); - return NULL; -} - -// -// DimensionFactory -// -#include "../storage/LevelData.h" -Dimension* DimensionFactory::createDefaultDimension(LevelData* data ) -{ - int dimensionId = Dimension::NORMAL; - - switch(data->getGameType()) { - case GameType::Survival: dimensionId = Dimension::NORMAL_DAYCYCLE; - break; - case GameType::Creative: - default: - dimensionId = Dimension::NORMAL; - break; - } - - return Dimension::getNew(dimensionId); -} +#include "Dimension.hpp" +#include "NormalDayCycleDimension.hpp" + +//#include "world/level/levelgen/SimpleLevelSource.hpp" +#include "world/level/levelgen/RandomLevelSource.hpp" +#include "world/level/Level.hpp" +#include "world/level/biome/BiomeSource.hpp" +#include "world/level/chunk/ChunkSource.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Mth.hpp" + + +Dimension::Dimension() +: foggy(false), + ultraWarm(false), + hasCeiling(false), + biomeSource(NULL), + id(0) +{ +} + +Dimension::~Dimension() +{ + delete biomeSource; +} + +void Dimension::init( Level* level ) +{ + this->level = level; + init(); + updateLightRamp(); +} + +void Dimension::init() +{ + biomeSource = new BiomeSource(level); +} + +/*virtual*/ +bool Dimension::isValidSpawn(int x, int z) { + int topTile = level->getTopTile(x, z); + + if (topTile == Tile::invisible_bedrock->id) + return false; + + //if (topTile != Tile::sand->id) return false; + if (!Tile::tiles[topTile]->isSolidRender()) return false; + + return true; +} + +float Dimension::getTimeOfDay(long time, float a) { + return 1; +} + +ChunkSource* Dimension::createRandomLevelSource() { + return new RandomLevelSource( + level, + level->getSeed(), + level->getLevelData()->getGeneratorVersion(), + !level->isClientSide && level->getLevelData()->getSpawnMobs()); + //return new PerformanceTestChunkSource(level); +} + + +void Dimension::updateLightRamp() +{ + float ambientLight = 0.05f; + for (int i = 0; i <= 15; /*Level::MAX_BRIGHTNESS;*/ i++) { + float v = (1 - i / (float) (16 /*Level::MAX_BRIGHTNESS*/)); + // Boosted ambient lightning by ten times. + brightnessRamp[i] = ((1 - v) / (v * 3 + 1)) * (1 - ambientLight) + ambientLight * 3; + } +} + +float* Dimension::getSunriseColor( float td, float a ) +{ + float span = 0.4f; + float tt = Mth::cos(td * Mth::PI * 2) - 0.0f; + float mid = -0.0f; + if (tt >= mid - span && tt <= mid + span) { + float aa = ((tt - mid) / span) * 0.5f + 0.5f; + float mix = 1 - (((1 - Mth::sin(aa * Mth::PI))) * 0.99f); + mix = mix * mix; + sunriseCol[0] = (aa * 0.3f + 0.7f); + sunriseCol[1] = (aa * aa * 0.7f + 0.2f); + sunriseCol[2] = (aa * aa * 0.0f + 0.2f); + sunriseCol[3] = mix; + return sunriseCol; + } + return NULL; +} + +Vec3 Dimension::getFogColor( float td, float a ) +{ + float br = Mth::cos(td * Mth::PI * 2) * 2 + 0.5f; + if (br < 0.0f) br = 0.0f; + if (br > 1.0f) br = 1.0f; + + float r = ((fogColor >> 16) & 0xff) / 255.0f; + float g = ((fogColor >> 8) & 0xff) / 255.0f; + float b = ((fogColor) & 0xff) / 255.0f; + r *= br * 0.94f + 0.06f; + g *= br * 0.94f + 0.06f; + b *= br * 0.91f + 0.09f; + return Vec3(r, g, b); + //return Vec3(0.752941f, 0.847059f, 1); +} + +bool Dimension::mayRespawn() +{ + return true; +} + +Dimension* Dimension::getNew( int id ) +{ + if (id == NORMAL) return new Dimension(); + if (id == NORMAL_DAYCYCLE) return new NormalDayCycleDimension(); + return NULL; +} + +// +// DimensionFactory +// +#include "world/level/storage/LevelData.hpp" +Dimension* DimensionFactory::createDefaultDimension(LevelData* data ) +{ + int dimensionId = Dimension::NORMAL; + + switch(data->getGameType()) { + case GameType::Survival: dimensionId = Dimension::NORMAL_DAYCYCLE; + break; + case GameType::Creative: + default: + dimensionId = Dimension::NORMAL; + break; + } + + return Dimension::getNew(dimensionId); +} diff --git a/src/world/level/dimension/Dimension.h b/src/world/level/dimension/Dimension.hpp similarity index 97% rename from src/world/level/dimension/Dimension.h rename to src/world/level/dimension/Dimension.hpp index 081ca23..e19ccb5 100755 --- a/src/world/level/dimension/Dimension.h +++ b/src/world/level/dimension/Dimension.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.dimension; -#include "../../phys/Vec3.h" +#include "world/phys/Vec3.hpp" class Level; class BiomeSource; diff --git a/src/world/level/dimension/NormalDayCycleDimension.h b/src/world/level/dimension/NormalDayCycleDimension.hpp similarity index 91% rename from src/world/level/dimension/NormalDayCycleDimension.h rename to src/world/level/dimension/NormalDayCycleDimension.hpp index 1127714..8a9e80f 100755 --- a/src/world/level/dimension/NormalDayCycleDimension.h +++ b/src/world/level/dimension/NormalDayCycleDimension.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.dimension; -#include "Dimension.h" -#include "../Level.h" -#include "../../../util/Mth.h" +#include "Dimension.hpp" +#include "world/level/Level.hpp" +#include "util/Mth.hpp" class NormalDayCycleDimension: public Dimension { public: diff --git a/src/world/level/levelgen/CanyonFeature.cpp b/src/world/level/levelgen/CanyonFeature.cpp index f7d9ca3..df24332 100755 --- a/src/world/level/levelgen/CanyonFeature.cpp +++ b/src/world/level/levelgen/CanyonFeature.cpp @@ -1,168 +1,168 @@ -#if 0 - -#include "CanyonFeature.h" - -#include "../Level.h" -#include "../tile/Tile.h" -#include "../../../util/Random.h" -#include "../../../util/Mth.h" - -void CanyonFeature::addTunnel( int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale ) -{ - float xMid = xOffs * 16 + 8; - float zMid = zOffs * 16 + 8; - - float yRota = 0; - float xRota = 0; - // int dist = CAVE_RADIUS * 16 - 16; - // if (step>0) dist = step*2; - Random random(this->random.nextLong()); - - if (dist <= 0) { - int max = radius * 16 - 16; - dist = max - random.nextInt(max / 4); - } - bool singleStep = false; - - if (step == -1) { - step = dist / 2; - singleStep = true; - } - - int splitPoint = random.nextInt(dist / 2) + dist / 4; - bool steep = random.nextInt(6) == 0; - - for (; step < dist; step++) { - float rad = 1.5 + (sin(step * Mth::PI / dist) * thickness) * 1; - float yRad = rad * yScale; - - float xc = cos(xRot); - float xs = sin(xRot); - xCave += cos(yRot) * xc; - yCave += xs; - zCave += sin(yRot) * xc; - - if (steep) { - xRot *= 0.92f; - } else { - xRot *= 0.7f; - } - xRot += xRota * 0.1f; - yRot += yRota * 0.1f; - - xRota *= 0.50f; - yRota *= 0.50f; - xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2; - yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4; - - - if (!singleStep && step == splitPoint && thickness > 1) { - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - Mth::PI / 2, xRot / 3, step, dist, 1.0); - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + Mth::PI / 2, xRot / 3, step, dist, 1.0); - return; - } - if (!singleStep && random.nextInt(4) == 0) continue; - - { - float xd = xCave - xMid; - float zd = zCave - zMid; - float remaining = dist - step; - float rr = (thickness + 2) + 16; - if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { - return; - } - } - - if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; - - int x0 = floor(xCave - rad) - xOffs * 16 - 1; - int x1 = floor(xCave + rad) - xOffs * 16 + 1; - - int y0 = floor(yCave - yRad) - 1; - int y1 = floor(yCave + yRad) + 1; - - int z0 = floor(zCave - rad) - zOffs * 16 - 1; - int z1 = floor(zCave + rad) - zOffs * 16 + 1; - - if (x0 < 0) x0 = 0; - if (x1 > 16) x1 = 16; - - if (y0 < 1) y0 = 1; - if (y1 > 120) y1 = 120; - - if (z0 < 0) z0 = 0; - if (z1 > 16) z1 = 16; - - bool detectedWater = false; - for (int xx = x0; !detectedWater && xx < x1; xx++) { - for (int zz = z0; !detectedWater && zz < z1; zz++) { - for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { - int p = (xx * 16 + zz) * 128 + yy; - if (yy < 0 || yy >= Level::DEPTH) continue; - if (blocks[p] == Tile::water->id || blocks[p] == Tile::calmWater->id) { - detectedWater = true; - } - if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { - yy = y0; - } - } - } - } - if (detectedWater) continue; - - for (int xx = x0; xx < x1; xx++) { - float xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; - for (int zz = z0; zz < z1; zz++) { - float zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; - int p = (xx * 16 + zz) * 128 + y1; - bool hasGrass = false; - for (int yy = y1 - 1; yy >= y0; yy--) { - float yd = (yy + 0.5 - yCave) / yRad; - if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) { - int block = blocks[p]; - if (block == Tile::grass->id) hasGrass = true; - if (block == Tile::rock->id || block == Tile::dirt->id || block == Tile::grass->id) { - if (yy < 10) { - blocks[p] = (unsigned char) Tile::lava->id; - } else { - blocks[p] = (unsigned char) 0; - if (hasGrass && blocks[p - 1] == Tile::dirt->id) blocks[p - 1] = (unsigned char) Tile::grass->id; - } - } - } - p--; - } - } - } - if (singleStep) break; - } -} - -void CanyonFeature::addFeature( Level level, int x, int z, int xOffs, int zOffs, char* blocks ) -{ - if (random.nextInt(15) != 0) return; - - float xCave = x * 16 + random.nextInt(16); - float yCave = random.nextInt(random.nextInt(120) + 8); - float zCave = z * 16 + random.nextInt(16); - - float yRot = random.nextFloat() * Mth::PI * 2; - float xRot = ((random.nextFloat() - 0.5f) * 2) / 8; - float thickness = (random.nextFloat() * 2 + random.nextFloat()) + 1; - - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 5.0); -} - - /* //private - void addCaves(Level level, int xOffs, int zOffs, byte[] blocks) { - int r = radius; - - random.setSeed(level.seed); - long xScale = random.nextLong() / 2 * 2 + 1; - long zScale = random.nextLong() / 2 * 2 + 1; - - for (int x = xOffs - r; x <= xOffs + r; x++) { - for (int z = zOffs - r; z <= zOffs + r; z++) { - random.setSeed((x * xScale + z * zScale) ^ level.seed);*/ - -#endif +#if 0 + +#include "CanyonFeature.hpp" + +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Random.hpp" +#include "util/Mth.hpp" + +void CanyonFeature::addTunnel( int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale ) +{ + float xMid = xOffs * 16 + 8; + float zMid = zOffs * 16 + 8; + + float yRota = 0; + float xRota = 0; + // int dist = CAVE_RADIUS * 16 - 16; + // if (step>0) dist = step*2; + Random random(this->random.nextLong()); + + if (dist <= 0) { + int max = radius * 16 - 16; + dist = max - random.nextInt(max / 4); + } + bool singleStep = false; + + if (step == -1) { + step = dist / 2; + singleStep = true; + } + + int splitPoint = random.nextInt(dist / 2) + dist / 4; + bool steep = random.nextInt(6) == 0; + + for (; step < dist; step++) { + float rad = 1.5 + (sin(step * Mth::PI / dist) * thickness) * 1; + float yRad = rad * yScale; + + float xc = cos(xRot); + float xs = sin(xRot); + xCave += cos(yRot) * xc; + yCave += xs; + zCave += sin(yRot) * xc; + + if (steep) { + xRot *= 0.92f; + } else { + xRot *= 0.7f; + } + xRot += xRota * 0.1f; + yRot += yRota * 0.1f; + + xRota *= 0.50f; + yRota *= 0.50f; + xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2; + yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4; + + + if (!singleStep && step == splitPoint && thickness > 1) { + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - Mth::PI / 2, xRot / 3, step, dist, 1.0); + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + Mth::PI / 2, xRot / 3, step, dist, 1.0); + return; + } + if (!singleStep && random.nextInt(4) == 0) continue; + + { + float xd = xCave - xMid; + float zd = zCave - zMid; + float remaining = dist - step; + float rr = (thickness + 2) + 16; + if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { + return; + } + } + + if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; + + int x0 = floor(xCave - rad) - xOffs * 16 - 1; + int x1 = floor(xCave + rad) - xOffs * 16 + 1; + + int y0 = floor(yCave - yRad) - 1; + int y1 = floor(yCave + yRad) + 1; + + int z0 = floor(zCave - rad) - zOffs * 16 - 1; + int z1 = floor(zCave + rad) - zOffs * 16 + 1; + + if (x0 < 0) x0 = 0; + if (x1 > 16) x1 = 16; + + if (y0 < 1) y0 = 1; + if (y1 > 120) y1 = 120; + + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; + + bool detectedWater = false; + for (int xx = x0; !detectedWater && xx < x1; xx++) { + for (int zz = z0; !detectedWater && zz < z1; zz++) { + for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { + int p = (xx * 16 + zz) * 128 + yy; + if (yy < 0 || yy >= Level::DEPTH) continue; + if (blocks[p] == Tile::water->id || blocks[p] == Tile::calmWater->id) { + detectedWater = true; + } + if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { + yy = y0; + } + } + } + } + if (detectedWater) continue; + + for (int xx = x0; xx < x1; xx++) { + float xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; + for (int zz = z0; zz < z1; zz++) { + float zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; + int p = (xx * 16 + zz) * 128 + y1; + bool hasGrass = false; + for (int yy = y1 - 1; yy >= y0; yy--) { + float yd = (yy + 0.5 - yCave) / yRad; + if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) { + int block = blocks[p]; + if (block == Tile::grass->id) hasGrass = true; + if (block == Tile::rock->id || block == Tile::dirt->id || block == Tile::grass->id) { + if (yy < 10) { + blocks[p] = (unsigned char) Tile::lava->id; + } else { + blocks[p] = (unsigned char) 0; + if (hasGrass && blocks[p - 1] == Tile::dirt->id) blocks[p - 1] = (unsigned char) Tile::grass->id; + } + } + } + p--; + } + } + } + if (singleStep) break; + } +} + +void CanyonFeature::addFeature( Level level, int x, int z, int xOffs, int zOffs, char* blocks ) +{ + if (random.nextInt(15) != 0) return; + + float xCave = x * 16 + random.nextInt(16); + float yCave = random.nextInt(random.nextInt(120) + 8); + float zCave = z * 16 + random.nextInt(16); + + float yRot = random.nextFloat() * Mth::PI * 2; + float xRot = ((random.nextFloat() - 0.5f) * 2) / 8; + float thickness = (random.nextFloat() * 2 + random.nextFloat()) + 1; + + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 5.0); +} + + /* //private + void addCaves(Level level, int xOffs, int zOffs, byte[] blocks) { + int r = radius; + + random.setSeed(level.seed); + long xScale = random.nextLong() / 2 * 2 + 1; + long zScale = random.nextLong() / 2 * 2 + 1; + + for (int x = xOffs - r; x <= xOffs + r; x++) { + for (int z = zOffs - r; z <= zOffs + r; z++) { + random.setSeed((x * xScale + z * zScale) ^ level.seed);*/ + +#endif diff --git a/src/world/level/levelgen/CanyonFeature.h b/src/world/level/levelgen/CanyonFeature.hpp similarity index 93% rename from src/world/level/levelgen/CanyonFeature.h rename to src/world/level/levelgen/CanyonFeature.hpp index 217c479..6d3ca84 100755 --- a/src/world/level/levelgen/CanyonFeature.h +++ b/src/world/level/levelgen/CanyonFeature.hpp @@ -4,7 +4,7 @@ //package net.minecraft.world.level.levelgen; -#include "LargeFeature.h" +#include "LargeFeature.hpp" class CanyonFeature: public LargeFeature { diff --git a/src/world/level/levelgen/DungeonFeature.cpp b/src/world/level/levelgen/DungeonFeature.cpp index 9c8d733..23d6b75 100755 --- a/src/world/level/levelgen/DungeonFeature.cpp +++ b/src/world/level/levelgen/DungeonFeature.cpp @@ -1,176 +1,176 @@ -#if 0 - -#include "DungeonFeature.h" - -#include "../Level.h" -#include "../tile/Tile.h" -#include "../../../util/Random.h" -#include "../../../util/Mth.h" - -void DungeonFeature::addRoom( int xOffs, int zOffs, unsigned char* blocks, float xRoom, float yRoom, float zRoom ) -{ - addTunnel(xOffs, zOffs, blocks, xRoom, yRoom, zRoom, 1 + random.nextFloat() * 6, 0, 0, -1, -1, 0.5); -} - -void DungeonFeature::addTunnel( int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale ) -{ - float xMid = xOffs * 16 + 8; - float zMid = zOffs * 16 + 8; - - float yRota = 0; - float xRota = 0; - // int dist = CAVE_RADIUS * 16 - 16; - // if (step>0) dist = step*2; - Random random(this->random.nextLong()); - - if (dist <= 0) { - int max = radius * 16 - 16; - dist = max - random.nextInt(max / 4); - } - bool singleStep = false; - - if (step == -1) { - step = dist / 2; - singleStep = true; - } - - - int splitPoint = random.nextInt(dist / 2) + dist / 4; - bool steep = random.nextInt(6) == 0; - - for (; step < dist; step++) { - float rad = 1.5 + (sin(step * Mth::PI / dist) * thickness) * 1; - float yRad = rad * yScale; - - float xc = cos(xRot); - float xs = sin(xRot); - xCave += cos(yRot) * xc; - yCave += xs; - zCave += sin(yRot) * xc; - - if (steep) { - xRot *= 0.92f; - } else { - xRot *= 0.7f; - } - xRot += xRota * 0.1f; - yRot += yRota * 0.1f; - - xRota *= 0.90f; - yRota *= 0.75f; - xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2; - yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4; - - - if (!singleStep && step == splitPoint && thickness > 1) { - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - Mth::PI / 2, xRot / 3, step, dist, 1.0); - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + Mth::PI / 2, xRot / 3, step, dist, 1.0); - return; - } - if (!singleStep && random.nextInt(4) == 0) continue; - - { - float xd = xCave - xMid; - float zd = zCave - zMid; - float remaining = dist - step; - float rr = (thickness + 2) + 16; - if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { - return; - } - } - - if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; - - int x0 = floor(xCave - rad) - xOffs * 16 - 1; - int x1 = floor(xCave + rad) - xOffs * 16 + 1; - - int y0 = floor(yCave - yRad) - 1; - int y1 = floor(yCave + yRad) + 1; - - int z0 = floor(zCave - rad) - zOffs * 16 - 1; - int z1 = floor(zCave + rad) - zOffs * 16 + 1; - - if (x0 < 0) x0 = 0; - if (x1 > 16) x1 = 16; - - if (y0 < 1) y0 = 1; - if (y1 > 120) y1 = 120; - - if (z0 < 0) z0 = 0; - if (z1 > 16) z1 = 16; - - bool detectedWater = false; - for (int xx = x0; !detectedWater && xx < x1; xx++) { - for (int zz = z0; !detectedWater && zz < z1; zz++) { - for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { - int p = (xx * 16 + zz) * 128 + yy; - if (yy < 0 || yy >= Level::DEPTH) continue; - if (blocks[p] == Tile::water->id || blocks[p] == Tile::calmWater->id) { - detectedWater = true; - } - if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { - yy = y0; - } - } - } - } - if (detectedWater) continue; - - for (int xx = x0; xx < x1; xx++) { - float xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; - for (int zz = z0; zz < z1; zz++) { - float zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; - int p = (xx * 16 + zz) * 128 + y1; - bool hasGrass = false; - for (int yy = y1 - 1; yy >= y0; yy--) { - float yd = (yy + 0.5 - yCave) / yRad; - if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) { - int block = blocks[p]; - if (block == Tile::grass->id) hasGrass = true; - if (block == Tile::rock->id || block == Tile.dirt.id || block == Tile.grass.id) { - if (yy < 10) { - blocks[p] = (char) Tile.lava.id; - } else { - blocks[p] = (char) 0; - if (hasGrass && blocks[p - 1] == Tile.dirt.id) blocks[p - 1] = (char) Tile.grass.id; - } - } - } - p--; - } - } - } - if (singleStep) break; - } -} - -void DungeonFeature::addFeature( Level level, int x, int z, int xOffs, int zOffs, unsigned char* blocks ) -{ - int caves = random.nextInt(random.nextInt(random.nextInt(40) + 1) + 1); - if (random.nextInt(15) != 0) caves = 0; - - for (int cave = 0; cave < caves; cave++) { - float xCave = x * 16 + random.nextInt(16); - // float yCave = (random.nextInt(random.nextInt(120) + 8) + random.nextInt(128)) / 2; - float yCave = random.nextInt(random.nextInt(120) + 8); - //float yCave = random.nextInt(128); - float zCave = z * 16 + random.nextInt(16); - - int tunnels = 1; - if (random.nextInt(4) == 0) { - addRoom(xOffs, zOffs, blocks, xCave, yCave, zCave); - tunnels += random.nextInt(4); - } - - for (int i = 0; i < tunnels; i++) { - - float yRot = random.nextFloat() * Mth::PI * 2; - float xRot = ((random.nextFloat() - 0.5f) * 2) / 8; - float thickness = random.nextFloat() * 2 + random.nextFloat(); - - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0); - } - } -} - -#endif +#if 0 + +#include "DungeonFeature.hpp" + +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "util/Random.hpp" +#include "util/Mth.hpp" + +void DungeonFeature::addRoom( int xOffs, int zOffs, unsigned char* blocks, float xRoom, float yRoom, float zRoom ) +{ + addTunnel(xOffs, zOffs, blocks, xRoom, yRoom, zRoom, 1 + random.nextFloat() * 6, 0, 0, -1, -1, 0.5); +} + +void DungeonFeature::addTunnel( int xOffs, int zOffs, unsigned char* blocks, float xCave, float yCave, float zCave, float thickness, float yRot, float xRot, int step, int dist, float yScale ) +{ + float xMid = xOffs * 16 + 8; + float zMid = zOffs * 16 + 8; + + float yRota = 0; + float xRota = 0; + // int dist = CAVE_RADIUS * 16 - 16; + // if (step>0) dist = step*2; + Random random(this->random.nextLong()); + + if (dist <= 0) { + int max = radius * 16 - 16; + dist = max - random.nextInt(max / 4); + } + bool singleStep = false; + + if (step == -1) { + step = dist / 2; + singleStep = true; + } + + + int splitPoint = random.nextInt(dist / 2) + dist / 4; + bool steep = random.nextInt(6) == 0; + + for (; step < dist; step++) { + float rad = 1.5 + (sin(step * Mth::PI / dist) * thickness) * 1; + float yRad = rad * yScale; + + float xc = cos(xRot); + float xs = sin(xRot); + xCave += cos(yRot) * xc; + yCave += xs; + zCave += sin(yRot) * xc; + + if (steep) { + xRot *= 0.92f; + } else { + xRot *= 0.7f; + } + xRot += xRota * 0.1f; + yRot += yRota * 0.1f; + + xRota *= 0.90f; + yRota *= 0.75f; + xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2; + yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4; + + + if (!singleStep && step == splitPoint && thickness > 1) { + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - Mth::PI / 2, xRot / 3, step, dist, 1.0); + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + Mth::PI / 2, xRot / 3, step, dist, 1.0); + return; + } + if (!singleStep && random.nextInt(4) == 0) continue; + + { + float xd = xCave - xMid; + float zd = zCave - zMid; + float remaining = dist - step; + float rr = (thickness + 2) + 16; + if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { + return; + } + } + + if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; + + int x0 = floor(xCave - rad) - xOffs * 16 - 1; + int x1 = floor(xCave + rad) - xOffs * 16 + 1; + + int y0 = floor(yCave - yRad) - 1; + int y1 = floor(yCave + yRad) + 1; + + int z0 = floor(zCave - rad) - zOffs * 16 - 1; + int z1 = floor(zCave + rad) - zOffs * 16 + 1; + + if (x0 < 0) x0 = 0; + if (x1 > 16) x1 = 16; + + if (y0 < 1) y0 = 1; + if (y1 > 120) y1 = 120; + + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; + + bool detectedWater = false; + for (int xx = x0; !detectedWater && xx < x1; xx++) { + for (int zz = z0; !detectedWater && zz < z1; zz++) { + for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { + int p = (xx * 16 + zz) * 128 + yy; + if (yy < 0 || yy >= Level::DEPTH) continue; + if (blocks[p] == Tile::water->id || blocks[p] == Tile::calmWater->id) { + detectedWater = true; + } + if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { + yy = y0; + } + } + } + } + if (detectedWater) continue; + + for (int xx = x0; xx < x1; xx++) { + float xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; + for (int zz = z0; zz < z1; zz++) { + float zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; + int p = (xx * 16 + zz) * 128 + y1; + bool hasGrass = false; + for (int yy = y1 - 1; yy >= y0; yy--) { + float yd = (yy + 0.5 - yCave) / yRad; + if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) { + int block = blocks[p]; + if (block == Tile::grass->id) hasGrass = true; + if (block == Tile::rock->id || block == Tile.dirt.id || block == Tile.grass.id) { + if (yy < 10) { + blocks[p] = (char) Tile.lava.id; + } else { + blocks[p] = (char) 0; + if (hasGrass && blocks[p - 1] == Tile.dirt.id) blocks[p - 1] = (char) Tile.grass.id; + } + } + } + p--; + } + } + } + if (singleStep) break; + } +} + +void DungeonFeature::addFeature( Level level, int x, int z, int xOffs, int zOffs, unsigned char* blocks ) +{ + int caves = random.nextInt(random.nextInt(random.nextInt(40) + 1) + 1); + if (random.nextInt(15) != 0) caves = 0; + + for (int cave = 0; cave < caves; cave++) { + float xCave = x * 16 + random.nextInt(16); + // float yCave = (random.nextInt(random.nextInt(120) + 8) + random.nextInt(128)) / 2; + float yCave = random.nextInt(random.nextInt(120) + 8); + //float yCave = random.nextInt(128); + float zCave = z * 16 + random.nextInt(16); + + int tunnels = 1; + if (random.nextInt(4) == 0) { + addRoom(xOffs, zOffs, blocks, xCave, yCave, zCave); + tunnels += random.nextInt(4); + } + + for (int i = 0; i < tunnels; i++) { + + float yRot = random.nextFloat() * Mth::PI * 2; + float xRot = ((random.nextFloat() - 0.5f) * 2) / 8; + float thickness = random.nextFloat() * 2 + random.nextFloat(); + + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0); + } + } +} + +#endif diff --git a/src/world/level/levelgen/DungeonFeature.h b/src/world/level/levelgen/DungeonFeature.hpp similarity index 95% rename from src/world/level/levelgen/DungeonFeature.h rename to src/world/level/levelgen/DungeonFeature.hpp index 446f7e5..1eff076 100755 --- a/src/world/level/levelgen/DungeonFeature.h +++ b/src/world/level/levelgen/DungeonFeature.hpp @@ -4,7 +4,7 @@ //package net.minecraft.world.level.levelgen; -#include "LargeFeature.h" +#include "LargeFeature.hpp" class DungeonFeature: public LargeFeature { diff --git a/src/world/level/levelgen/LargeCaveFeature.h b/src/world/level/levelgen/LargeCaveFeature.hpp similarity index 97% rename from src/world/level/levelgen/LargeCaveFeature.h rename to src/world/level/levelgen/LargeCaveFeature.hpp index 7b8db79..4399e29 100755 --- a/src/world/level/levelgen/LargeCaveFeature.h +++ b/src/world/level/levelgen/LargeCaveFeature.hpp @@ -2,14 +2,14 @@ //package net.minecraft.world.level.levelgen; -#include "../../../util/Random.h" -#include "../../../util/Mth.h" +#include "util/Random.hpp" +#include "util/Mth.hpp" -#include "LargeFeature.h" +#include "LargeFeature.hpp" -#include "../Level.h" -#include "../tile/Tile.h" -#include "../tile/GrassTile.h" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/GrassTile.hpp" class LargeCaveFeature: public LargeFeature { diff --git a/src/world/level/levelgen/LargeFeature.cpp b/src/world/level/levelgen/LargeFeature.cpp index 9b3befa..2f61356 100755 --- a/src/world/level/levelgen/LargeFeature.cpp +++ b/src/world/level/levelgen/LargeFeature.cpp @@ -1,27 +1,27 @@ -#include "LargeFeature.h" -#include "../Level.h" - -LargeFeature::LargeFeature() : radius(8) -{ -} - -LargeFeature::~LargeFeature() -{ -} - -void LargeFeature::apply( ChunkSource* chunkSource, Level* level, int xOffs, int zOffs, unsigned char* blocks, int blocksSize ) -{ - int r = radius; - - random.setSeed(level->getSeed()); - long xScale = random.nextLong() / 2 * 2 + 1; - long zScale = random.nextLong() / 2 * 2 + 1; - - for (int x = xOffs - r; x <= xOffs + r; x++) { - for (int z = zOffs - r; z <= zOffs + r; z++) { - random.setSeed((x * xScale + z * zScale) ^ level->getSeed()); - addFeature(level, x, z, xOffs, zOffs, blocks, blocksSize); - } - } -} - +#include "LargeFeature.hpp" +#include "world/level/Level.hpp" + +LargeFeature::LargeFeature() : radius(8) +{ +} + +LargeFeature::~LargeFeature() +{ +} + +void LargeFeature::apply( ChunkSource* chunkSource, Level* level, int xOffs, int zOffs, unsigned char* blocks, int blocksSize ) +{ + int r = radius; + + random.setSeed(level->getSeed()); + long xScale = random.nextLong() / 2 * 2 + 1; + long zScale = random.nextLong() / 2 * 2 + 1; + + for (int x = xOffs - r; x <= xOffs + r; x++) { + for (int z = zOffs - r; z <= zOffs + r; z++) { + random.setSeed((x * xScale + z * zScale) ^ level->getSeed()); + addFeature(level, x, z, xOffs, zOffs, blocks, blocksSize); + } + } +} + diff --git a/src/world/level/levelgen/LargeFeature.h b/src/world/level/levelgen/LargeFeature.hpp similarity index 93% rename from src/world/level/levelgen/LargeFeature.h rename to src/world/level/levelgen/LargeFeature.hpp index 9c3a8ce..119b25d 100755 --- a/src/world/level/levelgen/LargeFeature.h +++ b/src/world/level/levelgen/LargeFeature.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.levelgen; -#include "../../../util/Random.h" +#include "util/Random.hpp" class Random; class Level; diff --git a/src/world/level/levelgen/RandomLevelSource.cpp b/src/world/level/levelgen/RandomLevelSource.cpp index 7ef40e3..9338970 100755 --- a/src/world/level/levelgen/RandomLevelSource.cpp +++ b/src/world/level/levelgen/RandomLevelSource.cpp @@ -1,729 +1,729 @@ -#include "RandomLevelSource.h" - -#include "feature/FeatureInclude.h" -#include "../Level.h" -#include "../ChunkPos.h" -#include "../MobSpawner.h" -#include "../biome/Biome.h" -#include "../biome/BiomeSource.h" -#include "../chunk/LevelChunk.h" -#include "../material/Material.h" -#include "../tile/Tile.h" -#include "../tile/HeavyTile.h" -#include "../../../util/Random.h" - -const float RandomLevelSource::SNOW_CUTOFF = 0.5f; -const float RandomLevelSource::SNOW_SCALE = 0.3f; -static const int MAX_BUFFER_SIZE = 1024; - -RandomLevelSource::RandomLevelSource(Level* level, long seed, int version, bool spawnMobs) -: random(seed), - level(level), - lperlinNoise1(&random, 16), - lperlinNoise2(&random, 16), - perlinNoise1(&random, 8), - perlinNoise2(&random, 4), - perlinNoise3(&random, 4), - scaleNoise(&random, 10), - depthNoise(&random, 16), - forestNoise(&random, 8), - spawnMobs(spawnMobs), - pnr(NULL), ar(NULL), br(NULL), sr(NULL), dr(NULL), fi(NULL), fis(NULL) - //biomes(NULL) -{ - for (int i=0; i<32; ++i) - for (int j=0; j<32; ++j) - waterDepths[i][j] = 0; - - buffer = new float[MAX_BUFFER_SIZE]; - - Random randomCopy = random; - printf("random.get : %d\n", randomCopy.nextInt()); -} - -RandomLevelSource::~RandomLevelSource() { - - // chunks are deleted in the chunk cache instead - //ChunkMap::iterator it = chunkMap.begin(); - //while (it != chunkMap.end()) { - // it->second->deleteBlockData(); //@attn: we delete the block data here, for now - // delete it->second; - // ++it; - //} - - delete[] buffer; - delete[] pnr; - delete[] ar; - delete[] br; - delete[] sr; - delete[] dr; - delete[] fi; - delete[] fis; -} - -/*public*/ -void RandomLevelSource::prepareHeights(int xOffs, int zOffs, unsigned char* blocks, /*Biome*/void* biomes, float* temperatures) { - - int xChunks = 16 / CHUNK_WIDTH; - int waterHeight = Level::DEPTH - 64; - - int xSize = xChunks + 1; - int ySize = 128 / CHUNK_HEIGHT + 1; - int zSize = xChunks + 1; - buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize); - - for (int xc = 0; xc < xChunks; xc++) { - for (int zc = 0; zc < xChunks; zc++) { - for (int yc = 0; yc < 128 / CHUNK_HEIGHT; yc++) { - float yStep = 1 / (float) CHUNK_HEIGHT; - float s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; - float s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; - float s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; - float s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; - - float s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; - float s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; - float s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; - float s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; - - for (int y = 0; y < CHUNK_HEIGHT; y++) { - float xStep = 1 / (float) CHUNK_WIDTH; - - float _s0 = s0; - float _s1 = s1; - float _s0a = (s2 - s0) * xStep; - float _s1a = (s3 - s1) * xStep; - - for (int x = 0; x < CHUNK_WIDTH; x++) { - int offs = (x + xc * CHUNK_WIDTH) << 11 | (0 + zc * CHUNK_WIDTH) << 7 | (yc * CHUNK_HEIGHT + y); - int step = 1 << 7; - float zStep = 1 / (float) CHUNK_WIDTH; - - float val = _s0; - float vala = (_s1 - _s0) * zStep; - for (int z = 0; z < CHUNK_WIDTH; z++) { -// + (zc * CHUNK_WIDTH + z)]; - float temp = temperatures[(xc * CHUNK_WIDTH + x) * 16 + (zc * CHUNK_WIDTH + z)]; - int tileId = 0; - if (yc * CHUNK_HEIGHT + y < waterHeight) { - if (temp < SNOW_CUTOFF && yc * CHUNK_HEIGHT + y >= waterHeight - 1) { - tileId = Tile::ice->id; - } else { - tileId = Tile::calmWater->id; - } - } - if (val > 0) { - tileId = Tile::rock->id; - } else { - } - - blocks[offs] = (unsigned char) tileId; - offs += step; - val += vala; - } - _s0 += _s0a; - _s1 += _s1a; - } - - s0 += s0a; - s1 += s1a; - s2 += s2a; - s3 += s3a; - } - } - } - } -} - -void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, unsigned char* blocks, Biome** biomes) { - int waterHeight = Level::DEPTH - 64; - - float s = 1 / 32.0f; - perlinNoise2.getRegion(sandBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s, s, 1); - perlinNoise2.getRegion(gravelBuffer, (float)(xOffs * 16), 109.01340f, (float)(zOffs * 16), 16, 1, 16, s, 1, s); - perlinNoise3.getRegion(depthBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s * 2, s * 2, s * 2); - - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - float temp = 1; // @todo: read temp from BiomeSource - Biome* b = biomes[x + z * 16]; - bool sand = (sandBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 0; - bool gravel = (gravelBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 3; - int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random.nextFloat() * 0.25f); - - int run = -1; - - char top = b->topMaterial; - char material = b->material; - - for (int y = 127; y >= 0; y--) { - int offs = (z * 16 + x) * 128 + y; - - if (y <= 0 + random.nextInt(5)) { - blocks[offs] = (char) Tile::unbreakable->id; - } else { - int old = blocks[offs]; - - if (old == 0) { - run = -1; - } else if (old == Tile::rock->id) { - if (run == -1) { - if (runDepth <= 0) { - top = 0; - material = (char) Tile::rock->id; - } else if (y >= waterHeight - 4 && y <= waterHeight + 1) { - top = b->topMaterial; - material = b->material; - - //@attn: ? - if (gravel) { - top = 0; - material = (char) Tile::gravel->id; - } - if (sand) { - top = (char) Tile::sand->id; - material = (char) Tile::sand->id; - } - } - - if (y < waterHeight && top == 0) { - if (temp < 0.15f) - top = (char) Tile::ice->id; - else - top = (char) Tile::calmWater->id; - } - - run = runDepth; - if (y >= waterHeight - 1) blocks[offs] = top; - else blocks[offs] = material; - } else if (run > 0) { - run--; - blocks[offs] = material; - - // place a few sandstone blocks beneath sand - // runs - if (run == 0 && material == Tile::sand->id) { - run = random.nextInt(4); - material = (char) Tile::sandStone->id; - } - } - } - } - } - } - } -} - - -/*public*/ -void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { - - level->isGeneratingTerrain = true; - - HeavyTile::instaFall = true; - int xo = xt * 16; - int zo = zt * 16; - - Biome* biome = level->getBiomeSource()->getBiome(xo + 16, zo + 16); - // Biome* biome = Biome::forest; - - random.setSeed(level->getSeed()); - int xScale = random.nextInt() / 2 * 2 + 1; - int zScale = random.nextInt() / 2 * 2 + 1; - random.setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); - - // //@todo: hide those chunks if they are aren't visible -// if (random.nextInt(4) == 0) { -// int x = xo + random.nextInt(16) + 8; -// int y = random.nextInt(128); -// int z = zo + random.nextInt(16) + 8; -// LakeFeature feature(Tile::calmWater->id); -// feature.place(level, &random, x, y, z); -// LOGI("Adding underground lake @ (%d,%d,%d)\n", x, y, z); -// } - - ////@todo: hide those chunks if they are aren't visible - // if (random.nextInt(8) == 0) { - // int x = xo + random.nextInt(16) + 8; - // int y = random.nextInt(random.nextInt(120) + 8); - // int z = zo + random.nextInt(16) + 8; - // if (y < 64 || random.nextInt(10) == 0) { - // LakeFeature feature(Tile::calmLava->id); - // feature.place(level, &random, x, y, z); - // } - // } - - static float totalTime = 0; - const float st = getTimeS(); - - //for (int i = 0; i < 8; i++) { - // int x = xo + random.nextInt(16) + 8; - // int y = random.nextInt(128); - // int z = zo + random.nextInt(16) + 8; - // MonsterRoomFeature().place(level, random, x, y, z); - //} - - for (int i = 0; i < 10; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(128); - int z = zo + random.nextInt(16); - ClayFeature feature(32); - feature.place(level, &random, x, y, z); - } - - for (int i = 0; i < 20; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(128); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::dirt->id, 32); - feature.place(level, &random, x, y, z); - } - - for (int i = 0; i < 10; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(128); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::gravel->id, 32); - feature.place(level, &random, x, y, z); - } - - // Coal: common, wide Y range, moderate vein size - for (int i = 0; i < 16; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(128); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::coalOre->id, 14); - feature.place(level, &random, x, y, z); - } - - // Iron: common, limited to upper underground - for (int i = 0; i < 14; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(64); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::ironOre->id, 10); - feature.place(level, &random, x, y, z); - } - - // Gold: rarer and deeper - for (int i = 0; i < 2; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(32); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::goldOre->id, 9); - feature.place(level, &random, x, y, z); - } - - // Redstone: somewhat common at low depths - for (int i = 0; i < 6; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(16); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::redStoneOre->id, 8); - feature.place(level, &random, x, y, z); - } - - // Emerald (diamond-equivalent): still rare but slightly more than vanilla - for (int i = 0; i < 3; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(16); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::emeraldOre->id, 6); - feature.place(level, &random, x, y, z); - } - - // Lapis: rare and not in very high Y - for (int i = 0; i < 1; i++) { - int x = xo + random.nextInt(16); - int y = random.nextInt(16) + random.nextInt(16); - int z = zo + random.nextInt(16); - OreFeature feature(Tile::lapisOre->id, 6); - feature.place(level, &random, x, y, z); - } - - const float ss = 0.5f; - int oFor = (int) ((forestNoise.getValue(xo * ss, zo * ss) / 8 + random.nextFloat() * 4 + 4) / 3); - int forests = 0;//1; (java: 0) - if (random.nextInt(10) == 0) forests += 1; - - if (biome == Biome::forest) forests += oFor + 2; // + 5 - if (biome == Biome::rainForest) forests += oFor + 2; //+ 5 - if (biome == Biome::seasonalForest) forests += oFor + 1; // 2 - if (biome == Biome::taiga) { - forests += oFor + 1; // + 5 - //LOGI("Biome is taiga!\n"); - } - - if (biome == Biome::desert) forests -= 20; - if (biome == Biome::tundra) forests -= 20; - if (biome == Biome::plains) forests -= 20; - - for (int i = 0; i < forests; i++) { - int x = xo + random.nextInt(16) + 8; - int z = zo + random.nextInt(16) + 8; - int y = level->getHeightmap(x, z); - Feature* tree = biome->getTreeFeature(&random); - if (tree) { - tree->init(1, 1, 1); - tree->place(level, &random, x, y, z); - delete tree; - } - //printf("placing tree at %d, %d, %d\n", x, y, z); - } - - for (int i = 0; i < 2; i++) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(128); - int z = zo + random.nextInt(16) + 8; - FlowerFeature feature(Tile::flower->id); - feature.place(level, &random, x, y, z); - } - - if (random.nextInt(2) == 0) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(128); - int z = zo + random.nextInt(16) + 8; - FlowerFeature feature(Tile::rose->id); - feature.place(level, &random, x, y, z); - } - - if (random.nextInt(4) == 0) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(128); - int z = zo + random.nextInt(16) + 8; - FlowerFeature feature(Tile::mushroom1->id); - feature.place(level, &random, x, y, z); - } - - if (random.nextInt(8) == 0) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(128); - int z = zo + random.nextInt(16) + 8; - FlowerFeature feature(Tile::mushroom2->id); - feature.place(level, &random, x, y, z); - } - /*int grassCount = 1; - for (int i = 0; i < grassCount; i++) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(Level::genDepth); - int z = zo + random.nextInt(16) + 8; - Feature* grassFeature = biome->getGrassFeature(&random); - if (grassFeature) { - grassFeature->place(level, &random, x, y, z); - delete grassFeature; - } - }*/ - for (int i = 0; i < 10; i++) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(128); - int z = zo + random.nextInt(16) + 8; - ReedsFeature feature; - feature.place(level, &random, x, y, z); - } - - - //if (random.nextInt(32) == 0) { - // int x = xo + random.nextInt(16) + 8; - // int y = random.nextInt(128); - // int z = zo + random.nextInt(16) + 8; - // PumpkinFeature().place(level, random, x, y, z); - //} - - int cacti = 0; - if (biome == Biome::desert) cacti += 5; - - for (int i = 0; i < cacti; i++) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(128); - int z = zo + random.nextInt(16) + 8; - CactusFeature feature; - //LOGI("Tried creating a cactus at %d, %d, %d\n", x, y, z); - feature.place(level, &random, x, y, z); - } - - for (int i = 0; i < 50; i++) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(random.nextInt(120) + 8); - int z = zo + random.nextInt(16) + 8; - SpringFeature feature(Tile::water->id); - feature.place(level, &random, x, y, z); - } - - for (int i = 0; i < 20; i++) { - int x = xo + random.nextInt(16) + 8; - int y = random.nextInt(random.nextInt(random.nextInt(112) + 8) + 8); - int z = zo + random.nextInt(16) + 8; - SpringFeature feature(Tile::lava->id); - feature.place(level, &random, x, y, z); - } - - if (spawnMobs && !level->isClientSide) - MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, &random); - - //LOGI("Reading temp: 1\n"); - float* temperatures = level->getBiomeSource()->getTemperatureBlock(/*NULL,*/ xo + 8, zo + 8, 16, 16); - for (int x = xo + 8; x < xo + 8 + 16; x++) - for (int z = zo + 8; z < zo + 8 + 16; z++) { - int xp = x - (xo + 8); - int zp = z - (zo + 8); - int y = level->getTopSolidBlock(x, z); - float temp = temperatures[xp * 16 + zp] - (y - 64) / 64.0f * SNOW_SCALE; - if (temp < SNOW_CUTOFF) { - if (y > 0 && y < 128 && level->isEmptyTile(x, y, z) && level->getMaterial(x, y - 1, z)->blocksMotion()) { - if (level->getMaterial(x, y - 1, z) != Material::ice) level->setTile(x, y, z, Tile::topSnow->id); - } - } - } - //LOGI("Reading temp: 0 END\n"); - - const float et = getTimeS(); - totalTime += (et-st); - - //printf("Time to place features: %f. Total %f\n", et - st, totalTime); - - HeavyTile::instaFall = false; - - level->isGeneratingTerrain = false; -} - -LevelChunk* RandomLevelSource::create(int x, int z) { - return getChunk(x, z); -} - -LevelChunk* RandomLevelSource::getChunk(int xOffs, int zOffs) { - //static int chunkx = 0; - int hashedPos = ChunkPos::hashCode(xOffs, zOffs); - - ChunkMap::iterator it = chunkMap.find(hashedPos); - if (it != chunkMap.end()) - return it->second; - - random.setSeed((long)(xOffs * 341872712l + zOffs * 132899541l)); //@fix - - unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount]; - LevelChunk* levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); - chunkMap.insert(std::make_pair(hashedPos, levelChunk)); - - Biome** biomes = level->getBiomeSource()->getBiomeBlock(/*biomes, */xOffs * 16, zOffs * 16, 16, 16); - float* temperatures = level->getBiomeSource()->temperatures; - prepareHeights(xOffs, zOffs, blocks, 0, temperatures);//biomes, temperatures); - buildSurfaces(xOffs, zOffs, blocks, biomes); - - // Carve caves into the chunk - caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount); - levelChunk->recalcHeightmap(); - - return levelChunk; -} - -/*private*/ -float* RandomLevelSource::getHeights(float* buffer, int x, int y, int z, int xSize, int ySize, int zSize) { - const int size = xSize * ySize * zSize; - if (size > MAX_BUFFER_SIZE) { - LOGI("RandomLevelSource::getHeights: TOO LARGE BUFFER REQUESTED: %d (max %d)\n", size, MAX_BUFFER_SIZE); - } - - float s = 1 * 684.412f; - float hs = 1 * 684.412f; - - float* temperatures = level->getBiomeSource()->temperatures; - float* downfalls = level->getBiomeSource()->downfalls; - sr = scaleNoise.getRegion(sr, x, z, xSize, zSize, 1.121f, 1.121f, 0.5f); - dr = depthNoise.getRegion(dr, x, z, xSize, zSize, 200.0f, 200.0f, 0.5f); - - pnr = perlinNoise1.getRegion(pnr, (float)x, (float)y, (float)z, xSize, ySize, zSize, s / 80.0f, hs / 160.0f, s / 80.0f); - ar = lperlinNoise1.getRegion(ar, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s); - br = lperlinNoise2.getRegion(br, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s); - - int p = 0; - int pp = 0; - - int wScale = 16 / xSize; - for (int xx = 0; xx < xSize; xx++) { - int xp = xx * wScale + wScale / 2; - - for (int zz = 0; zz < zSize; zz++) { - int zp = zz * wScale + wScale / 2; - float temperature = temperatures[xp * 16 + zp]; - float downfall = downfalls[xp * 16 + zp] * temperature; - float dd = 1 - downfall; - dd = dd * dd; - dd = dd * dd; - dd = 1 - dd; - - float scale = ((sr[pp] + 256.0f) / 512); - scale *= dd; - if (scale > 1) scale = 1; - - - float depth = (dr[pp] / 8000.0f); - if (depth < 0) depth = -depth * 0.3f; - depth = depth * 3.0f - 2.0f; - - if (depth < 0) { - depth = depth / 2; - if (depth < -1) depth = -1; - depth = depth / 1.4f; - depth /= 2; - scale = 0; - } else { - if (depth > 1) depth = 1; - depth = depth / 8; - } - - if (scale < 0) scale = 0; - scale = (scale) + 0.5f; - depth = depth * ySize / 16; - - float yCenter = ySize / 2.0f + depth * 4; - - pp++; - - for (int yy = 0; yy < ySize; yy++) { - float val = 0; - - float yOffs = (yy - (yCenter)) * 12 / scale; - if (yOffs < 0) yOffs *= 4; - - float bb = ar[p] / 512; - float cc = br[p] / 512; - - float v = (pnr[p] / 10 + 1) / 2; - if (v < 0) val = bb; - else if (v > 1) val = cc; - else val = bb + (cc - bb) * v; - val -= yOffs; - - if (yy > ySize - 4) { - float slide = (yy - (ySize - 4)) / (4 - 1.0f); - val = val * (1 - slide) + -10 * slide; - } - - buffer[p] = val; - p++; - } - } - } - return buffer; -} - -/*private*/ -void RandomLevelSource::calcWaterDepths(ChunkSource* parent, int xt, int zt) { - int xo = xt * 16; - int zo = zt * 16; - for (int x = 0; x < 16; x++) { - int y = level->getSeaLevel(); - for (int z = 0; z < 16; z++) { - int xp = xo + x + 7; - int zp = zo + z + 7; - int h = level->getHeightmap(xp, zp); - if (h <= 0) { - if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) { - bool hadWater = false; - if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater->id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater->id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater->id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater->id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; - if (hadWater) { - for (int x2 = -5; x2 <= 5; x2++) { - for (int z2 = -5; z2 <= 5; z2++) { - int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); - - if (d <= 5) { - d = 6 - d; - if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater->id) { - int od = level->getData(xp + x2, y, zp + z2); - if (od < 7 && od < d) { - level->setData(xp + x2, y, zp + z2, d); - } - } - } - } - } - if (hadWater) { - level->setTileAndDataNoUpdate(xp, y, zp, Tile::calmWater->id, 7); - for (int y2 = 0; y2 < y; y2++) { - level->setTileAndDataNoUpdate(xp, y2, zp, Tile::calmWater->id, 8); - } - } - } - } - } - } - } -} - -bool RandomLevelSource::hasChunk(int x, int y) { - //return x >= 0 && x < 16 && y >= 0 && y < 16; - return true; -} - -bool RandomLevelSource::tick() { - return false; -} - -bool RandomLevelSource::shouldSave() { - return true; -} - -std::string RandomLevelSource::gatherStats() { - return "RandomLevelSource"; -} - -//bool RandomLevelSource::save(bool force, ProgressListener progressListener) { -// return true; -//} - -Biome::MobList RandomLevelSource::getMobsAt(const MobCategory& mobCategory, int x, int y, int z) { - BiomeSource* biomeSource = level->getBiomeSource(); - if (biomeSource == NULL) { - return Biome::MobList(); - } -// static Stopwatch sw; sw.start(); - Biome* biome = biomeSource->getBiome(x, z); -// sw.stop(); -// sw.printEvery(10, "getBiome::"); - if (biome == NULL) { - return Biome::MobList(); - } - return biome->getMobs(mobCategory); -} - - -LevelChunk* PerformanceTestChunkSource::create(int x, int z) -{ - unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount]; - memset(blocks, 0, LevelChunk::ChunkBlockCount); - - for (int y = 0; y < 65; y++) - { - if (y < 60) - { - for (int x = (y + 1) & 1; x < 16; x += 2) - { - for (int z = y & 1; z < 16; z += 2) - { - blocks[x << 11 | z << 7 | y] = 3; - } - } - } - else - { - for (int x = 0; x < 16; x += 2) - { - for (int z = 0; z < 16; z += 2) - { - blocks[x << 11 | z << 7 | y] = 3; - } - } - - } - } - - LevelChunk* levelChunk = new LevelChunk(level, blocks, x, z); - - //caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount); - levelChunk->recalcHeightmap(); - - return levelChunk; -} +#include "RandomLevelSource.hpp" + +#include "feature/FeatureInclude.hpp" +#include "world/level/Level.hpp" +#include "world/level/ChunkPos.hpp" +#include "world/level/MobSpawner.hpp" +#include "world/level/biome/Biome.hpp" +#include "world/level/biome/BiomeSource.hpp" +#include "world/level/chunk/LevelChunk.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/HeavyTile.hpp" +#include "util/Random.hpp" + +const float RandomLevelSource::SNOW_CUTOFF = 0.5f; +const float RandomLevelSource::SNOW_SCALE = 0.3f; +static const int MAX_BUFFER_SIZE = 1024; + +RandomLevelSource::RandomLevelSource(Level* level, long seed, int version, bool spawnMobs) +: random(seed), + level(level), + lperlinNoise1(&random, 16), + lperlinNoise2(&random, 16), + perlinNoise1(&random, 8), + perlinNoise2(&random, 4), + perlinNoise3(&random, 4), + scaleNoise(&random, 10), + depthNoise(&random, 16), + forestNoise(&random, 8), + spawnMobs(spawnMobs), + pnr(NULL), ar(NULL), br(NULL), sr(NULL), dr(NULL), fi(NULL), fis(NULL) + //biomes(NULL) +{ + for (int i=0; i<32; ++i) + for (int j=0; j<32; ++j) + waterDepths[i][j] = 0; + + buffer = new float[MAX_BUFFER_SIZE]; + + Random randomCopy = random; + printf("random.get : %d\n", randomCopy.nextInt()); +} + +RandomLevelSource::~RandomLevelSource() { + + // chunks are deleted in the chunk cache instead + //ChunkMap::iterator it = chunkMap.begin(); + //while (it != chunkMap.end()) { + // it->second->deleteBlockData(); //@attn: we delete the block data here, for now + // delete it->second; + // ++it; + //} + + delete[] buffer; + delete[] pnr; + delete[] ar; + delete[] br; + delete[] sr; + delete[] dr; + delete[] fi; + delete[] fis; +} + +/*public*/ +void RandomLevelSource::prepareHeights(int xOffs, int zOffs, unsigned char* blocks, /*Biome*/void* biomes, float* temperatures) { + + int xChunks = 16 / CHUNK_WIDTH; + int waterHeight = Level::DEPTH - 64; + + int xSize = xChunks + 1; + int ySize = 128 / CHUNK_HEIGHT + 1; + int zSize = xChunks + 1; + buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize); + + for (int xc = 0; xc < xChunks; xc++) { + for (int zc = 0; zc < xChunks; zc++) { + for (int yc = 0; yc < 128 / CHUNK_HEIGHT; yc++) { + float yStep = 1 / (float) CHUNK_HEIGHT; + float s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; + float s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; + float s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; + float s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; + + float s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; + float s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; + float s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; + float s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; + + for (int y = 0; y < CHUNK_HEIGHT; y++) { + float xStep = 1 / (float) CHUNK_WIDTH; + + float _s0 = s0; + float _s1 = s1; + float _s0a = (s2 - s0) * xStep; + float _s1a = (s3 - s1) * xStep; + + for (int x = 0; x < CHUNK_WIDTH; x++) { + int offs = (x + xc * CHUNK_WIDTH) << 11 | (0 + zc * CHUNK_WIDTH) << 7 | (yc * CHUNK_HEIGHT + y); + int step = 1 << 7; + float zStep = 1 / (float) CHUNK_WIDTH; + + float val = _s0; + float vala = (_s1 - _s0) * zStep; + for (int z = 0; z < CHUNK_WIDTH; z++) { +// + (zc * CHUNK_WIDTH + z)]; + float temp = temperatures[(xc * CHUNK_WIDTH + x) * 16 + (zc * CHUNK_WIDTH + z)]; + int tileId = 0; + if (yc * CHUNK_HEIGHT + y < waterHeight) { + if (temp < SNOW_CUTOFF && yc * CHUNK_HEIGHT + y >= waterHeight - 1) { + tileId = Tile::ice->id; + } else { + tileId = Tile::calmWater->id; + } + } + if (val > 0) { + tileId = Tile::rock->id; + } else { + } + + blocks[offs] = (unsigned char) tileId; + offs += step; + val += vala; + } + _s0 += _s0a; + _s1 += _s1a; + } + + s0 += s0a; + s1 += s1a; + s2 += s2a; + s3 += s3a; + } + } + } + } +} + +void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, unsigned char* blocks, Biome** biomes) { + int waterHeight = Level::DEPTH - 64; + + float s = 1 / 32.0f; + perlinNoise2.getRegion(sandBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s, s, 1); + perlinNoise2.getRegion(gravelBuffer, (float)(xOffs * 16), 109.01340f, (float)(zOffs * 16), 16, 1, 16, s, 1, s); + perlinNoise3.getRegion(depthBuffer, (float)(xOffs * 16), (float)(zOffs * 16), 0, 16, 16, 1, s * 2, s * 2, s * 2); + + for (int x = 0; x < 16; x++) { + for (int z = 0; z < 16; z++) { + float temp = 1; // @todo: read temp from BiomeSource + Biome* b = biomes[x + z * 16]; + bool sand = (sandBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 0; + bool gravel = (gravelBuffer[x + z * 16] + random.nextFloat() * 0.2f) > 3; + int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random.nextFloat() * 0.25f); + + int run = -1; + + char top = b->topMaterial; + char material = b->material; + + for (int y = 127; y >= 0; y--) { + int offs = (z * 16 + x) * 128 + y; + + if (y <= 0 + random.nextInt(5)) { + blocks[offs] = (char) Tile::unbreakable->id; + } else { + int old = blocks[offs]; + + if (old == 0) { + run = -1; + } else if (old == Tile::rock->id) { + if (run == -1) { + if (runDepth <= 0) { + top = 0; + material = (char) Tile::rock->id; + } else if (y >= waterHeight - 4 && y <= waterHeight + 1) { + top = b->topMaterial; + material = b->material; + + //@attn: ? + if (gravel) { + top = 0; + material = (char) Tile::gravel->id; + } + if (sand) { + top = (char) Tile::sand->id; + material = (char) Tile::sand->id; + } + } + + if (y < waterHeight && top == 0) { + if (temp < 0.15f) + top = (char) Tile::ice->id; + else + top = (char) Tile::calmWater->id; + } + + run = runDepth; + if (y >= waterHeight - 1) blocks[offs] = top; + else blocks[offs] = material; + } else if (run > 0) { + run--; + blocks[offs] = material; + + // place a few sandstone blocks beneath sand + // runs + if (run == 0 && material == Tile::sand->id) { + run = random.nextInt(4); + material = (char) Tile::sandStone->id; + } + } + } + } + } + } + } +} + + +/*public*/ +void RandomLevelSource::postProcess(ChunkSource* parent, int xt, int zt) { + + level->isGeneratingTerrain = true; + + HeavyTile::instaFall = true; + int xo = xt * 16; + int zo = zt * 16; + + Biome* biome = level->getBiomeSource()->getBiome(xo + 16, zo + 16); + // Biome* biome = Biome::forest; + + random.setSeed(level->getSeed()); + int xScale = random.nextInt() / 2 * 2 + 1; + int zScale = random.nextInt() / 2 * 2 + 1; + random.setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); + + // //@todo: hide those chunks if they are aren't visible +// if (random.nextInt(4) == 0) { +// int x = xo + random.nextInt(16) + 8; +// int y = random.nextInt(128); +// int z = zo + random.nextInt(16) + 8; +// LakeFeature feature(Tile::calmWater->id); +// feature.place(level, &random, x, y, z); +// LOGI("Adding underground lake @ (%d,%d,%d)\n", x, y, z); +// } + + ////@todo: hide those chunks if they are aren't visible + // if (random.nextInt(8) == 0) { + // int x = xo + random.nextInt(16) + 8; + // int y = random.nextInt(random.nextInt(120) + 8); + // int z = zo + random.nextInt(16) + 8; + // if (y < 64 || random.nextInt(10) == 0) { + // LakeFeature feature(Tile::calmLava->id); + // feature.place(level, &random, x, y, z); + // } + // } + + static float totalTime = 0; + const float st = getTimeS(); + + //for (int i = 0; i < 8; i++) { + // int x = xo + random.nextInt(16) + 8; + // int y = random.nextInt(128); + // int z = zo + random.nextInt(16) + 8; + // MonsterRoomFeature().place(level, random, x, y, z); + //} + + for (int i = 0; i < 10; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(128); + int z = zo + random.nextInt(16); + ClayFeature feature(32); + feature.place(level, &random, x, y, z); + } + + for (int i = 0; i < 20; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(128); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::dirt->id, 32); + feature.place(level, &random, x, y, z); + } + + for (int i = 0; i < 10; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(128); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::gravel->id, 32); + feature.place(level, &random, x, y, z); + } + + // Coal: common, wide Y range, moderate vein size + for (int i = 0; i < 16; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(128); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::coalOre->id, 14); + feature.place(level, &random, x, y, z); + } + + // Iron: common, limited to upper underground + for (int i = 0; i < 14; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(64); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::ironOre->id, 10); + feature.place(level, &random, x, y, z); + } + + // Gold: rarer and deeper + for (int i = 0; i < 2; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(32); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::goldOre->id, 9); + feature.place(level, &random, x, y, z); + } + + // Redstone: somewhat common at low depths + for (int i = 0; i < 6; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(16); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::redStoneOre->id, 8); + feature.place(level, &random, x, y, z); + } + + // Emerald (diamond-equivalent): still rare but slightly more than vanilla + for (int i = 0; i < 3; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(16); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::emeraldOre->id, 6); + feature.place(level, &random, x, y, z); + } + + // Lapis: rare and not in very high Y + for (int i = 0; i < 1; i++) { + int x = xo + random.nextInt(16); + int y = random.nextInt(16) + random.nextInt(16); + int z = zo + random.nextInt(16); + OreFeature feature(Tile::lapisOre->id, 6); + feature.place(level, &random, x, y, z); + } + + const float ss = 0.5f; + int oFor = (int) ((forestNoise.getValue(xo * ss, zo * ss) / 8 + random.nextFloat() * 4 + 4) / 3); + int forests = 0;//1; (java: 0) + if (random.nextInt(10) == 0) forests += 1; + + if (biome == Biome::forest) forests += oFor + 2; // + 5 + if (biome == Biome::rainForest) forests += oFor + 2; //+ 5 + if (biome == Biome::seasonalForest) forests += oFor + 1; // 2 + if (biome == Biome::taiga) { + forests += oFor + 1; // + 5 + //LOGI("Biome is taiga!\n"); + } + + if (biome == Biome::desert) forests -= 20; + if (biome == Biome::tundra) forests -= 20; + if (biome == Biome::plains) forests -= 20; + + for (int i = 0; i < forests; i++) { + int x = xo + random.nextInt(16) + 8; + int z = zo + random.nextInt(16) + 8; + int y = level->getHeightmap(x, z); + Feature* tree = biome->getTreeFeature(&random); + if (tree) { + tree->init(1, 1, 1); + tree->place(level, &random, x, y, z); + delete tree; + } + //printf("placing tree at %d, %d, %d\n", x, y, z); + } + + for (int i = 0; i < 2; i++) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(128); + int z = zo + random.nextInt(16) + 8; + FlowerFeature feature(Tile::flower->id); + feature.place(level, &random, x, y, z); + } + + if (random.nextInt(2) == 0) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(128); + int z = zo + random.nextInt(16) + 8; + FlowerFeature feature(Tile::rose->id); + feature.place(level, &random, x, y, z); + } + + if (random.nextInt(4) == 0) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(128); + int z = zo + random.nextInt(16) + 8; + FlowerFeature feature(Tile::mushroom1->id); + feature.place(level, &random, x, y, z); + } + + if (random.nextInt(8) == 0) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(128); + int z = zo + random.nextInt(16) + 8; + FlowerFeature feature(Tile::mushroom2->id); + feature.place(level, &random, x, y, z); + } + /*int grassCount = 1; + for (int i = 0; i < grassCount; i++) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(Level::genDepth); + int z = zo + random.nextInt(16) + 8; + Feature* grassFeature = biome->getGrassFeature(&random); + if (grassFeature) { + grassFeature->place(level, &random, x, y, z); + delete grassFeature; + } + }*/ + for (int i = 0; i < 10; i++) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(128); + int z = zo + random.nextInt(16) + 8; + ReedsFeature feature; + feature.place(level, &random, x, y, z); + } + + + //if (random.nextInt(32) == 0) { + // int x = xo + random.nextInt(16) + 8; + // int y = random.nextInt(128); + // int z = zo + random.nextInt(16) + 8; + // PumpkinFeature().place(level, random, x, y, z); + //} + + int cacti = 0; + if (biome == Biome::desert) cacti += 5; + + for (int i = 0; i < cacti; i++) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(128); + int z = zo + random.nextInt(16) + 8; + CactusFeature feature; + //LOGI("Tried creating a cactus at %d, %d, %d\n", x, y, z); + feature.place(level, &random, x, y, z); + } + + for (int i = 0; i < 50; i++) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(random.nextInt(120) + 8); + int z = zo + random.nextInt(16) + 8; + SpringFeature feature(Tile::water->id); + feature.place(level, &random, x, y, z); + } + + for (int i = 0; i < 20; i++) { + int x = xo + random.nextInt(16) + 8; + int y = random.nextInt(random.nextInt(random.nextInt(112) + 8) + 8); + int z = zo + random.nextInt(16) + 8; + SpringFeature feature(Tile::lava->id); + feature.place(level, &random, x, y, z); + } + + if (spawnMobs && !level->isClientSide) + MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, &random); + + //LOGI("Reading temp: 1\n"); + float* temperatures = level->getBiomeSource()->getTemperatureBlock(/*NULL,*/ xo + 8, zo + 8, 16, 16); + for (int x = xo + 8; x < xo + 8 + 16; x++) + for (int z = zo + 8; z < zo + 8 + 16; z++) { + int xp = x - (xo + 8); + int zp = z - (zo + 8); + int y = level->getTopSolidBlock(x, z); + float temp = temperatures[xp * 16 + zp] - (y - 64) / 64.0f * SNOW_SCALE; + if (temp < SNOW_CUTOFF) { + if (y > 0 && y < 128 && level->isEmptyTile(x, y, z) && level->getMaterial(x, y - 1, z)->blocksMotion()) { + if (level->getMaterial(x, y - 1, z) != Material::ice) level->setTile(x, y, z, Tile::topSnow->id); + } + } + } + //LOGI("Reading temp: 0 END\n"); + + const float et = getTimeS(); + totalTime += (et-st); + + //printf("Time to place features: %f. Total %f\n", et - st, totalTime); + + HeavyTile::instaFall = false; + + level->isGeneratingTerrain = false; +} + +LevelChunk* RandomLevelSource::create(int x, int z) { + return getChunk(x, z); +} + +LevelChunk* RandomLevelSource::getChunk(int xOffs, int zOffs) { + //static int chunkx = 0; + int hashedPos = ChunkPos::hashCode(xOffs, zOffs); + + ChunkMap::iterator it = chunkMap.find(hashedPos); + if (it != chunkMap.end()) + return it->second; + + random.setSeed((long)(xOffs * 341872712l + zOffs * 132899541l)); //@fix + + unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount]; + LevelChunk* levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); + chunkMap.insert(std::make_pair(hashedPos, levelChunk)); + + Biome** biomes = level->getBiomeSource()->getBiomeBlock(/*biomes, */xOffs * 16, zOffs * 16, 16, 16); + float* temperatures = level->getBiomeSource()->temperatures; + prepareHeights(xOffs, zOffs, blocks, 0, temperatures);//biomes, temperatures); + buildSurfaces(xOffs, zOffs, blocks, biomes); + + // Carve caves into the chunk + caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount); + levelChunk->recalcHeightmap(); + + return levelChunk; +} + +/*private*/ +float* RandomLevelSource::getHeights(float* buffer, int x, int y, int z, int xSize, int ySize, int zSize) { + const int size = xSize * ySize * zSize; + if (size > MAX_BUFFER_SIZE) { + LOGI("RandomLevelSource::getHeights: TOO LARGE BUFFER REQUESTED: %d (max %d)\n", size, MAX_BUFFER_SIZE); + } + + float s = 1 * 684.412f; + float hs = 1 * 684.412f; + + float* temperatures = level->getBiomeSource()->temperatures; + float* downfalls = level->getBiomeSource()->downfalls; + sr = scaleNoise.getRegion(sr, x, z, xSize, zSize, 1.121f, 1.121f, 0.5f); + dr = depthNoise.getRegion(dr, x, z, xSize, zSize, 200.0f, 200.0f, 0.5f); + + pnr = perlinNoise1.getRegion(pnr, (float)x, (float)y, (float)z, xSize, ySize, zSize, s / 80.0f, hs / 160.0f, s / 80.0f); + ar = lperlinNoise1.getRegion(ar, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s); + br = lperlinNoise2.getRegion(br, (float)x, (float)y, (float)z, xSize, ySize, zSize, s, hs, s); + + int p = 0; + int pp = 0; + + int wScale = 16 / xSize; + for (int xx = 0; xx < xSize; xx++) { + int xp = xx * wScale + wScale / 2; + + for (int zz = 0; zz < zSize; zz++) { + int zp = zz * wScale + wScale / 2; + float temperature = temperatures[xp * 16 + zp]; + float downfall = downfalls[xp * 16 + zp] * temperature; + float dd = 1 - downfall; + dd = dd * dd; + dd = dd * dd; + dd = 1 - dd; + + float scale = ((sr[pp] + 256.0f) / 512); + scale *= dd; + if (scale > 1) scale = 1; + + + float depth = (dr[pp] / 8000.0f); + if (depth < 0) depth = -depth * 0.3f; + depth = depth * 3.0f - 2.0f; + + if (depth < 0) { + depth = depth / 2; + if (depth < -1) depth = -1; + depth = depth / 1.4f; + depth /= 2; + scale = 0; + } else { + if (depth > 1) depth = 1; + depth = depth / 8; + } + + if (scale < 0) scale = 0; + scale = (scale) + 0.5f; + depth = depth * ySize / 16; + + float yCenter = ySize / 2.0f + depth * 4; + + pp++; + + for (int yy = 0; yy < ySize; yy++) { + float val = 0; + + float yOffs = (yy - (yCenter)) * 12 / scale; + if (yOffs < 0) yOffs *= 4; + + float bb = ar[p] / 512; + float cc = br[p] / 512; + + float v = (pnr[p] / 10 + 1) / 2; + if (v < 0) val = bb; + else if (v > 1) val = cc; + else val = bb + (cc - bb) * v; + val -= yOffs; + + if (yy > ySize - 4) { + float slide = (yy - (ySize - 4)) / (4 - 1.0f); + val = val * (1 - slide) + -10 * slide; + } + + buffer[p] = val; + p++; + } + } + } + return buffer; +} + +/*private*/ +void RandomLevelSource::calcWaterDepths(ChunkSource* parent, int xt, int zt) { + int xo = xt * 16; + int zo = zt * 16; + for (int x = 0; x < 16; x++) { + int y = level->getSeaLevel(); + for (int z = 0; z < 16; z++) { + int xp = xo + x + 7; + int zp = zo + z + 7; + int h = level->getHeightmap(xp, zp); + if (h <= 0) { + if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) { + bool hadWater = false; + if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater->id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater->id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater->id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater->id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; + if (hadWater) { + for (int x2 = -5; x2 <= 5; x2++) { + for (int z2 = -5; z2 <= 5; z2++) { + int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); + + if (d <= 5) { + d = 6 - d; + if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater->id) { + int od = level->getData(xp + x2, y, zp + z2); + if (od < 7 && od < d) { + level->setData(xp + x2, y, zp + z2, d); + } + } + } + } + } + if (hadWater) { + level->setTileAndDataNoUpdate(xp, y, zp, Tile::calmWater->id, 7); + for (int y2 = 0; y2 < y; y2++) { + level->setTileAndDataNoUpdate(xp, y2, zp, Tile::calmWater->id, 8); + } + } + } + } + } + } + } +} + +bool RandomLevelSource::hasChunk(int x, int y) { + //return x >= 0 && x < 16 && y >= 0 && y < 16; + return true; +} + +bool RandomLevelSource::tick() { + return false; +} + +bool RandomLevelSource::shouldSave() { + return true; +} + +std::string RandomLevelSource::gatherStats() { + return "RandomLevelSource"; +} + +//bool RandomLevelSource::save(bool force, ProgressListener progressListener) { +// return true; +//} + +Biome::MobList RandomLevelSource::getMobsAt(const MobCategory& mobCategory, int x, int y, int z) { + BiomeSource* biomeSource = level->getBiomeSource(); + if (biomeSource == NULL) { + return Biome::MobList(); + } +// static Stopwatch sw; sw.start(); + Biome* biome = biomeSource->getBiome(x, z); +// sw.stop(); +// sw.printEvery(10, "getBiome::"); + if (biome == NULL) { + return Biome::MobList(); + } + return biome->getMobs(mobCategory); +} + + +LevelChunk* PerformanceTestChunkSource::create(int x, int z) +{ + unsigned char* blocks = new unsigned char[LevelChunk::ChunkBlockCount]; + memset(blocks, 0, LevelChunk::ChunkBlockCount); + + for (int y = 0; y < 65; y++) + { + if (y < 60) + { + for (int x = (y + 1) & 1; x < 16; x += 2) + { + for (int z = y & 1; z < 16; z += 2) + { + blocks[x << 11 | z << 7 | y] = 3; + } + } + } + else + { + for (int x = 0; x < 16; x += 2) + { + for (int z = 0; z < 16; z += 2) + { + blocks[x << 11 | z << 7 | y] = 3; + } + } + + } + } + + LevelChunk* levelChunk = new LevelChunk(level, blocks, x, z); + + //caveFeature.apply(this, level, xOffs, zOffs, blocks, LevelChunk::ChunkBlockCount); + levelChunk->recalcHeightmap(); + + return levelChunk; +} diff --git a/src/world/level/levelgen/RandomLevelSource.h b/src/world/level/levelgen/RandomLevelSource.hpp similarity index 95% rename from src/world/level/levelgen/RandomLevelSource.h rename to src/world/level/levelgen/RandomLevelSource.hpp index b1a634a..83ace20 100755 --- a/src/world/level/levelgen/RandomLevelSource.h +++ b/src/world/level/levelgen/RandomLevelSource.hpp @@ -22,10 +22,10 @@ class LevelChunk; #endif -#include "../chunk/ChunkSource.h" -#include "LargeCaveFeature.h" -#include "synth/PerlinNoise.h" -#include "../../../SharedConstants.h" +#include "world/level/chunk/ChunkSource.hpp" +#include "LargeCaveFeature.hpp" +#include "synth/PerlinNoise.hpp" +#include "SharedConstants.hpp" class RandomLevelSource: public ChunkSource { diff --git a/src/world/level/levelgen/TownFeature.h b/src/world/level/levelgen/TownFeature.hpp similarity index 87% rename from src/world/level/levelgen/TownFeature.h rename to src/world/level/levelgen/TownFeature.hpp index eec4f04..21e42de 100755 --- a/src/world/level/levelgen/TownFeature.h +++ b/src/world/level/levelgen/TownFeature.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.levelgen; -#include "world/level/Level.h" +#include "world/level/Level.hpp" /*public*/ class TownFeature extends LargeFeature { /*protected*/ void addFeature(Level level, int x, int z, int xOffs, int zOffs, byte[] blocks) { diff --git a/src/world/level/levelgen/feature/BirchFeature.h b/src/world/level/levelgen/feature/BirchFeature.hpp similarity index 92% rename from src/world/level/levelgen/feature/BirchFeature.h rename to src/world/level/levelgen/feature/BirchFeature.hpp index 100528a..1066271 100755 --- a/src/world/level/levelgen/feature/BirchFeature.h +++ b/src/world/level/levelgen/feature/BirchFeature.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" -#include "../../../../util/Random.h" -#include "../../Level.h" -#include "../../tile/LeafTile.h" -#include "../../tile/Tile.h" -#include "../../tile/TreeTile.h" +#include "Feature.hpp" +#include "util/Random.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/LeafTile.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/TreeTile.hpp" /** * Same as tree feature, but slightly taller and white in color diff --git a/src/world/level/levelgen/feature/CactusFeature.h b/src/world/level/levelgen/feature/CactusFeature.hpp similarity index 90% rename from src/world/level/levelgen/feature/CactusFeature.h rename to src/world/level/levelgen/feature/CactusFeature.hpp index b136ac4..e55e1aa 100755 --- a/src/world/level/levelgen/feature/CactusFeature.h +++ b/src/world/level/levelgen/feature/CactusFeature.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.levelgen.feature; -#include "../../../../util/Mth.h" +#include "util/Mth.hpp" -#include "../../Level.h" -#include "../../tile/CactusTile.h" +#include "world/level/Level.hpp" +#include "world/level/tile/CactusTile.hpp" /* import net.minecraft.world.level.tile.* */ class CactusFeature: public Feature diff --git a/src/world/level/levelgen/feature/ClayFeature.h b/src/world/level/levelgen/feature/ClayFeature.hpp similarity index 91% rename from src/world/level/levelgen/feature/ClayFeature.h rename to src/world/level/levelgen/feature/ClayFeature.hpp index 8d17ff2..b6f82af 100755 --- a/src/world/level/levelgen/feature/ClayFeature.h +++ b/src/world/level/levelgen/feature/ClayFeature.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" -#include "../../Level.h" -#include "../../tile/Tile.h" -#include "../../material/Material.h" -#include "../../../../util/Mth.h" -#include "../../../../util/Random.h" +#include "Feature.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Mth.hpp" +#include "util/Random.hpp" class ClayFeature: public Feature { diff --git a/src/world/level/levelgen/feature/Feature.cpp b/src/world/level/levelgen/feature/Feature.cpp index be36828..128544f 100755 --- a/src/world/level/levelgen/feature/Feature.cpp +++ b/src/world/level/levelgen/feature/Feature.cpp @@ -1,26 +1,26 @@ -#include "Feature.h" - -Feature::Feature( bool doUpdate /*= false*/ ) -: doUpdate(doUpdate) -{ -} - -void Feature::placeBlock( Level* level, int x, int y, int z, int tile ) -{ - placeBlock(level, x, y, z, tile, 0); -} - -void Feature::placeBlock( Level* level, int x, int y, int z, int tile, int data ) -{ - if (doUpdate) { - level->setTileAndData(x, y, z, tile, data); - /* - } else if (level->hasChunkAt(x, y, z) && level->getChunkAt(x, z).seenByPlayer) { - if (level->setTileAndDataNoUpdate(x, y, z, tile, data)) { - level->sendTileUpdated(x, y, z); - } - */ - } else { - level->setTileAndDataNoUpdate(x, y, z, tile, data); - } -} +#include "Feature.hpp" + +Feature::Feature( bool doUpdate /*= false*/ ) +: doUpdate(doUpdate) +{ +} + +void Feature::placeBlock( Level* level, int x, int y, int z, int tile ) +{ + placeBlock(level, x, y, z, tile, 0); +} + +void Feature::placeBlock( Level* level, int x, int y, int z, int tile, int data ) +{ + if (doUpdate) { + level->setTileAndData(x, y, z, tile, data); + /* + } else if (level->hasChunkAt(x, y, z) && level->getChunkAt(x, z).seenByPlayer) { + if (level->setTileAndDataNoUpdate(x, y, z, tile, data)) { + level->sendTileUpdated(x, y, z); + } + */ + } else { + level->setTileAndDataNoUpdate(x, y, z, tile, data); + } +} diff --git a/src/world/level/levelgen/feature/Feature.h b/src/world/level/levelgen/feature/Feature.hpp similarity index 93% rename from src/world/level/levelgen/feature/Feature.h rename to src/world/level/levelgen/feature/Feature.hpp index d5c8e89..a173871 100755 --- a/src/world/level/levelgen/feature/Feature.h +++ b/src/world/level/levelgen/feature/Feature.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.levelgen.feature; -#include "../../Level.h" +#include "world/level/Level.hpp" class Random; class Feature diff --git a/src/world/level/levelgen/feature/FeatureInclude.h b/src/world/level/levelgen/feature/FeatureInclude.h deleted file mode 100755 index e3822ff..0000000 --- a/src/world/level/levelgen/feature/FeatureInclude.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "Feature.h" -#include "CactusFeature.h" -#include "ClayFeature.h" -#include "FlowerFeature.h" -#include "TreeFeature.h" -#include "LakeFeature.h" -#include "OreFeature.h" -#include "ReedsFeature.h" -#include "SpringFeature.h" - diff --git a/src/world/level/levelgen/feature/FeatureInclude.hpp b/src/world/level/levelgen/feature/FeatureInclude.hpp new file mode 100755 index 0000000..4b330ff --- /dev/null +++ b/src/world/level/levelgen/feature/FeatureInclude.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "Feature.hpp" +#include "CactusFeature.hpp" +#include "ClayFeature.hpp" +#include "FlowerFeature.hpp" +#include "TreeFeature.hpp" +#include "LakeFeature.hpp" +#include "OreFeature.hpp" +#include "ReedsFeature.hpp" +#include "SpringFeature.hpp" + diff --git a/src/world/level/levelgen/feature/FlowerFeature.h b/src/world/level/levelgen/feature/FlowerFeature.hpp similarity index 86% rename from src/world/level/levelgen/feature/FlowerFeature.h rename to src/world/level/levelgen/feature/FlowerFeature.hpp index 590bd79..1747a16 100755 --- a/src/world/level/levelgen/feature/FlowerFeature.h +++ b/src/world/level/levelgen/feature/FlowerFeature.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.levelgen.feature; -#include "../../../../util/Random.h" -#include "../../Level.h" +#include "util/Random.hpp" +#include "world/level/Level.hpp" -#include "../../tile/Bush.h" -#include "Feature.h" +#include "world/level/tile/Bush.hpp" +#include "Feature.hpp" class FlowerFeature: public Feature { public: diff --git a/src/world/level/levelgen/feature/LakeFeature.h b/src/world/level/levelgen/feature/LakeFeature.hpp similarity index 96% rename from src/world/level/levelgen/feature/LakeFeature.h rename to src/world/level/levelgen/feature/LakeFeature.hpp index 3664900..0b5b585 100755 --- a/src/world/level/levelgen/feature/LakeFeature.h +++ b/src/world/level/levelgen/feature/LakeFeature.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" -#include "../../Level.h" -#include "../../tile/Tile.h" -#include "../../material/Material.h" -#include "../../../../util/Mth.h" -#include "../../../../util/Random.h" +#include "Feature.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Mth.hpp" +#include "util/Random.hpp" class LakeFeature: public Feature { diff --git a/src/world/level/levelgen/feature/OreFeature.h b/src/world/level/levelgen/feature/OreFeature.hpp similarity index 92% rename from src/world/level/levelgen/feature/OreFeature.h rename to src/world/level/levelgen/feature/OreFeature.hpp index 7e57c9b..9f5ef89 100755 --- a/src/world/level/levelgen/feature/OreFeature.h +++ b/src/world/level/levelgen/feature/OreFeature.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" -#include "../../Level.h" -#include "../../tile/Tile.h" -#include "../../material/Material.h" -#include "../../../../util/Mth.h" -#include "../../../../util/Random.h" +#include "Feature.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Mth.hpp" +#include "util/Random.hpp" class OreFeature: public Feature { int tile; diff --git a/src/world/level/levelgen/feature/PineFeature.h b/src/world/level/levelgen/feature/PineFeature.hpp similarity index 93% rename from src/world/level/levelgen/feature/PineFeature.h rename to src/world/level/levelgen/feature/PineFeature.hpp index 51073bc..dd191c2 100755 --- a/src/world/level/levelgen/feature/PineFeature.h +++ b/src/world/level/levelgen/feature/PineFeature.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level->levelgen.feature; -#include "Feature.h" -#include "../../../../util/Random.h" -#include "../../Level.h" -#include "../../tile/LeafTile.h" -#include "../../tile/Tile.h" -#include "../../tile/TreeTile.h" +#include "Feature.hpp" +#include "util/Random.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/LeafTile.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/tile/TreeTile.hpp" class PineFeature: public Feature { diff --git a/src/world/level/levelgen/feature/ReedsFeature.h b/src/world/level/levelgen/feature/ReedsFeature.hpp similarity index 87% rename from src/world/level/levelgen/feature/ReedsFeature.h rename to src/world/level/levelgen/feature/ReedsFeature.hpp index e3680ce..f49ee63 100755 --- a/src/world/level/levelgen/feature/ReedsFeature.h +++ b/src/world/level/levelgen/feature/ReedsFeature.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" -#include "../../Level.h" -#include "../../tile/Tile.h" -#include "../../material/Material.h" -#include "../../../../util/Random.h" +#include "Feature.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Random.hpp" class ReedsFeature: public Feature { diff --git a/src/world/level/levelgen/feature/SpringFeature.h b/src/world/level/levelgen/feature/SpringFeature.hpp similarity index 89% rename from src/world/level/levelgen/feature/SpringFeature.h rename to src/world/level/levelgen/feature/SpringFeature.hpp index 6df9d15..7612489 100755 --- a/src/world/level/levelgen/feature/SpringFeature.h +++ b/src/world/level/levelgen/feature/SpringFeature.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" -#include "../../Level.h" -#include "../../tile/Tile.h" -#include "../../material/Material.h" -#include "../../../../util/Random.h" +#include "Feature.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/Tile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Random.hpp" class SpringFeature: public Feature { diff --git a/src/world/level/levelgen/feature/SpruceFeature.h b/src/world/level/levelgen/feature/SpruceFeature.hpp similarity index 95% rename from src/world/level/levelgen/feature/SpruceFeature.h rename to src/world/level/levelgen/feature/SpruceFeature.hpp index ef48284..69a15cd 100755 --- a/src/world/level/levelgen/feature/SpruceFeature.h +++ b/src/world/level/levelgen/feature/SpruceFeature.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" -#include "../../../../util/Random.h" -#include "../../Level.h" -#include "../../tile/LeafTile.h" -#include "../../tile/TreeTile.h" +#include "Feature.hpp" +#include "util/Random.hpp" +#include "world/level/Level.hpp" +#include "world/level/tile/LeafTile.hpp" +#include "world/level/tile/TreeTile.hpp" class SpruceFeature: public Feature { diff --git a/src/world/level/levelgen/feature/TallgrassFeature.h b/src/world/level/levelgen/feature/TallgrassFeature.hpp similarity index 97% rename from src/world/level/levelgen/feature/TallgrassFeature.h rename to src/world/level/levelgen/feature/TallgrassFeature.hpp index e8b0c46..9d59e6c 100755 --- a/src/world/level/levelgen/feature/TallgrassFeature.h +++ b/src/world/level/levelgen/feature/TallgrassFeature.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" +#include "Feature.hpp" class TallgrassFeature : public Feature { diff --git a/src/world/level/levelgen/feature/TreeFeature.h b/src/world/level/levelgen/feature/TreeFeature.hpp similarity index 94% rename from src/world/level/levelgen/feature/TreeFeature.h rename to src/world/level/levelgen/feature/TreeFeature.hpp index f9ff6fd..2fdd97d 100755 --- a/src/world/level/levelgen/feature/TreeFeature.h +++ b/src/world/level/levelgen/feature/TreeFeature.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.levelgen.feature; -#include "Feature.h" +#include "Feature.hpp" -#include "../../../../util/Random.h" -#include "../../Level.h" +#include "util/Random.hpp" +#include "world/level/Level.hpp" -#include "../../tile/TreeTile.h" +#include "world/level/tile/TreeTile.hpp" class TreeFeature: public Feature { diff --git a/src/world/level/levelgen/synth/ImprovedNoise.cpp b/src/world/level/levelgen/synth/ImprovedNoise.cpp index 316657a..59397af 100755 --- a/src/world/level/levelgen/synth/ImprovedNoise.cpp +++ b/src/world/level/levelgen/synth/ImprovedNoise.cpp @@ -1,205 +1,205 @@ -#include "ImprovedNoise.h" -#include "../../../../util/Random.h" - -ImprovedNoise::ImprovedNoise() -{ - Random random(1); - init(&random); -} - -ImprovedNoise::ImprovedNoise( Random* random ) -{ - init(random); -} - -void ImprovedNoise::init( Random* random ) -{ - xo = random->nextFloat() * 256.f; - yo = random->nextFloat() * 256.f; - zo = random->nextFloat() * 256.f; - for (int i = 0; i < 256; i++) { - p[i] = i; - } - - for (int i = 0; i < 256; i++) { - int j = random->nextInt(256 - i) + i; - int tmp = p[i]; - p[i] = p[j]; - p[j] = tmp; - - p[i + 256] = p[i]; - } -} - -float ImprovedNoise::noise( float _x, float _y, float _z ) -{ - float x = _x + xo; - float y = _y + yo; - float z = _z + zo; - - int xf = (int) x; - int yf = (int) y; - int zf = (int) z; - - if (x < xf) xf--; - if (y < yf) yf--; - if (z < zf) zf--; - - int X = xf & 255, // FIND UNIT CUBE THAT - Y = yf & 255, // CONTAINS POINT. - Z = zf & 255; - - x -= xf; // FIND RELATIVE X,Y,Z - y -= yf; // OF POINT IN CUBE. - z -= zf; - - float u = x * x * x * (x * (x * 6 - 15) + 10), // COMPUTE FADE CURVES - v = y * y * y * (y * (y * 6 - 15) + 10), // FOR EACH OF X,Y,Z. - w = z * z * z * (z * (z * 6 - 15) + 10); - - int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF - B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS, - - return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD - grad(p[BA], x - 1, y, z)), // BLENDED - lerp(u, grad(p[AB], x, y - 1, z), // RESULTS - grad(p[BB], x - 1, y - 1, z))),// FROM 8 - lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS - grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE - lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)))); -} - -const float ImprovedNoise::lerp( float t, float a, float b ) -{ - return a + t * (b - a); -} - -const float ImprovedNoise::grad2( int hash, float x, float z ) -{ - int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE - - float u = (1-((h&8)>>3))*x, // INTO 12 GRADIENT DIRECTIONS. - v = h < 4 ? 0 : h == 12 || h == 14 ? x : z; - - return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); -} - -const float ImprovedNoise::grad( int hash, float x, float y, float z ) -{ - int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE - - float u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. - v = h < 4 ? y : h == 12 || h == 14 ? x : z; - - return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); -} - -float ImprovedNoise::getValue( float x, float y ) -{ - return noise(x, y, 0); -} - -float ImprovedNoise::getValue( float x, float y, float z ) -{ - return noise(x, y, z); -} - -void ImprovedNoise::add( float* buffer, float _x, float _y, float _z, int xSize, int ySize, int zSize, float xs, float ys, float zs, float pow ) -{ - if (ySize==1) { - int A = 0, AA = 0, B = 0, BA = 0; - float vv0 = 0, vv2 = 0; - int pp = 0; - float scale = 1.0f / pow; - for (int xx = 0; xx < xSize; xx++) { - float x = (_x + xx) * xs + xo; - int xf = (int) x; - if (x < xf) xf--; - int X = xf & 255; - x -= xf; - float u = x * x * x * (x * (x * 6 - 15) + 10); - - for (int zz = 0; zz < zSize; zz++) { - float z = (_z + zz) * zs + zo; - int zf = (int) z; - if (z < zf) zf--; - int Z = zf & 255; - z -= zf; - float w = z * z * z * (z * (z * 6 - 15) + 10); - - A = p[X] + 0; - AA = p[A] + Z; - B = p[X + 1] + 0; - BA = p[B] + Z; - vv0 = lerp(u, grad2(p[AA], x, z), grad(p[BA], x - 1, 0, z)); - vv2 = lerp(u, grad(p[AA + 1], x, 0, z - 1), grad(p[BA + 1], x - 1, 0, z - 1)); - - float val = lerp(w, vv0, vv2); - - buffer[pp++] += val * scale; - } - } - return; - } - int pp = 0; - float scale = 1 / pow; - int yOld = -1; - int A = 0, AA = 0, AB = 0, B = 0, BA = 0, BB = 0; - float vv0 = 0, vv1 = 0, vv2 = 0, vv3 = 0; - - for (int xx = 0; xx < xSize; xx++) { - float x = (_x + xx) * xs + xo; - int xf = (int) x; - if (x < xf) xf--; - int X = xf & 255; - x -= xf; - float u = x * x * x * (x * (x * 6 - 15) + 10); - - - for (int zz = 0; zz < zSize; zz++) { - float z = (_z + zz) * zs + zo; - int zf = (int) z; - if (z < zf) zf--; - int Z = zf & 255; - z -= zf; - float w = z * z * z * (z * (z * 6 - 15) + 10); - - for (int yy = 0; yy < ySize; yy++) { - float y = (_y + yy) * ys + yo; - int yf = (int) y; - if (y < yf) yf--; - int Y = yf & 255; - y -= yf; - float v = y * y * y * (y * (y * 6 - 15) + 10); - - if (yy == 0 || Y != yOld) { - yOld = Y; - A = p[X] + Y; - AA = p[A] + Z; - AB = p[A + 1] + Z; - B = p[X + 1] + Y; - BA = p[B] + Z; - BB = p[B + 1] + Z; - vv0 = lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)); - vv1 = lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z)); - vv2 = lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)); - vv3 = lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)); - } - - float v0 = lerp(v, vv0, vv1); - float v1 = lerp(v, vv2, vv3); - float val = lerp(w, v0, v1); - - buffer[pp++] += val * scale; - } - } - } -} - -int ImprovedNoise::hashCode() { - int x = 4711; - for (int i = 0; i < 512; ++i) - x = x * 37 + p[i]; - return x; -} - +#include "ImprovedNoise.hpp" +#include "util/Random.hpp" + +ImprovedNoise::ImprovedNoise() +{ + Random random(1); + init(&random); +} + +ImprovedNoise::ImprovedNoise( Random* random ) +{ + init(random); +} + +void ImprovedNoise::init( Random* random ) +{ + xo = random->nextFloat() * 256.f; + yo = random->nextFloat() * 256.f; + zo = random->nextFloat() * 256.f; + for (int i = 0; i < 256; i++) { + p[i] = i; + } + + for (int i = 0; i < 256; i++) { + int j = random->nextInt(256 - i) + i; + int tmp = p[i]; + p[i] = p[j]; + p[j] = tmp; + + p[i + 256] = p[i]; + } +} + +float ImprovedNoise::noise( float _x, float _y, float _z ) +{ + float x = _x + xo; + float y = _y + yo; + float z = _z + zo; + + int xf = (int) x; + int yf = (int) y; + int zf = (int) z; + + if (x < xf) xf--; + if (y < yf) yf--; + if (z < zf) zf--; + + int X = xf & 255, // FIND UNIT CUBE THAT + Y = yf & 255, // CONTAINS POINT. + Z = zf & 255; + + x -= xf; // FIND RELATIVE X,Y,Z + y -= yf; // OF POINT IN CUBE. + z -= zf; + + float u = x * x * x * (x * (x * 6 - 15) + 10), // COMPUTE FADE CURVES + v = y * y * y * (y * (y * 6 - 15) + 10), // FOR EACH OF X,Y,Z. + w = z * z * z * (z * (z * 6 - 15) + 10); + + int A = p[X] + Y, AA = p[A] + Z, AB = p[A + 1] + Z, // HASH COORDINATES OF + B = p[X + 1] + Y, BA = p[B] + Z, BB = p[B + 1] + Z; // THE 8 CUBE CORNERS, + + return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), // AND ADD + grad(p[BA], x - 1, y, z)), // BLENDED + lerp(u, grad(p[AB], x, y - 1, z), // RESULTS + grad(p[BB], x - 1, y - 1, z))),// FROM 8 + lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1), // CORNERS + grad(p[BA + 1], x - 1, y, z - 1)), // OF CUBE + lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)))); +} + +const float ImprovedNoise::lerp( float t, float a, float b ) +{ + return a + t * (b - a); +} + +const float ImprovedNoise::grad2( int hash, float x, float z ) +{ + int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE + + float u = (1-((h&8)>>3))*x, // INTO 12 GRADIENT DIRECTIONS. + v = h < 4 ? 0 : h == 12 || h == 14 ? x : z; + + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); +} + +const float ImprovedNoise::grad( int hash, float x, float y, float z ) +{ + int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE + + float u = h < 8 ? x : y, // INTO 12 GRADIENT DIRECTIONS. + v = h < 4 ? y : h == 12 || h == 14 ? x : z; + + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); +} + +float ImprovedNoise::getValue( float x, float y ) +{ + return noise(x, y, 0); +} + +float ImprovedNoise::getValue( float x, float y, float z ) +{ + return noise(x, y, z); +} + +void ImprovedNoise::add( float* buffer, float _x, float _y, float _z, int xSize, int ySize, int zSize, float xs, float ys, float zs, float pow ) +{ + if (ySize==1) { + int A = 0, AA = 0, B = 0, BA = 0; + float vv0 = 0, vv2 = 0; + int pp = 0; + float scale = 1.0f / pow; + for (int xx = 0; xx < xSize; xx++) { + float x = (_x + xx) * xs + xo; + int xf = (int) x; + if (x < xf) xf--; + int X = xf & 255; + x -= xf; + float u = x * x * x * (x * (x * 6 - 15) + 10); + + for (int zz = 0; zz < zSize; zz++) { + float z = (_z + zz) * zs + zo; + int zf = (int) z; + if (z < zf) zf--; + int Z = zf & 255; + z -= zf; + float w = z * z * z * (z * (z * 6 - 15) + 10); + + A = p[X] + 0; + AA = p[A] + Z; + B = p[X + 1] + 0; + BA = p[B] + Z; + vv0 = lerp(u, grad2(p[AA], x, z), grad(p[BA], x - 1, 0, z)); + vv2 = lerp(u, grad(p[AA + 1], x, 0, z - 1), grad(p[BA + 1], x - 1, 0, z - 1)); + + float val = lerp(w, vv0, vv2); + + buffer[pp++] += val * scale; + } + } + return; + } + int pp = 0; + float scale = 1 / pow; + int yOld = -1; + int A = 0, AA = 0, AB = 0, B = 0, BA = 0, BB = 0; + float vv0 = 0, vv1 = 0, vv2 = 0, vv3 = 0; + + for (int xx = 0; xx < xSize; xx++) { + float x = (_x + xx) * xs + xo; + int xf = (int) x; + if (x < xf) xf--; + int X = xf & 255; + x -= xf; + float u = x * x * x * (x * (x * 6 - 15) + 10); + + + for (int zz = 0; zz < zSize; zz++) { + float z = (_z + zz) * zs + zo; + int zf = (int) z; + if (z < zf) zf--; + int Z = zf & 255; + z -= zf; + float w = z * z * z * (z * (z * 6 - 15) + 10); + + for (int yy = 0; yy < ySize; yy++) { + float y = (_y + yy) * ys + yo; + int yf = (int) y; + if (y < yf) yf--; + int Y = yf & 255; + y -= yf; + float v = y * y * y * (y * (y * 6 - 15) + 10); + + if (yy == 0 || Y != yOld) { + yOld = Y; + A = p[X] + Y; + AA = p[A] + Z; + AB = p[A + 1] + Z; + B = p[X + 1] + Y; + BA = p[B] + Z; + BB = p[B + 1] + Z; + vv0 = lerp(u, grad(p[AA], x, y, z), grad(p[BA], x - 1, y, z)); + vv1 = lerp(u, grad(p[AB], x, y - 1, z), grad(p[BB], x - 1, y - 1, z)); + vv2 = lerp(u, grad(p[AA + 1], x, y, z - 1), grad(p[BA + 1], x - 1, y, z - 1)); + vv3 = lerp(u, grad(p[AB + 1], x, y - 1, z - 1), grad(p[BB + 1], x - 1, y - 1, z - 1)); + } + + float v0 = lerp(v, vv0, vv1); + float v1 = lerp(v, vv2, vv3); + float val = lerp(w, v0, v1); + + buffer[pp++] += val * scale; + } + } + } +} + +int ImprovedNoise::hashCode() { + int x = 4711; + for (int i = 0; i < 512; ++i) + x = x * 37 + p[i]; + return x; +} + diff --git a/src/world/level/levelgen/synth/ImprovedNoise.h b/src/world/level/levelgen/synth/ImprovedNoise.hpp similarity index 97% rename from src/world/level/levelgen/synth/ImprovedNoise.h rename to src/world/level/levelgen/synth/ImprovedNoise.hpp index 5a8e981..d8b80c5 100755 --- a/src/world/level/levelgen/synth/ImprovedNoise.h +++ b/src/world/level/levelgen/synth/ImprovedNoise.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.levelgen.synth; -#include "Synth.h" +#include "Synth.hpp" class Random; class ImprovedNoise: public Synth diff --git a/src/world/level/levelgen/synth/PerlinNoise.cpp b/src/world/level/levelgen/synth/PerlinNoise.cpp index a10fc37..9b3544e 100755 --- a/src/world/level/levelgen/synth/PerlinNoise.cpp +++ b/src/world/level/levelgen/synth/PerlinNoise.cpp @@ -1,88 +1,88 @@ -#include "PerlinNoise.h" -#include "ImprovedNoise.h" - -void PerlinNoise::init( int levels ) -{ - this->levels = levels; - noiseLevels = new ImprovedNoise* [levels]; - for (int i = 0; i < levels; i++) { - noiseLevels[i] = new ImprovedNoise(_rndPtr); - } -} - -PerlinNoise::~PerlinNoise() -{ - for (int i = 0; i < levels; ++i) - delete noiseLevels[i]; - delete[] noiseLevels; -} - -PerlinNoise::PerlinNoise( int levels ) -{ - _rndPtr = &_random; - init(levels); -} - -PerlinNoise::PerlinNoise( Random* random, int levels ) -{ - _rndPtr = random; - init(levels); -} - -float PerlinNoise::getValue( float x, float y ) -{ - float value = 0; - float pow = 1; - - for (int i = 0; i < levels; i++) { - value += noiseLevels[i]->getValue(x * pow, y * pow) / pow; - pow /= 2; - } - - return value; -} - -float PerlinNoise::getValue( float x, float y, float z ) -{ - float value = 0; - float pow = 1; - - for (int i = 0; i < levels; i++) { - value += noiseLevels[i]->getValue(x * pow, y * pow, z * pow) / pow; - pow /= 2; - } - - return value; -} - -float* PerlinNoise::getRegion( float* buffer, float x, float y, float z, int xSize, int ySize, int zSize, float xScale, float yScale, float zScale ) -{ - const int size = xSize * ySize * zSize; - if (buffer == 0) { - buffer = new float[size]; - } - for (int i = 0; i < size; i++) - buffer[i] = 0; - - float pow = 1; - - for (int i = 0; i < levels; i++) { - noiseLevels[i]->add(buffer, x, y, z, xSize, ySize, zSize, xScale * pow, yScale * pow, zScale * pow, pow); - pow /= 2; - } - - return buffer; -} - -float* PerlinNoise::getRegion( float* sr, int x, int z, int xSize, int zSize, float xScale, float zScale, float pow ) -{ - return getRegion(sr, (float)x, 10.0f, (float)z, xSize, 1, zSize, xScale, 1, zScale); -} - -int PerlinNoise::hashCode() { - int x = 4711; - for (int i = 0; i < levels; ++i) - x *= noiseLevels[i]->hashCode(); - return x; -} - +#include "PerlinNoise.hpp" +#include "ImprovedNoise.hpp" + +void PerlinNoise::init( int levels ) +{ + this->levels = levels; + noiseLevels = new ImprovedNoise* [levels]; + for (int i = 0; i < levels; i++) { + noiseLevels[i] = new ImprovedNoise(_rndPtr); + } +} + +PerlinNoise::~PerlinNoise() +{ + for (int i = 0; i < levels; ++i) + delete noiseLevels[i]; + delete[] noiseLevels; +} + +PerlinNoise::PerlinNoise( int levels ) +{ + _rndPtr = &_random; + init(levels); +} + +PerlinNoise::PerlinNoise( Random* random, int levels ) +{ + _rndPtr = random; + init(levels); +} + +float PerlinNoise::getValue( float x, float y ) +{ + float value = 0; + float pow = 1; + + for (int i = 0; i < levels; i++) { + value += noiseLevels[i]->getValue(x * pow, y * pow) / pow; + pow /= 2; + } + + return value; +} + +float PerlinNoise::getValue( float x, float y, float z ) +{ + float value = 0; + float pow = 1; + + for (int i = 0; i < levels; i++) { + value += noiseLevels[i]->getValue(x * pow, y * pow, z * pow) / pow; + pow /= 2; + } + + return value; +} + +float* PerlinNoise::getRegion( float* buffer, float x, float y, float z, int xSize, int ySize, int zSize, float xScale, float yScale, float zScale ) +{ + const int size = xSize * ySize * zSize; + if (buffer == 0) { + buffer = new float[size]; + } + for (int i = 0; i < size; i++) + buffer[i] = 0; + + float pow = 1; + + for (int i = 0; i < levels; i++) { + noiseLevels[i]->add(buffer, x, y, z, xSize, ySize, zSize, xScale * pow, yScale * pow, zScale * pow, pow); + pow /= 2; + } + + return buffer; +} + +float* PerlinNoise::getRegion( float* sr, int x, int z, int xSize, int zSize, float xScale, float zScale, float pow ) +{ + return getRegion(sr, (float)x, 10.0f, (float)z, xSize, 1, zSize, xScale, 1, zScale); +} + +int PerlinNoise::hashCode() { + int x = 4711; + for (int i = 0; i < levels; ++i) + x *= noiseLevels[i]->hashCode(); + return x; +} + diff --git a/src/world/level/levelgen/synth/PerlinNoise.h b/src/world/level/levelgen/synth/PerlinNoise.hpp similarity index 93% rename from src/world/level/levelgen/synth/PerlinNoise.h rename to src/world/level/levelgen/synth/PerlinNoise.hpp index 9791a02..0b71aff 100755 --- a/src/world/level/levelgen/synth/PerlinNoise.h +++ b/src/world/level/levelgen/synth/PerlinNoise.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.levelgen.synth; -#include "../../../../util/Random.h" -#include "Synth.h" +#include "util/Random.hpp" +#include "Synth.hpp" class ImprovedNoise; diff --git a/src/world/level/levelgen/synth/Synth.cpp b/src/world/level/levelgen/synth/Synth.cpp index a47889b..48f8bfc 100755 --- a/src/world/level/levelgen/synth/Synth.cpp +++ b/src/world/level/levelgen/synth/Synth.cpp @@ -1,21 +1,21 @@ -#include "Synth.h" - -Synth::~Synth() -{ - -} - -int Synth::getDataSize( int width, int height ) -{ - return width * height * sizeof(float); -} - -void Synth::create( int width, int height, float* result ) -{ - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - result[x + y * width] = getValue((float)x, (float)y); - } - } -} - +#include "Synth.hpp" + +Synth::~Synth() +{ + +} + +int Synth::getDataSize( int width, int height ) +{ + return width * height * sizeof(float); +} + +void Synth::create( int width, int height, float* result ) +{ + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + result[x + y * width] = getValue((float)x, (float)y); + } + } +} + diff --git a/src/world/level/levelgen/synth/Synth.h b/src/world/level/levelgen/synth/Synth.hpp similarity index 100% rename from src/world/level/levelgen/synth/Synth.h rename to src/world/level/levelgen/synth/Synth.hpp diff --git a/src/world/level/material/DecorationMaterial.h b/src/world/level/material/DecorationMaterial.hpp similarity index 92% rename from src/world/level/material/DecorationMaterial.h rename to src/world/level/material/DecorationMaterial.hpp index 06d1b8b..35262a9 100755 --- a/src/world/level/material/DecorationMaterial.h +++ b/src/world/level/material/DecorationMaterial.hpp @@ -1,7 +1,7 @@ #pragma once //package net.minecraft.world.level.material; -#include "Material.h" +#include "Material.hpp" class DecorationMaterial: public Material { diff --git a/src/world/level/material/GasMaterial.h b/src/world/level/material/GasMaterial.hpp similarity index 93% rename from src/world/level/material/GasMaterial.h rename to src/world/level/material/GasMaterial.hpp index a56fc8d..b9950ac 100755 --- a/src/world/level/material/GasMaterial.h +++ b/src/world/level/material/GasMaterial.hpp @@ -1,7 +1,7 @@ #pragma once //package net.minecraft.world.level.material; -#include "Material.h" +#include "Material.hpp" class GasMaterial: public Material { diff --git a/src/world/level/material/LiquidMaterial.h b/src/world/level/material/LiquidMaterial.hpp similarity index 93% rename from src/world/level/material/LiquidMaterial.h rename to src/world/level/material/LiquidMaterial.hpp index 1ab3979..acb0ad1 100755 --- a/src/world/level/material/LiquidMaterial.h +++ b/src/world/level/material/LiquidMaterial.hpp @@ -1,7 +1,7 @@ #pragma once //package net.minecraft.world.level.material; -#include "Material.h" +#include "Material.hpp" class LiquidMaterial: public Material { diff --git a/src/world/level/material/Material.cpp b/src/world/level/material/Material.cpp index 0d61d1a..5731ae1 100755 --- a/src/world/level/material/Material.cpp +++ b/src/world/level/material/Material.cpp @@ -1,99 +1,99 @@ -#include "Material.h" -#include "GasMaterial.h" -#include "LiquidMaterial.h" -#include "DecorationMaterial.h" -#include "WebMaterial.h" -#include - -const Material* Material::air = NULL; -const Material* Material::dirt = NULL; -const Material* Material::wood = NULL; -const Material* Material::stone = NULL; -const Material* Material::metal = NULL; -const Material* Material::water = NULL; -const Material* Material::lava = NULL; -const Material* Material::leaves = NULL; -const Material* Material::plant = NULL; -const Material* Material::replaceable_plant = NULL; -const Material* Material::sponge = NULL; -const Material* Material::cloth = NULL; -const Material* Material::fire = NULL; -const Material* Material::sand = NULL; -const Material* Material::decoration= NULL; -const Material* Material::glass = NULL; -const Material* Material::explosive = NULL; -const Material* Material::coral = NULL; -const Material* Material::ice = NULL; -const Material* Material::topSnow = NULL; -const Material* Material::snow = NULL; -const Material* Material::cactus = NULL; -const Material* Material::clay = NULL; -const Material* Material::vegetable = NULL; -const Material* Material::portal = NULL; -const Material* Material::cake = NULL; -const Material* Material::web = NULL; - -/*static*/ -void Material::initMaterials() -{ - air = new GasMaterial(); - dirt = new Material(); - wood = (new Material())->flammable(); - stone = (new Material())->notAlwaysDestroyable(); - metal = (new Material())->notAlwaysDestroyable(); - water = new LiquidMaterial(); - lava = new LiquidMaterial(); - leaves = (new Material())->flammable()->neverBuildable(); - plant = new DecorationMaterial(); - replaceable_plant = (new DecorationMaterial())->replaceable()->flammable(); - sponge = new Material(); - cloth = (new Material())->flammable(); - fire = new GasMaterial(); - sand = new Material(); - decoration= new DecorationMaterial(); - glass = (new Material())->neverBuildable(); - explosive = (new Material())->flammable()->neverBuildable(); - coral = new Material(); - ice = (new Material())->neverBuildable(); - topSnow = (new DecorationMaterial())->neverBuildable()->notAlwaysDestroyable()->replaceable(); - snow = (new Material())->notAlwaysDestroyable(); - cactus = (new Material())->neverBuildable(); - clay = new Material(); - vegetable = new Material(); - portal = new Material(); - cake = new Material(); - web = (new WebMaterial()); -} - -#define SAFEDEL(x) if (x) { delete x; x = NULL; } - -/*static*/ -void Material::teardownMaterials() { - SAFEDEL(air); - SAFEDEL(dirt); - SAFEDEL(wood); - SAFEDEL(stone); - SAFEDEL(metal); - SAFEDEL(water); - SAFEDEL(lava); - SAFEDEL(leaves); - SAFEDEL(plant); - SAFEDEL(replaceable_plant); - SAFEDEL(sponge); - SAFEDEL(cloth); - SAFEDEL(fire); - SAFEDEL(sand); - SAFEDEL(decoration); - SAFEDEL(glass); - SAFEDEL(explosive); - SAFEDEL(coral); - SAFEDEL(ice); - SAFEDEL(topSnow); - SAFEDEL(snow); - SAFEDEL(cactus); - SAFEDEL(clay); - SAFEDEL(vegetable); - SAFEDEL(portal); - SAFEDEL(cake); - SAFEDEL(web); -} +#include "Material.hpp" +#include "GasMaterial.hpp" +#include "LiquidMaterial.hpp" +#include "DecorationMaterial.hpp" +#include "WebMaterial.hpp" +#include + +const Material* Material::air = NULL; +const Material* Material::dirt = NULL; +const Material* Material::wood = NULL; +const Material* Material::stone = NULL; +const Material* Material::metal = NULL; +const Material* Material::water = NULL; +const Material* Material::lava = NULL; +const Material* Material::leaves = NULL; +const Material* Material::plant = NULL; +const Material* Material::replaceable_plant = NULL; +const Material* Material::sponge = NULL; +const Material* Material::cloth = NULL; +const Material* Material::fire = NULL; +const Material* Material::sand = NULL; +const Material* Material::decoration= NULL; +const Material* Material::glass = NULL; +const Material* Material::explosive = NULL; +const Material* Material::coral = NULL; +const Material* Material::ice = NULL; +const Material* Material::topSnow = NULL; +const Material* Material::snow = NULL; +const Material* Material::cactus = NULL; +const Material* Material::clay = NULL; +const Material* Material::vegetable = NULL; +const Material* Material::portal = NULL; +const Material* Material::cake = NULL; +const Material* Material::web = NULL; + +/*static*/ +void Material::initMaterials() +{ + air = new GasMaterial(); + dirt = new Material(); + wood = (new Material())->flammable(); + stone = (new Material())->notAlwaysDestroyable(); + metal = (new Material())->notAlwaysDestroyable(); + water = new LiquidMaterial(); + lava = new LiquidMaterial(); + leaves = (new Material())->flammable()->neverBuildable(); + plant = new DecorationMaterial(); + replaceable_plant = (new DecorationMaterial())->replaceable()->flammable(); + sponge = new Material(); + cloth = (new Material())->flammable(); + fire = new GasMaterial(); + sand = new Material(); + decoration= new DecorationMaterial(); + glass = (new Material())->neverBuildable(); + explosive = (new Material())->flammable()->neverBuildable(); + coral = new Material(); + ice = (new Material())->neverBuildable(); + topSnow = (new DecorationMaterial())->neverBuildable()->notAlwaysDestroyable()->replaceable(); + snow = (new Material())->notAlwaysDestroyable(); + cactus = (new Material())->neverBuildable(); + clay = new Material(); + vegetable = new Material(); + portal = new Material(); + cake = new Material(); + web = (new WebMaterial()); +} + +#define SAFEDEL(x) if (x) { delete x; x = NULL; } + +/*static*/ +void Material::teardownMaterials() { + SAFEDEL(air); + SAFEDEL(dirt); + SAFEDEL(wood); + SAFEDEL(stone); + SAFEDEL(metal); + SAFEDEL(water); + SAFEDEL(lava); + SAFEDEL(leaves); + SAFEDEL(plant); + SAFEDEL(replaceable_plant); + SAFEDEL(sponge); + SAFEDEL(cloth); + SAFEDEL(fire); + SAFEDEL(sand); + SAFEDEL(decoration); + SAFEDEL(glass); + SAFEDEL(explosive); + SAFEDEL(coral); + SAFEDEL(ice); + SAFEDEL(topSnow); + SAFEDEL(snow); + SAFEDEL(cactus); + SAFEDEL(clay); + SAFEDEL(vegetable); + SAFEDEL(portal); + SAFEDEL(cake); + SAFEDEL(web); +} diff --git a/src/world/level/material/Material.h b/src/world/level/material/Material.hpp similarity index 100% rename from src/world/level/material/Material.h rename to src/world/level/material/Material.hpp diff --git a/src/world/level/material/WebMaterial.h b/src/world/level/material/WebMaterial.hpp similarity index 90% rename from src/world/level/material/WebMaterial.h rename to src/world/level/material/WebMaterial.hpp index 804d7b9..c43c25c 100755 --- a/src/world/level/material/WebMaterial.h +++ b/src/world/level/material/WebMaterial.hpp @@ -1,7 +1,7 @@ #pragma once //package net.minecraft.world.level.material; -#include "Material.h" +#include "Material.hpp" class WebMaterial: public Material { diff --git a/src/world/level/pathfinder/BinaryHeap.h b/src/world/level/pathfinder/BinaryHeap.hpp similarity index 99% rename from src/world/level/pathfinder/BinaryHeap.h rename to src/world/level/pathfinder/BinaryHeap.hpp index 0b555f5..820099e 100755 --- a/src/world/level/pathfinder/BinaryHeap.h +++ b/src/world/level/pathfinder/BinaryHeap.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level->pathfinder; -#include "Node.h" +#include "Node.hpp" #include class BinaryHeap diff --git a/src/world/level/pathfinder/Node.h b/src/world/level/pathfinder/Node.hpp similarity index 98% rename from src/world/level/pathfinder/Node.h rename to src/world/level/pathfinder/Node.hpp index bd2d23a..2b5deef 100755 --- a/src/world/level/pathfinder/Node.h +++ b/src/world/level/pathfinder/Node.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.pathfinder; -#include "../../../util/Mth.h" +#include "util/Mth.hpp" #include class Node diff --git a/src/world/level/pathfinder/Path.cpp b/src/world/level/pathfinder/Path.cpp index 7a67af6..efad0c0 100755 --- a/src/world/level/pathfinder/Path.cpp +++ b/src/world/level/pathfinder/Path.cpp @@ -1,134 +1,134 @@ -#include "Path.h" - -int Path::p = 0; - -Path::Path() -: nodes(NULL), - length(0), - index(0), - id(++p) -{ -} - -Path::~Path() -{ - destroy(); -} - -bool Path::isEmpty() const -{ - return length == 0 || nodes == NULL; -} - -void Path::copyNodes( Node** nodes, int length ) -{ - destroy(); - - this->length = length; - this->nodes = new Node*[length]; - - for (int i = 0; i < length; ++i) - this->nodes[i] = new Node(*nodes[i]); -} - -void Path::destroy() -{ - if (nodes) { - for (int i = 0; i < length; ++i) - delete nodes[i]; - delete[] nodes; - - nodes = NULL; - index = length = 0; - } -} - -Node* Path::currentPos() -{ - return nodes[index]; -} - -Vec3 Path::currentPos( Entity* e ) const -{ - return getPos(e, index); -} - -void Path::next() -{ - index++; -} - -void Path::setSize( int size ) -{ - length = size; -} - -int Path::getSize() const -{ - return length; -} - -bool Path::isDone() const -{ - return index >= length; -} - -Node* Path::last() const -{ - if (length > 0) { - return nodes[length - 1]; - } - return NULL; -} - -Node* Path::get( int i ) const -{ - return nodes[i]; -} - -int Path::getIndex() const -{ - return index; -} - -void Path::setIndex( int index ) -{ - this->index = index; -} - -Vec3 Path::getPos( Entity* e, int index ) const -{ - float x = nodes[index]->x + (int) (e->bbWidth + 1) * 0.5f; - float z = nodes[index]->z + (int) (e->bbWidth + 1) * 0.5f; - float y = nodes[index]->y; - return Vec3(x, y, z); -} - -bool Path::sameAs( const Path* path ) const -{ - if (!path) return false; - if (path->length != length) return false; - for (int i = 0; i < length; ++i) { - Node& node = *path->nodes[i]; - if (nodes[i]->x != node.x || nodes[i]->y != node.y || nodes[i]->z != node.z) - return false; - } - return true; -} - -bool Path::endsIn( const Vec3& pos ) const -{ - const Node* end = last(); - if (end == NULL) return false; - return end->x == Mth::floor(pos.x) - && end->y == Mth::floor(pos.y) - && end->z == Mth::floor(pos.z); -} - -bool Path::endsInXZ( const Vec3& pos ) const -{ - const Node* end = last(); - if (end == NULL) return false; - return end->x == Mth::floor(pos.x) - && end->z == Mth::floor(pos.z); -} +#include "Path.hpp" + +int Path::p = 0; + +Path::Path() +: nodes(NULL), + length(0), + index(0), + id(++p) +{ +} + +Path::~Path() +{ + destroy(); +} + +bool Path::isEmpty() const +{ + return length == 0 || nodes == NULL; +} + +void Path::copyNodes( Node** nodes, int length ) +{ + destroy(); + + this->length = length; + this->nodes = new Node*[length]; + + for (int i = 0; i < length; ++i) + this->nodes[i] = new Node(*nodes[i]); +} + +void Path::destroy() +{ + if (nodes) { + for (int i = 0; i < length; ++i) + delete nodes[i]; + delete[] nodes; + + nodes = NULL; + index = length = 0; + } +} + +Node* Path::currentPos() +{ + return nodes[index]; +} + +Vec3 Path::currentPos( Entity* e ) const +{ + return getPos(e, index); +} + +void Path::next() +{ + index++; +} + +void Path::setSize( int size ) +{ + length = size; +} + +int Path::getSize() const +{ + return length; +} + +bool Path::isDone() const +{ + return index >= length; +} + +Node* Path::last() const +{ + if (length > 0) { + return nodes[length - 1]; + } + return NULL; +} + +Node* Path::get( int i ) const +{ + return nodes[i]; +} + +int Path::getIndex() const +{ + return index; +} + +void Path::setIndex( int index ) +{ + this->index = index; +} + +Vec3 Path::getPos( Entity* e, int index ) const +{ + float x = nodes[index]->x + (int) (e->bbWidth + 1) * 0.5f; + float z = nodes[index]->z + (int) (e->bbWidth + 1) * 0.5f; + float y = nodes[index]->y; + return Vec3(x, y, z); +} + +bool Path::sameAs( const Path* path ) const +{ + if (!path) return false; + if (path->length != length) return false; + for (int i = 0; i < length; ++i) { + Node& node = *path->nodes[i]; + if (nodes[i]->x != node.x || nodes[i]->y != node.y || nodes[i]->z != node.z) + return false; + } + return true; +} + +bool Path::endsIn( const Vec3& pos ) const +{ + const Node* end = last(); + if (end == NULL) return false; + return end->x == Mth::floor(pos.x) + && end->y == Mth::floor(pos.y) + && end->z == Mth::floor(pos.z); +} + +bool Path::endsInXZ( const Vec3& pos ) const +{ + const Node* end = last(); + if (end == NULL) return false; + return end->x == Mth::floor(pos.x) + && end->z == Mth::floor(pos.z); +} diff --git a/src/world/level/pathfinder/Path.h b/src/world/level/pathfinder/Path.hpp similarity index 89% rename from src/world/level/pathfinder/Path.h rename to src/world/level/pathfinder/Path.hpp index d1804da..22bb66b 100755 --- a/src/world/level/pathfinder/Path.h +++ b/src/world/level/pathfinder/Path.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.pathfinder; -#include "Node.h" -#include "../../phys/Vec3.h" -#include "../../entity/Entity.h" +#include "Node.hpp" +#include "world/phys/Vec3.hpp" +#include "world/entity/Entity.hpp" class Path { diff --git a/src/world/level/pathfinder/PathFinder.h b/src/world/level/pathfinder/PathFinder.hpp similarity index 97% rename from src/world/level/pathfinder/PathFinder.h rename to src/world/level/pathfinder/PathFinder.hpp index 85bbb08..48b6e36 100755 --- a/src/world/level/pathfinder/PathFinder.h +++ b/src/world/level/pathfinder/PathFinder.hpp @@ -2,16 +2,16 @@ //package net.minecraft.world.level.pathfinder; -#include "../LevelSource.h" -#include "../material/Material.h" -#include "../tile/DoorTile.h" -#include "../../entity/Entity.h" -#include "../../../util/Mth.h" +#include "world/level/LevelSource.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/tile/DoorTile.hpp" +#include "world/entity/Entity.hpp" +#include "util/Mth.hpp" #include -#include "BinaryHeap.h" -#include "Node.h" -#include "Path.h" +#include "BinaryHeap.hpp" +#include "Node.hpp" +#include "Path.hpp" static int __created; static int __maxCreated = 0; diff --git a/src/world/level/storage/ExternalFileLevelStorage.cpp b/src/world/level/storage/ExternalFileLevelStorage.cpp index 91bcf45..63a94b4 100755 --- a/src/world/level/storage/ExternalFileLevelStorage.cpp +++ b/src/world/level/storage/ExternalFileLevelStorage.cpp @@ -1,634 +1,634 @@ -#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) - -#include "LevelData.h" -#include "RegionFile.h" -#include "ExternalFileLevelStorage.h" -#include "FolderMethods.h" -#include "../chunk/LevelChunk.h" -#include "../Level.h" -#include "../LevelConstants.h" -#include "platform/log.h" -#include "../tile/TreeTile.h" -#include "../../entity/EntityFactory.h" -#include "../../../nbt/NbtIo.h" -#include "../../../util/RakDataIO.h" -#include "../../../raknet/GetTime.h" -#include "../tile/entity/TileEntity.h" - -static const int ChunkVersion_Light = 1; -static const int ChunkVersion_Entity = 2; - -const char* const fnLevelDatOld = "level.dat_old"; -const char* const fnLevelDatNew = "level.dat_new"; -const char* const fnLevelDat = "level.dat"; -const char* const fnPlayerDat = "player.dat"; - -// -// Helpers for converting old levels to newer -// -class LevelConverters -{ -public: - // Replacing old Cloth (id based) with new Cloth (data based) - static bool v1_ClothIdToClothData(LevelChunk* c) { - bool changed = false; - unsigned char* blocks = c->getBlockData(); - unsigned char newTile = Tile::cloth->id; - - for (int i = 0; i < 16*16*128; ++i) { - unsigned char oldTile = blocks[i]; - //Tile::cloth_00 to Tile::cloth_61 - if (oldTile >= 101 && oldTile <= 115) { - int color = 0xf - (oldTile - 101); - blocks[i] = newTile; - c->data.set(i, color); - changed = true; - } - } - return changed; - } - - // Replacing unavailable blocks with "Update!" blocks - static bool ReplaceUnavailableBlocks(LevelChunk* c) { - //int st = getTimeMs(); - - bool changed = false; - unsigned char* blocks = c->getBlockData(); - - for (int i = 0; i < 16*16*128; ++i) { - unsigned char oldTile = blocks[i]; - unsigned char newTile = Tile::transformToValidBlockId(oldTile); - if (oldTile != newTile) { - blocks[i] = newTile; - changed = true; - } - } - - //int et = getTimeMs(); - //LOGI("time: %d\n", et - st); - return changed; - } - - //static bool ConvertPlayerDatToLevelDat() { - // return false; - //} -}; - - -ExternalFileLevelStorage::ExternalFileLevelStorage(const std::string& levelId, const std::string& fullPath) -: levelId(levelId), - levelPath(fullPath), - loadedLevelData(NULL), - regionFile(NULL), - entitiesFile(NULL), - tickCount(0), - lastSavedEntitiesTick(-999999), - level(NULL), - loadedStorageVersion(SharedConstants::StorageVersion) -{ - createFolderIfNotExists(levelPath.c_str()); - - std::string datFileName = levelPath + "/" + fnLevelDat; - std::string levelFileName = levelPath + "/" + fnPlayerDat; - loadedLevelData = new LevelData(); - if (readLevelData(levelPath, *loadedLevelData)) - { - loadedStorageVersion = loadedLevelData->getStorageVersion(); - readPlayerData(levelFileName, *loadedLevelData); - } else { - delete loadedLevelData; - loadedLevelData = NULL; - } -} - -ExternalFileLevelStorage::~ExternalFileLevelStorage() -{ - delete regionFile; - delete loadedLevelData; -} - -void ExternalFileLevelStorage::saveLevelData(LevelData& levelData, std::vector* players) { - ExternalFileLevelStorage::saveLevelData(levelPath, levelData, players); -} - -void ExternalFileLevelStorage::saveLevelData( const std::string& levelPath, LevelData& levelData, std::vector* players ) -{ - std::string directory = levelPath + "/"; - std::string tmpFile = directory + fnLevelDatNew; - std::string datFile = directory + fnLevelDat; - std::string oldFile = directory + fnLevelDatOld; - - levelData.setStorageVersion(SharedConstants::StorageVersion); - if (!writeLevelData(tmpFile, levelData, players)) - return; - - // Remove old backup - remove(oldFile.c_str()); - - // If it exists, move the previous save to backup (and possibly delete it) - if (exists(datFile.c_str())) { - if (rename(datFile.c_str(), oldFile.c_str())) { - LOGE("Error@saveLevelData: Couldn't move savefile to level.dat_old\n"); - return; - } - remove(datFile.c_str()); - } - // Move the new save to level.dat - if (rename(tmpFile.c_str(), datFile.c_str())) { - LOGE("Error@saveLevelData: Couldn't move new file to level.dat\n"); - return; - } - - // Remove the temporary save, if the rename didn't do it - remove(tmpFile.c_str()); -} - -LevelData* ExternalFileLevelStorage::prepareLevel(Level* _level) -{ - level = _level; - return loadedLevelData; -} - -bool ExternalFileLevelStorage::readLevelData(const std::string& directory, LevelData& levelData) -{ - // Try to load level.dat - std::string datFilename = directory + "/" + fnLevelDat; - FILE* file = fopen(datFilename.c_str(), "rb"); - - // If that fails, try to load level.dat_old - if (!file) { - datFilename = directory + "/" + fnLevelDatOld; - file = fopen(datFilename.c_str(), "rb"); - } - - if (!file) - return false; - - int version = 0; - int size = 0; - unsigned char* data = NULL; - - do { - if (fread(&version, sizeof(version), 1, file) != 1) - { - break; - } - if (fread(&size, sizeof(size), 1, file) != 1) - { - break; - } - - int left = getRemainingFileSize(file); - if (size > left || size <= 0) - break; - - data = new unsigned char[size]; - if (fread(data, 1, size, file) != size) - { - break; - } - - if (version == 1) { - RakNet::BitStream bitStream(data, size, false); - levelData.v1_read(bitStream, version); - } else if (version >= 2) { - //LOGI("---> Trying to load level with version %d\n", version); - RakNet::BitStream bitStream(data, size, false); - RakDataInput stream(bitStream); - //LOGI("dat: %s\n", datFileName.c_str()); - CompoundTag* tag = NbtIo::read(&stream); - if (tag) { - levelData.getTagData(tag); - tag->deleteChildren(); - delete tag; - } - //LOGI("<--- Finished reading level tag: %p\n", tag); - } - } while (false); - - fclose(file); - delete [] data; - - return true; -} - -bool ExternalFileLevelStorage::writeLevelData(const std::string& datFileName, LevelData& levelData, const std::vector* players) -{ - LOGI("Writing down level seed as: %ld\n", levelData.getSeed()); - //return true; - - // Write level info - FILE* file = fopen(datFileName.c_str(), "wb"); - if (!file) - return false; - - //if (levelData.getStorageVersion() == 1) { - RakNet::BitStream data; - if (levelData.getStorageVersion() == 1) - levelData.v1_write(data); - else { - RakDataOutput buf(data); - //LOGI("---> Trying to write level with version %d\n", version); - CompoundTag* tag = NULL; - if (players && !players->empty()) - tag = levelData.createTag(*players); - else - tag = levelData.createTag(); - - NbtIo::write(tag, &buf); - tag->deleteChildren(); - delete tag; - //LOGI("<--- Finished writing level data. Size: %d\n", fdout.bytesWritten); - } - - int version = levelData.getStorageVersion(); // 1 - fwrite(&version, sizeof(version), 1, file); - int size = data.GetNumberOfBytesUsed(); - fwrite(&size, sizeof(size), 1, file); - - fwrite(data.GetData(), 1, size, file); - fclose(file); - - return true; -} - -bool ExternalFileLevelStorage::readPlayerData(const std::string& filename, LevelData& dest) -{ - FILE* fp = fopen(filename.c_str(), "rb"); - if (!fp) - return false; - - do { - int version; - if (fread(&version, 4, 1, fp) != 1) - break; - - int size; - if (fread(&size, 4, 1, fp) != 1) - break; - - if (version == 1) { - if (fread(&dest.playerData, 1, sizeof(dest.playerData), fp) != size) - break; - - // Fix coordinates - Vec3& pos = dest.playerData.pos; - if (pos.x < 0.5f) pos.x = 0.5f; - if (pos.z < 0.5f) pos.z = 0.5f; - if (pos.x > (LEVEL_WIDTH - 0.5f)) pos.x = LEVEL_WIDTH - 0.5f; - if (pos.z > (LEVEL_DEPTH - 0.5f)) pos.z = LEVEL_DEPTH - 0.5f; - if (pos.y < 0) pos.y = 64; - - dest.playerDataVersion = version; - } - } while (false); - - fclose(fp); - return true; -} - -void ExternalFileLevelStorage::tick() -{ - tickCount++; - if ((tickCount % 1000) == 0 && level) { - LOGI("Saving level...\n"); - - // look for chunks that needs to be saved - for (int z = 0; z < CHUNK_CACHE_WIDTH; z++) - { - for (int x = 0; x < CHUNK_CACHE_WIDTH; x++) - { - LevelChunk* chunk = level->getChunk(x, z); - if (chunk && chunk->unsaved) - { - int pos = x + z * CHUNK_CACHE_WIDTH; - UnsavedChunkList::iterator prev = unsavedChunkList.begin(); - for ( ; prev != unsavedChunkList.end(); ++prev) - { - if ((*prev).pos == pos) - { - // the chunk has been modified again, so update its time - (*prev).addedToList = RakNet::GetTimeMS(); - break; - } - } - if (prev == unsavedChunkList.end()) - { - UnsavedLevelChunk unsaved; - unsaved.pos = pos; - unsaved.addedToList = RakNet::GetTimeMS(); - unsaved.chunk = chunk; - unsavedChunkList.push_back(unsaved); - } - chunk->unsaved = false; // not actually saved, but in our working list at least - } - } - } - - savePendingUnsavedChunks(2); - } - if (tickCount - lastSavedEntitiesTick > (60 * SharedConstants::TicksPerSecond)) { - saveEntities(level, NULL); - } -} - -void ExternalFileLevelStorage::save(Level* level, LevelChunk* levelChunk) -{ - if (!regionFile) - { - regionFile = new RegionFile(levelPath); - if (!regionFile->open()) - { - delete regionFile; - regionFile = NULL; - return; - } - } - - // Write chunk - RakNet::BitStream chunkData; - chunkData.Write((const char*)levelChunk->getBlockData(), CHUNK_BLOCK_COUNT); - chunkData.Write((const char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2); - - chunkData.Write((const char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2); - chunkData.Write((const char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2); - - chunkData.Write((const char*)levelChunk->updateMap, CHUNK_COLUMNS); - - regionFile->writeChunk(levelChunk->x, levelChunk->z, chunkData); - - // Write entities - - //LOGI("Saved chunk (%d, %d)\n", levelChunk->x, levelChunk->z); - -} - -LevelChunk* ExternalFileLevelStorage::load(Level* level, int x, int z) -{ - if (!regionFile) - { - regionFile = new RegionFile(levelPath); - if (!regionFile->open()) - { - delete regionFile; - regionFile = NULL; - return NULL; - } - } - - RakNet::BitStream* chunkData = NULL; - if (!regionFile->readChunk(x, z, &chunkData)) - { - //LOGI("Failed to read data for %d, %d\n", x, z); - return NULL; - } - - chunkData->ResetReadPointer(); - - unsigned char* blockIds = new unsigned char[CHUNK_BLOCK_COUNT]; - chunkData->Read((char*)blockIds, CHUNK_BLOCK_COUNT); - - LevelChunk* levelChunk = new LevelChunk(level, blockIds, x, z); - chunkData->Read((char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2); - if (loadedStorageVersion >= ChunkVersion_Light) { - chunkData->Read((char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2); - chunkData->Read((char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2); - } - chunkData->Read((char*)levelChunk->updateMap, CHUNK_COLUMNS); - // This will be difficult to maintain.. Storage version could be per chunk - // too (but probably better to just read all -> write all, so that all - // chunks got same version anyway) - //if (loadedStorageVersion >= ChunkVersion_Entity) { - // int dictSize; - // chunkData->Read(dictSize); - - // RakDataInput dis(*chunkData); - // Tag* tmp = Tag::readNamedTag(&dis); - // if (tmp && tmp->getId() == Tag::TAG_Compound) { - // CompoundTag* tag = (CompoundTag*) tmp; - - // delete tmp; - // } - //} - - delete [] chunkData->GetData(); - delete chunkData; - - //bool dbg = (x == 7 && z == 9); - - //int t = 0; - //for (int i = 0; i < CHUNK_COLUMNS; ++i) { - // char bits = levelChunk->updateMap[i]; - // t += (bits != 0); - // int xx = x * 16 + i%16; - // int zz = z * 16 + i/16; - // if (dbg && xx == 125 && zz == 152) { - // LOGI("xz: %d, %d: %d\n", xx, zz, bits); - // for (int j = 0; j < 8; ++j) { - // if (bits & (1 << j)) { - // LOGI("%d - %d\n", j << 4, ((j+1) << 4) - 1); - // } - // } - // } - //} - - // - // Convert LevelChunks here if necessary - // - //LOGI("level version: %d: upd: %d - (%d, %d)\n", loadedStorageVersion, t, x, z); - bool changed = false; - - // Loaded level has old Cloth types (one Tile* per color) - if (loadedStorageVersion == 1) - changed |= LevelConverters::v1_ClothIdToClothData(levelChunk); - - // Loaded level is newer than our level - replace all unavailable block types - //if (loadedStorageVersion > SharedConstants::StorageVersion) - changed |= LevelConverters::ReplaceUnavailableBlocks(levelChunk); - - levelChunk->recalcHeightmap(); - levelChunk->unsaved = changed; - levelChunk->terrainPopulated = true; - levelChunk->createdFromSave = true; - - return levelChunk; -} - -void ExternalFileLevelStorage::saveEntities( Level* level, LevelChunk* levelChunk ) -{ - lastSavedEntitiesTick = tickCount; - int count = 0; - float st = getTimeS(); - - // Version 1: Save ALL Entities for all chunks in one structure - EntityList& entities = level->entities; - - ListTag* entityTags = new ListTag(); - for (unsigned int i = 0; i < entities.size(); ++i) { - Entity* e = entities[i]; - - CompoundTag* tag = new CompoundTag(); - if (e->save(tag)) { - count++; - entityTags->add(tag); - } else - delete tag; - } - - // Version 1: Save ALL TileEntities for all chunks in one structure - TileEntityList& tileEntities = level->tileEntities; - //TileEntityList keep, dontKeep; - //partitionTileEntities - - ListTag* tileEntityTags = new ListTag(); - for (unsigned int i = 0; i < tileEntities.size(); ++i) { - TileEntity* e = tileEntities[i]; - if (!e->shouldSave()) continue; - - CompoundTag* tag = new CompoundTag(); - if (e->save(tag)) { - count++; - tileEntityTags->add(tag); - } else - delete tag; - } - - CompoundTag base; - base.put("Entities", entityTags); - base.put("TileEntities", tileEntityTags); - - RakNet::BitStream stream; - RakDataOutput dos(stream); - NbtIo::write(&base, &dos); - int numBytes = stream.GetNumberOfBytesUsed(); - - FILE* fp = fopen((levelPath + "/entities.dat").c_str(), "wb"); - if (fp) { - int version = 1; - fwrite("ENT\0", 1, 4, fp); - fwrite(&version, sizeof(int), 1, fp); - fwrite(&numBytes, sizeof(int), 1, fp); - fwrite(stream.GetData(), 1, numBytes, fp); - fclose(fp); - } - - base.deleteChildren(); - - float tt = getTimeS() - st; - LOGI("Time to save %d entities: %f s. Size: %d bytes\n", count, tt, numBytes); -} - -void ExternalFileLevelStorage::loadEntities(Level* level, LevelChunk* chunk) { - lastSavedEntitiesTick = tickCount; - FILE* fp = fopen((levelPath + "/entities.dat").c_str(), "rb"); - if (fp) { - char header[5]; - int version, numBytes; - fread(header, 1, 4, fp); - fread(&version, sizeof(int), 1, fp); - fread(&numBytes, sizeof(int), 1, fp); - - int left = getRemainingFileSize(fp); - if (numBytes <= left && numBytes > 0) { - unsigned char* buf = new unsigned char[numBytes]; - - fread(buf, 1, numBytes, fp); - - RakNet::BitStream stream(buf, numBytes, false); - RakDataInput dis(stream); - - CompoundTag* tag = NbtIo::read(&dis); - // - // Read Entity:es - // - if (tag->contains("Entities", Tag::TAG_List)) { - ListTag* entityTags = tag->getList("Entities"); - for (int i = 0; i < entityTags->size(); ++i) { - Tag* _et = entityTags->get(i); - if (!_et || _et->getId() != Tag::TAG_Compound) { - LOGE("Entity tag is either NULL or not a compoundTag: %p : %d!\n", _et, _et?_et->getId() : -1); - continue; - } - CompoundTag* et = (CompoundTag*)_et; - if (Entity* e = EntityFactory::loadEntity(et, level)) { - level->addEntity(e); - } - } - } - // - // Read TileEntity:s - // - if (tag->contains("TileEntities", Tag::TAG_List)) { - ListTag* tileEntityTags = tag->getList("TileEntities"); - for (int i = 0; i < tileEntityTags->size(); ++i) { - Tag* _et = tileEntityTags->get(i); - if (!_et || _et->getId() != Tag::TAG_Compound) { - LOGE("TileEntity tag is either NULL or not a compoundTag: %p : %d!\n", _et, _et?_et->getId() : -1); - continue; - } - CompoundTag* et = (CompoundTag*)_et; - if (TileEntity* e = TileEntity::loadStatic(et)) { - - LevelChunk* chunk = level->getChunkAt(e->x, e->z); - if (chunk && !chunk->hasTileEntityAt(e)) { - LOGI("Adding TileEntity %d to %d, %d, %d\n", e->type, e->x, e->y, e->z); - chunk->addTileEntity(e); - } else { - if (!chunk) - LOGE("Couldn't find chunk at %d, %d to add %d\n", e->x, e->z, e->type); - else - LOGE("Already have TileEntity at %d, %d to add %d\n", e->x, e->z, e->type); - delete e; - } - } - } - } - - tag->deleteChildren(); - delete tag; - - delete[] buf; - } - LOGI("header: %s, version: %d, bytes: %d (remaining: %d)\n", header, version, numBytes, left); - - //fread(stream.GetData(), 1, numBytes, fp); - fclose(fp); - } -} - -void ExternalFileLevelStorage::saveGame(Level* level) { - saveEntities(level, NULL); -} - -int ExternalFileLevelStorage::savePendingUnsavedChunks( int maxCount ) { - if (maxCount < 0) - maxCount = unsavedChunkList.size(); - - int count = 0; - while (++count <= maxCount && !unsavedChunkList.empty()) { - - UnsavedChunkList::iterator it = unsavedChunkList.begin(); - UnsavedChunkList::iterator remove = unsavedChunkList.begin(); - UnsavedLevelChunk* oldest = &(*it); - - for ( ; it != unsavedChunkList.end(); ++it) { - if ((*it).addedToList < oldest->addedToList) { - oldest = &(*it); - remove = it; - } - } - LevelChunk* chunk = oldest->chunk; - unsavedChunkList.erase(remove); - - save(level, chunk); - } - return count; -} - -void ExternalFileLevelStorage::saveAll( Level* level, std::vector& levelChunks ) { - ChunkStorage::saveAll(level, levelChunks); - int numChunks = savePendingUnsavedChunks(-1); - LOGI("Saving %d additional chunks.\n", numChunks); -} - -#endif /*DEMO_MODE*/ +#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) + +#include "LevelData.hpp" +#include "RegionFile.hpp" +#include "ExternalFileLevelStorage.hpp" +#include "FolderMethods.hpp" +#include "world/level/chunk/LevelChunk.hpp" +#include "world/level/Level.hpp" +#include "world/level/LevelConstants.hpp" +#include "platform/log.hpp" +#include "world/level/tile/TreeTile.hpp" +#include "world/entity/EntityFactory.hpp" +#include "nbt/NbtIo.hpp" +#include "util/RakDataIO.hpp" +#include "raknet/GetTime.h" +#include "world/level/tile/entity/TileEntity.hpp" + +static const int ChunkVersion_Light = 1; +static const int ChunkVersion_Entity = 2; + +const char* const fnLevelDatOld = "level.dat_old"; +const char* const fnLevelDatNew = "level.dat_new"; +const char* const fnLevelDat = "level.dat"; +const char* const fnPlayerDat = "player.dat"; + +// +// Helpers for converting old levels to newer +// +class LevelConverters +{ +public: + // Replacing old Cloth (id based) with new Cloth (data based) + static bool v1_ClothIdToClothData(LevelChunk* c) { + bool changed = false; + unsigned char* blocks = c->getBlockData(); + unsigned char newTile = Tile::cloth->id; + + for (int i = 0; i < 16*16*128; ++i) { + unsigned char oldTile = blocks[i]; + //Tile::cloth_00 to Tile::cloth_61 + if (oldTile >= 101 && oldTile <= 115) { + int color = 0xf - (oldTile - 101); + blocks[i] = newTile; + c->data.set(i, color); + changed = true; + } + } + return changed; + } + + // Replacing unavailable blocks with "Update!" blocks + static bool ReplaceUnavailableBlocks(LevelChunk* c) { + //int st = getTimeMs(); + + bool changed = false; + unsigned char* blocks = c->getBlockData(); + + for (int i = 0; i < 16*16*128; ++i) { + unsigned char oldTile = blocks[i]; + unsigned char newTile = Tile::transformToValidBlockId(oldTile); + if (oldTile != newTile) { + blocks[i] = newTile; + changed = true; + } + } + + //int et = getTimeMs(); + //LOGI("time: %d\n", et - st); + return changed; + } + + //static bool ConvertPlayerDatToLevelDat() { + // return false; + //} +}; + + +ExternalFileLevelStorage::ExternalFileLevelStorage(const std::string& levelId, const std::string& fullPath) +: levelId(levelId), + levelPath(fullPath), + loadedLevelData(NULL), + regionFile(NULL), + entitiesFile(NULL), + tickCount(0), + lastSavedEntitiesTick(-999999), + level(NULL), + loadedStorageVersion(SharedConstants::StorageVersion) +{ + createFolderIfNotExists(levelPath.c_str()); + + std::string datFileName = levelPath + "/" + fnLevelDat; + std::string levelFileName = levelPath + "/" + fnPlayerDat; + loadedLevelData = new LevelData(); + if (readLevelData(levelPath, *loadedLevelData)) + { + loadedStorageVersion = loadedLevelData->getStorageVersion(); + readPlayerData(levelFileName, *loadedLevelData); + } else { + delete loadedLevelData; + loadedLevelData = NULL; + } +} + +ExternalFileLevelStorage::~ExternalFileLevelStorage() +{ + delete regionFile; + delete loadedLevelData; +} + +void ExternalFileLevelStorage::saveLevelData(LevelData& levelData, std::vector* players) { + ExternalFileLevelStorage::saveLevelData(levelPath, levelData, players); +} + +void ExternalFileLevelStorage::saveLevelData( const std::string& levelPath, LevelData& levelData, std::vector* players ) +{ + std::string directory = levelPath + "/"; + std::string tmpFile = directory + fnLevelDatNew; + std::string datFile = directory + fnLevelDat; + std::string oldFile = directory + fnLevelDatOld; + + levelData.setStorageVersion(SharedConstants::StorageVersion); + if (!writeLevelData(tmpFile, levelData, players)) + return; + + // Remove old backup + remove(oldFile.c_str()); + + // If it exists, move the previous save to backup (and possibly delete it) + if (exists(datFile.c_str())) { + if (rename(datFile.c_str(), oldFile.c_str())) { + LOGE("Error@saveLevelData: Couldn't move savefile to level.dat_old\n"); + return; + } + remove(datFile.c_str()); + } + // Move the new save to level.dat + if (rename(tmpFile.c_str(), datFile.c_str())) { + LOGE("Error@saveLevelData: Couldn't move new file to level.dat\n"); + return; + } + + // Remove the temporary save, if the rename didn't do it + remove(tmpFile.c_str()); +} + +LevelData* ExternalFileLevelStorage::prepareLevel(Level* _level) +{ + level = _level; + return loadedLevelData; +} + +bool ExternalFileLevelStorage::readLevelData(const std::string& directory, LevelData& levelData) +{ + // Try to load level.dat + std::string datFilename = directory + "/" + fnLevelDat; + FILE* file = fopen(datFilename.c_str(), "rb"); + + // If that fails, try to load level.dat_old + if (!file) { + datFilename = directory + "/" + fnLevelDatOld; + file = fopen(datFilename.c_str(), "rb"); + } + + if (!file) + return false; + + int version = 0; + int size = 0; + unsigned char* data = NULL; + + do { + if (fread(&version, sizeof(version), 1, file) != 1) + { + break; + } + if (fread(&size, sizeof(size), 1, file) != 1) + { + break; + } + + int left = getRemainingFileSize(file); + if (size > left || size <= 0) + break; + + data = new unsigned char[size]; + if (fread(data, 1, size, file) != size) + { + break; + } + + if (version == 1) { + RakNet::BitStream bitStream(data, size, false); + levelData.v1_read(bitStream, version); + } else if (version >= 2) { + //LOGI("---> Trying to load level with version %d\n", version); + RakNet::BitStream bitStream(data, size, false); + RakDataInput stream(bitStream); + //LOGI("dat: %s\n", datFileName.c_str()); + CompoundTag* tag = NbtIo::read(&stream); + if (tag) { + levelData.getTagData(tag); + tag->deleteChildren(); + delete tag; + } + //LOGI("<--- Finished reading level tag: %p\n", tag); + } + } while (false); + + fclose(file); + delete [] data; + + return true; +} + +bool ExternalFileLevelStorage::writeLevelData(const std::string& datFileName, LevelData& levelData, const std::vector* players) +{ + LOGI("Writing down level seed as: %ld\n", levelData.getSeed()); + //return true; + + // Write level info + FILE* file = fopen(datFileName.c_str(), "wb"); + if (!file) + return false; + + //if (levelData.getStorageVersion() == 1) { + RakNet::BitStream data; + if (levelData.getStorageVersion() == 1) + levelData.v1_write(data); + else { + RakDataOutput buf(data); + //LOGI("---> Trying to write level with version %d\n", version); + CompoundTag* tag = NULL; + if (players && !players->empty()) + tag = levelData.createTag(*players); + else + tag = levelData.createTag(); + + NbtIo::write(tag, &buf); + tag->deleteChildren(); + delete tag; + //LOGI("<--- Finished writing level data. Size: %d\n", fdout.bytesWritten); + } + + int version = levelData.getStorageVersion(); // 1 + fwrite(&version, sizeof(version), 1, file); + int size = data.GetNumberOfBytesUsed(); + fwrite(&size, sizeof(size), 1, file); + + fwrite(data.GetData(), 1, size, file); + fclose(file); + + return true; +} + +bool ExternalFileLevelStorage::readPlayerData(const std::string& filename, LevelData& dest) +{ + FILE* fp = fopen(filename.c_str(), "rb"); + if (!fp) + return false; + + do { + int version; + if (fread(&version, 4, 1, fp) != 1) + break; + + int size; + if (fread(&size, 4, 1, fp) != 1) + break; + + if (version == 1) { + if (fread(&dest.playerData, 1, sizeof(dest.playerData), fp) != size) + break; + + // Fix coordinates + Vec3& pos = dest.playerData.pos; + if (pos.x < 0.5f) pos.x = 0.5f; + if (pos.z < 0.5f) pos.z = 0.5f; + if (pos.x > (LEVEL_WIDTH - 0.5f)) pos.x = LEVEL_WIDTH - 0.5f; + if (pos.z > (LEVEL_DEPTH - 0.5f)) pos.z = LEVEL_DEPTH - 0.5f; + if (pos.y < 0) pos.y = 64; + + dest.playerDataVersion = version; + } + } while (false); + + fclose(fp); + return true; +} + +void ExternalFileLevelStorage::tick() +{ + tickCount++; + if ((tickCount % 1000) == 0 && level) { + LOGI("Saving level...\n"); + + // look for chunks that needs to be saved + for (int z = 0; z < CHUNK_CACHE_WIDTH; z++) + { + for (int x = 0; x < CHUNK_CACHE_WIDTH; x++) + { + LevelChunk* chunk = level->getChunk(x, z); + if (chunk && chunk->unsaved) + { + int pos = x + z * CHUNK_CACHE_WIDTH; + UnsavedChunkList::iterator prev = unsavedChunkList.begin(); + for ( ; prev != unsavedChunkList.end(); ++prev) + { + if ((*prev).pos == pos) + { + // the chunk has been modified again, so update its time + (*prev).addedToList = RakNet::GetTimeMS(); + break; + } + } + if (prev == unsavedChunkList.end()) + { + UnsavedLevelChunk unsaved; + unsaved.pos = pos; + unsaved.addedToList = RakNet::GetTimeMS(); + unsaved.chunk = chunk; + unsavedChunkList.push_back(unsaved); + } + chunk->unsaved = false; // not actually saved, but in our working list at least + } + } + } + + savePendingUnsavedChunks(2); + } + if (tickCount - lastSavedEntitiesTick > (60 * SharedConstants::TicksPerSecond)) { + saveEntities(level, NULL); + } +} + +void ExternalFileLevelStorage::save(Level* level, LevelChunk* levelChunk) +{ + if (!regionFile) + { + regionFile = new RegionFile(levelPath); + if (!regionFile->open()) + { + delete regionFile; + regionFile = NULL; + return; + } + } + + // Write chunk + RakNet::BitStream chunkData; + chunkData.Write((const char*)levelChunk->getBlockData(), CHUNK_BLOCK_COUNT); + chunkData.Write((const char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2); + + chunkData.Write((const char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2); + chunkData.Write((const char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2); + + chunkData.Write((const char*)levelChunk->updateMap, CHUNK_COLUMNS); + + regionFile->writeChunk(levelChunk->x, levelChunk->z, chunkData); + + // Write entities + + //LOGI("Saved chunk (%d, %d)\n", levelChunk->x, levelChunk->z); + +} + +LevelChunk* ExternalFileLevelStorage::load(Level* level, int x, int z) +{ + if (!regionFile) + { + regionFile = new RegionFile(levelPath); + if (!regionFile->open()) + { + delete regionFile; + regionFile = NULL; + return NULL; + } + } + + RakNet::BitStream* chunkData = NULL; + if (!regionFile->readChunk(x, z, &chunkData)) + { + //LOGI("Failed to read data for %d, %d\n", x, z); + return NULL; + } + + chunkData->ResetReadPointer(); + + unsigned char* blockIds = new unsigned char[CHUNK_BLOCK_COUNT]; + chunkData->Read((char*)blockIds, CHUNK_BLOCK_COUNT); + + LevelChunk* levelChunk = new LevelChunk(level, blockIds, x, z); + chunkData->Read((char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2); + if (loadedStorageVersion >= ChunkVersion_Light) { + chunkData->Read((char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2); + chunkData->Read((char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2); + } + chunkData->Read((char*)levelChunk->updateMap, CHUNK_COLUMNS); + // This will be difficult to maintain.. Storage version could be per chunk + // too (but probably better to just read all -> write all, so that all + // chunks got same version anyway) + //if (loadedStorageVersion >= ChunkVersion_Entity) { + // int dictSize; + // chunkData->Read(dictSize); + + // RakDataInput dis(*chunkData); + // Tag* tmp = Tag::readNamedTag(&dis); + // if (tmp && tmp->getId() == Tag::TAG_Compound) { + // CompoundTag* tag = (CompoundTag*) tmp; + + // delete tmp; + // } + //} + + delete [] chunkData->GetData(); + delete chunkData; + + //bool dbg = (x == 7 && z == 9); + + //int t = 0; + //for (int i = 0; i < CHUNK_COLUMNS; ++i) { + // char bits = levelChunk->updateMap[i]; + // t += (bits != 0); + // int xx = x * 16 + i%16; + // int zz = z * 16 + i/16; + // if (dbg && xx == 125 && zz == 152) { + // LOGI("xz: %d, %d: %d\n", xx, zz, bits); + // for (int j = 0; j < 8; ++j) { + // if (bits & (1 << j)) { + // LOGI("%d - %d\n", j << 4, ((j+1) << 4) - 1); + // } + // } + // } + //} + + // + // Convert LevelChunks here if necessary + // + //LOGI("level version: %d: upd: %d - (%d, %d)\n", loadedStorageVersion, t, x, z); + bool changed = false; + + // Loaded level has old Cloth types (one Tile* per color) + if (loadedStorageVersion == 1) + changed |= LevelConverters::v1_ClothIdToClothData(levelChunk); + + // Loaded level is newer than our level - replace all unavailable block types + //if (loadedStorageVersion > SharedConstants::StorageVersion) + changed |= LevelConverters::ReplaceUnavailableBlocks(levelChunk); + + levelChunk->recalcHeightmap(); + levelChunk->unsaved = changed; + levelChunk->terrainPopulated = true; + levelChunk->createdFromSave = true; + + return levelChunk; +} + +void ExternalFileLevelStorage::saveEntities( Level* level, LevelChunk* levelChunk ) +{ + lastSavedEntitiesTick = tickCount; + int count = 0; + float st = getTimeS(); + + // Version 1: Save ALL Entities for all chunks in one structure + EntityList& entities = level->entities; + + ListTag* entityTags = new ListTag(); + for (unsigned int i = 0; i < entities.size(); ++i) { + Entity* e = entities[i]; + + CompoundTag* tag = new CompoundTag(); + if (e->save(tag)) { + count++; + entityTags->add(tag); + } else + delete tag; + } + + // Version 1: Save ALL TileEntities for all chunks in one structure + TileEntityList& tileEntities = level->tileEntities; + //TileEntityList keep, dontKeep; + //partitionTileEntities + + ListTag* tileEntityTags = new ListTag(); + for (unsigned int i = 0; i < tileEntities.size(); ++i) { + TileEntity* e = tileEntities[i]; + if (!e->shouldSave()) continue; + + CompoundTag* tag = new CompoundTag(); + if (e->save(tag)) { + count++; + tileEntityTags->add(tag); + } else + delete tag; + } + + CompoundTag base; + base.put("Entities", entityTags); + base.put("TileEntities", tileEntityTags); + + RakNet::BitStream stream; + RakDataOutput dos(stream); + NbtIo::write(&base, &dos); + int numBytes = stream.GetNumberOfBytesUsed(); + + FILE* fp = fopen((levelPath + "/entities.dat").c_str(), "wb"); + if (fp) { + int version = 1; + fwrite("ENT\0", 1, 4, fp); + fwrite(&version, sizeof(int), 1, fp); + fwrite(&numBytes, sizeof(int), 1, fp); + fwrite(stream.GetData(), 1, numBytes, fp); + fclose(fp); + } + + base.deleteChildren(); + + float tt = getTimeS() - st; + LOGI("Time to save %d entities: %f s. Size: %d bytes\n", count, tt, numBytes); +} + +void ExternalFileLevelStorage::loadEntities(Level* level, LevelChunk* chunk) { + lastSavedEntitiesTick = tickCount; + FILE* fp = fopen((levelPath + "/entities.dat").c_str(), "rb"); + if (fp) { + char header[5]; + int version, numBytes; + fread(header, 1, 4, fp); + fread(&version, sizeof(int), 1, fp); + fread(&numBytes, sizeof(int), 1, fp); + + int left = getRemainingFileSize(fp); + if (numBytes <= left && numBytes > 0) { + unsigned char* buf = new unsigned char[numBytes]; + + fread(buf, 1, numBytes, fp); + + RakNet::BitStream stream(buf, numBytes, false); + RakDataInput dis(stream); + + CompoundTag* tag = NbtIo::read(&dis); + // + // Read Entity:es + // + if (tag->contains("Entities", Tag::TAG_List)) { + ListTag* entityTags = tag->getList("Entities"); + for (int i = 0; i < entityTags->size(); ++i) { + Tag* _et = entityTags->get(i); + if (!_et || _et->getId() != Tag::TAG_Compound) { + LOGE("Entity tag is either NULL or not a compoundTag: %p : %d!\n", _et, _et?_et->getId() : -1); + continue; + } + CompoundTag* et = (CompoundTag*)_et; + if (Entity* e = EntityFactory::loadEntity(et, level)) { + level->addEntity(e); + } + } + } + // + // Read TileEntity:s + // + if (tag->contains("TileEntities", Tag::TAG_List)) { + ListTag* tileEntityTags = tag->getList("TileEntities"); + for (int i = 0; i < tileEntityTags->size(); ++i) { + Tag* _et = tileEntityTags->get(i); + if (!_et || _et->getId() != Tag::TAG_Compound) { + LOGE("TileEntity tag is either NULL or not a compoundTag: %p : %d!\n", _et, _et?_et->getId() : -1); + continue; + } + CompoundTag* et = (CompoundTag*)_et; + if (TileEntity* e = TileEntity::loadStatic(et)) { + + LevelChunk* chunk = level->getChunkAt(e->x, e->z); + if (chunk && !chunk->hasTileEntityAt(e)) { + LOGI("Adding TileEntity %d to %d, %d, %d\n", e->type, e->x, e->y, e->z); + chunk->addTileEntity(e); + } else { + if (!chunk) + LOGE("Couldn't find chunk at %d, %d to add %d\n", e->x, e->z, e->type); + else + LOGE("Already have TileEntity at %d, %d to add %d\n", e->x, e->z, e->type); + delete e; + } + } + } + } + + tag->deleteChildren(); + delete tag; + + delete[] buf; + } + LOGI("header: %s, version: %d, bytes: %d (remaining: %d)\n", header, version, numBytes, left); + + //fread(stream.GetData(), 1, numBytes, fp); + fclose(fp); + } +} + +void ExternalFileLevelStorage::saveGame(Level* level) { + saveEntities(level, NULL); +} + +int ExternalFileLevelStorage::savePendingUnsavedChunks( int maxCount ) { + if (maxCount < 0) + maxCount = unsavedChunkList.size(); + + int count = 0; + while (++count <= maxCount && !unsavedChunkList.empty()) { + + UnsavedChunkList::iterator it = unsavedChunkList.begin(); + UnsavedChunkList::iterator remove = unsavedChunkList.begin(); + UnsavedLevelChunk* oldest = &(*it); + + for ( ; it != unsavedChunkList.end(); ++it) { + if ((*it).addedToList < oldest->addedToList) { + oldest = &(*it); + remove = it; + } + } + LevelChunk* chunk = oldest->chunk; + unsavedChunkList.erase(remove); + + save(level, chunk); + } + return count; +} + +void ExternalFileLevelStorage::saveAll( Level* level, std::vector& levelChunks ) { + ChunkStorage::saveAll(level, levelChunks); + int numChunks = savePendingUnsavedChunks(-1); + LOGI("Saving %d additional chunks.\n", numChunks); +} + +#endif /*DEMO_MODE*/ diff --git a/src/world/level/storage/ExternalFileLevelStorage.h b/src/world/level/storage/ExternalFileLevelStorage.hpp similarity index 92% rename from src/world/level/storage/ExternalFileLevelStorage.h rename to src/world/level/storage/ExternalFileLevelStorage.hpp index b7dd960..6c056dd 100755 --- a/src/world/level/storage/ExternalFileLevelStorage.h +++ b/src/world/level/storage/ExternalFileLevelStorage.hpp @@ -1,88 +1,88 @@ -#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) - -#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__ -#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__ - -//package net.minecraft.world.level.storage; - -#include -#include - -//#include "com/mojang/nbt/CompoundTag.h" -#include "LevelStorage.h" -#include "../chunk/storage/ChunkStorage.h" - -class Player; -class Dimension; -class RegionFile; - - -typedef struct UnsavedLevelChunk -{ - int pos; - RakNet::TimeMS addedToList; - LevelChunk* chunk; -} UnsavedLevelChunk; - -typedef std::list UnsavedChunkList; - -/*public*/ -class ExternalFileLevelStorage: - public LevelStorage, - public ChunkStorage - //public PlayerIO -{ -public: - ExternalFileLevelStorage(const std::string& levelId, const std::string& fullPath); - virtual ~ExternalFileLevelStorage(); - - LevelData* prepareLevel(Level* level); - - //throws LevelConflictException - void checkSession() {} - - ChunkStorage* createChunkStorage(Dimension* dimension) { return this; } - - void saveLevelData(LevelData& levelData, std::vector* players); - // PlayerIO getPlayerIO() { return this; } - // CompoundTag loadPlayerDataTag(std::string playerName) { return NULL; } - - void closeAll() {} - - static bool readLevelData(const std::string& directory, LevelData& dest); - static bool readPlayerData(const std::string& filename, LevelData& dest); - static bool writeLevelData(const std::string& datFileName, LevelData& dest, const std::vector* players); - static void saveLevelData(const std::string& directory, LevelData& levelData, std::vector* players); - - int savePendingUnsavedChunks(int maxCount); - - // - // ChunkStorage methods - // - virtual LevelChunk* load(Level* level, int x, int z); - void save(Level* level, LevelChunk* levelChunk); - // @note, loadEntities and saveEntities dont use second parameter - void loadEntities(Level* level, LevelChunk* levelChunk); - void saveEntities(Level* level, LevelChunk* levelChunk); - void saveGame(Level* level); - void saveAll(Level* level, std::vector& levelChunks); - - virtual void tick(); - virtual void flush() {} -private: - std::string levelId; - std::string levelPath; - LevelData* loadedLevelData; - RegionFile* regionFile; - RegionFile* entitiesFile; - - Level* level; - int tickCount; - int loadedStorageVersion; - UnsavedChunkList unsavedChunkList; - int lastSavedEntitiesTick; -}; - -#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__*/ - -#endif /*DEMO_MODE*/ +#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) + +#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__ +#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__ + +//package net.minecraft.world.level.storage; + +#include +#include + +//#include "com/mojang/nbt/CompoundTag.hpp" +#include "LevelStorage.hpp" +#include "world/level/chunk/storage/ChunkStorage.hpp" + +class Player; +class Dimension; +class RegionFile; + + +typedef struct UnsavedLevelChunk +{ + int pos; + RakNet::TimeMS addedToList; + LevelChunk* chunk; +} UnsavedLevelChunk; + +typedef std::list UnsavedChunkList; + +/*public*/ +class ExternalFileLevelStorage: + public LevelStorage, + public ChunkStorage + //public PlayerIO +{ +public: + ExternalFileLevelStorage(const std::string& levelId, const std::string& fullPath); + virtual ~ExternalFileLevelStorage(); + + LevelData* prepareLevel(Level* level); + + //throws LevelConflictException + void checkSession() {} + + ChunkStorage* createChunkStorage(Dimension* dimension) { return this; } + + void saveLevelData(LevelData& levelData, std::vector* players); + // PlayerIO getPlayerIO() { return this; } + // CompoundTag loadPlayerDataTag(std::string playerName) { return NULL; } + + void closeAll() {} + + static bool readLevelData(const std::string& directory, LevelData& dest); + static bool readPlayerData(const std::string& filename, LevelData& dest); + static bool writeLevelData(const std::string& datFileName, LevelData& dest, const std::vector* players); + static void saveLevelData(const std::string& directory, LevelData& levelData, std::vector* players); + + int savePendingUnsavedChunks(int maxCount); + + // + // ChunkStorage methods + // + virtual LevelChunk* load(Level* level, int x, int z); + void save(Level* level, LevelChunk* levelChunk); + // @note, loadEntities and saveEntities dont use second parameter + void loadEntities(Level* level, LevelChunk* levelChunk); + void saveEntities(Level* level, LevelChunk* levelChunk); + void saveGame(Level* level); + void saveAll(Level* level, std::vector& levelChunks); + + virtual void tick(); + virtual void flush() {} +private: + std::string levelId; + std::string levelPath; + LevelData* loadedLevelData; + RegionFile* regionFile; + RegionFile* entitiesFile; + + Level* level; + int tickCount; + int loadedStorageVersion; + UnsavedChunkList unsavedChunkList; + int lastSavedEntitiesTick; +}; + +#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorage_H__*/ + +#endif /*DEMO_MODE*/ diff --git a/src/world/level/storage/ExternalFileLevelStorageSource.cpp b/src/world/level/storage/ExternalFileLevelStorageSource.cpp index b09b48f..dd5a32e 100755 --- a/src/world/level/storage/ExternalFileLevelStorageSource.cpp +++ b/src/world/level/storage/ExternalFileLevelStorageSource.cpp @@ -1,193 +1,193 @@ -#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) - -#include "LevelData.h" -#include "ExternalFileLevelStorageSource.h" -#include "ExternalFileLevelStorage.h" -#include "FolderMethods.h" -#include "../../../platform/file.h" -#include "../../../util/StringUtils.h" -#include -#include - -#ifdef __APPLE__ -#include "MoveFolder.h" -#endif - -static const char ILLEGAL_FILE_CHARACTERS[] = { - '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' -}; - -ExternalFileLevelStorageSource::ExternalFileLevelStorageSource(const std::string& externalPath, const std::string& temporaryFilesPath) -: _hasTempDirectory(temporaryFilesPath != externalPath) -{ -#ifndef STANDALONE_SERVER - const char* p0 = "/games"; - const char* p1 = "/com.mojang"; - const char* p2 = "/minecraftWorlds"; - const char* tree[] = { - p0, p1, p2 - }; - - int treeLength = sizeof(tree) / sizeof(tree[0]); - - createTree(externalPath.c_str(), tree, treeLength); - - if (hasTempDirectory()) - createTree(temporaryFilesPath.c_str(), tree, treeLength); - - basePath = externalPath + p0 + p1 + p2; - tmpBasePath = temporaryFilesPath + p0 + p1 + p2; -#else - basePath = externalPath; - tmpBasePath = temporaryFilesPath; -#endif -} - -void ExternalFileLevelStorageSource::addLevelSummaryIfExists(LevelSummaryList& dest, const char* dirName) -{ - std::string directory = basePath; - directory += "/"; - directory += dirName; - - LevelData levelData; - - if (ExternalFileLevelStorage::readLevelData(directory, levelData)) - { - LevelSummary summary; - summary.id = dirName; - summary.name = levelData.levelName; - summary.lastPlayed = levelData.getLastPlayed(); - summary.sizeOnDisk = (unsigned int)levelData.getSizeOnDisk(); - summary.gameType = levelData.getGameType(); - - dest.push_back(summary); - } -} - -void ExternalFileLevelStorageSource::getLevelList(LevelSummaryList& dest) -{ -#ifdef WIN32 - - WIN32_FIND_DATAA fileData; - HANDLE hFind; - - std::string searchString = basePath; - searchString += "/*"; - - hFind = FindFirstFileA(searchString.c_str(), &fileData); - if (hFind != INVALID_HANDLE_VALUE) { - do { - if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - addLevelSummaryIfExists(dest, fileData.cFileName); - - } while (FindNextFileA(hFind, &fileData)); - FindClose(hFind); - } - - -#else - DIR *dp; - struct dirent *dirp; - if((dp = opendir(basePath.c_str())) == NULL) { - LOGI("Error listing base folder %s: %d", basePath.c_str(), _errno()); - return; - } - - while ((dirp = readdir(dp)) != NULL) { - if (dirp->d_type == DT_DIR) - { - addLevelSummaryIfExists(dest, dirp->d_name); - } - } - closedir(dp); -#endif - -} - -LevelStorage* ExternalFileLevelStorageSource::selectLevel(const std::string& levelId, bool createPlayerDir) { - return new ExternalFileLevelStorage(levelId, getFullPath(levelId)); -} - -void ExternalFileLevelStorageSource::deleteLevel( const std::string& levelId ) -{ - std::string path = getFullPath(levelId); - if (!DeleteDirectory(path)) { // If we couldn't delete whole folder, try to remove chunks.. - remove((path + "/chunks.dat").c_str()); - remove((path + "/player.dat").c_str()); - remove((path + "/level.dat").c_str()); - } -} - -static std::string getUniqueLevelName(const LevelSummaryList& levels, const std::string& level ) -{ - std::set Set; - for (unsigned int i = 0; i < levels.size(); ++i) - Set.insert(levels[i].id); - - std::string s = level; - while ( Set.find(s) != Set.end() ) - s += "-"; - return s; -} - -void ExternalFileLevelStorageSource::renameLevel( const std::string& oldLevelId_, const std::string& newLevelName_ ) -{ -#define _renFULLPATH(s) ((basePath + "/" + s).c_str()) - bool isTempFile = (TempLevelId == oldLevelId_); - std::string oldFolder = getFullPath(oldLevelId_); - - if (_access(oldFolder.c_str(), 0) != 0) { - LOGI("Couldn't access %s\n", oldFolder.c_str()); - return; - } - - std::string levelName = Util::stringTrim(newLevelName_); - std::string levelId = levelName; - for (int i = 0; i < sizeof(ILLEGAL_FILE_CHARACTERS) / sizeof(char); ++i) - levelId = Util::stringReplace(levelId, std::string(1, ILLEGAL_FILE_CHARACTERS[i]), ""); - - LevelSummaryList levels; - getLevelList(levels); - levelId = getUniqueLevelName(levels, levelId); - - bool couldRename = false; - if (hasTempDirectory() && isTempFile) { -#ifdef __APPLE__ - std::string newFolder = basePath + "/" + levelId; - moveFolder(oldFolder, newFolder); - couldRename = (_access(newFolder.c_str(), 0) == 0); -#endif - } - - couldRename = couldRename || rename(_renFULLPATH(oldLevelId_), _renFULLPATH(levelId)) == 0; - if (!couldRename) // != 0: fail - levelId = oldLevelId_; // Try to rewrite the level name anyway - - // Rename the level name and write back to file - LevelData levelData; - ExternalFileLevelStorage::readLevelData(_renFULLPATH(levelId), levelData); - levelData.setLevelName(newLevelName_); - ExternalFileLevelStorage::saveLevelData(_renFULLPATH(levelId), levelData, NULL); -} - -std::string ExternalFileLevelStorageSource::getName() -{ - return "External File Level Storage"; -} - -LevelData* ExternalFileLevelStorageSource::getDataTagFor( const std::string& levelId ) -{ - return NULL; -} - -bool ExternalFileLevelStorageSource::isNewLevelIdAcceptable( const std::string& levelId ) -{ - return true; -} - -std::string ExternalFileLevelStorageSource::getFullPath(const std::string& levelId) { - return ((TempLevelId == levelId)? tmpBasePath : basePath) + "/" + levelId; -} - - -#endif /*DEMO_MODE*/ +#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) + +#include "LevelData.hpp" +#include "ExternalFileLevelStorageSource.hpp" +#include "ExternalFileLevelStorage.hpp" +#include "FolderMethods.hpp" +#include "platform/file.hpp" +#include "util/StringUtils.hpp" +#include +#include + +#ifdef __APPLE__ +#include "MoveFolder.hpp" +#endif + +static const char ILLEGAL_FILE_CHARACTERS[] = { + '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' +}; + +ExternalFileLevelStorageSource::ExternalFileLevelStorageSource(const std::string& externalPath, const std::string& temporaryFilesPath) +: _hasTempDirectory(temporaryFilesPath != externalPath) +{ +#ifndef STANDALONE_SERVER + const char* p0 = "/games"; + const char* p1 = "/com.mojang"; + const char* p2 = "/minecraftWorlds"; + const char* tree[] = { + p0, p1, p2 + }; + + int treeLength = sizeof(tree) / sizeof(tree[0]); + + createTree(externalPath.c_str(), tree, treeLength); + + if (hasTempDirectory()) + createTree(temporaryFilesPath.c_str(), tree, treeLength); + + basePath = externalPath + p0 + p1 + p2; + tmpBasePath = temporaryFilesPath + p0 + p1 + p2; +#else + basePath = externalPath; + tmpBasePath = temporaryFilesPath; +#endif +} + +void ExternalFileLevelStorageSource::addLevelSummaryIfExists(LevelSummaryList& dest, const char* dirName) +{ + std::string directory = basePath; + directory += "/"; + directory += dirName; + + LevelData levelData; + + if (ExternalFileLevelStorage::readLevelData(directory, levelData)) + { + LevelSummary summary; + summary.id = dirName; + summary.name = levelData.levelName; + summary.lastPlayed = levelData.getLastPlayed(); + summary.sizeOnDisk = (unsigned int)levelData.getSizeOnDisk(); + summary.gameType = levelData.getGameType(); + + dest.push_back(summary); + } +} + +void ExternalFileLevelStorageSource::getLevelList(LevelSummaryList& dest) +{ +#ifdef WIN32 + + WIN32_FIND_DATAA fileData; + HANDLE hFind; + + std::string searchString = basePath; + searchString += "/*"; + + hFind = FindFirstFileA(searchString.c_str(), &fileData); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + addLevelSummaryIfExists(dest, fileData.cFileName); + + } while (FindNextFileA(hFind, &fileData)); + FindClose(hFind); + } + + +#else + DIR *dp; + struct dirent *dirp; + if((dp = opendir(basePath.c_str())) == NULL) { + LOGI("Error listing base folder %s: %d", basePath.c_str(), _errno()); + return; + } + + while ((dirp = readdir(dp)) != NULL) { + if (dirp->d_type == DT_DIR) + { + addLevelSummaryIfExists(dest, dirp->d_name); + } + } + closedir(dp); +#endif + +} + +LevelStorage* ExternalFileLevelStorageSource::selectLevel(const std::string& levelId, bool createPlayerDir) { + return new ExternalFileLevelStorage(levelId, getFullPath(levelId)); +} + +void ExternalFileLevelStorageSource::deleteLevel( const std::string& levelId ) +{ + std::string path = getFullPath(levelId); + if (!DeleteDirectory(path)) { // If we couldn't delete whole folder, try to remove chunks.. + remove((path + "/chunks.dat").c_str()); + remove((path + "/player.dat").c_str()); + remove((path + "/level.dat").c_str()); + } +} + +static std::string getUniqueLevelName(const LevelSummaryList& levels, const std::string& level ) +{ + std::set Set; + for (unsigned int i = 0; i < levels.size(); ++i) + Set.insert(levels[i].id); + + std::string s = level; + while ( Set.find(s) != Set.end() ) + s += "-"; + return s; +} + +void ExternalFileLevelStorageSource::renameLevel( const std::string& oldLevelId_, const std::string& newLevelName_ ) +{ +#define _renFULLPATH(s) ((basePath + "/" + s).c_str()) + bool isTempFile = (TempLevelId == oldLevelId_); + std::string oldFolder = getFullPath(oldLevelId_); + + if (_access(oldFolder.c_str(), 0) != 0) { + LOGI("Couldn't access %s\n", oldFolder.c_str()); + return; + } + + std::string levelName = Util::stringTrim(newLevelName_); + std::string levelId = levelName; + for (int i = 0; i < sizeof(ILLEGAL_FILE_CHARACTERS) / sizeof(char); ++i) + levelId = Util::stringReplace(levelId, std::string(1, ILLEGAL_FILE_CHARACTERS[i]), ""); + + LevelSummaryList levels; + getLevelList(levels); + levelId = getUniqueLevelName(levels, levelId); + + bool couldRename = false; + if (hasTempDirectory() && isTempFile) { +#ifdef __APPLE__ + std::string newFolder = basePath + "/" + levelId; + moveFolder(oldFolder, newFolder); + couldRename = (_access(newFolder.c_str(), 0) == 0); +#endif + } + + couldRename = couldRename || rename(_renFULLPATH(oldLevelId_), _renFULLPATH(levelId)) == 0; + if (!couldRename) // != 0: fail + levelId = oldLevelId_; // Try to rewrite the level name anyway + + // Rename the level name and write back to file + LevelData levelData; + ExternalFileLevelStorage::readLevelData(_renFULLPATH(levelId), levelData); + levelData.setLevelName(newLevelName_); + ExternalFileLevelStorage::saveLevelData(_renFULLPATH(levelId), levelData, NULL); +} + +std::string ExternalFileLevelStorageSource::getName() +{ + return "External File Level Storage"; +} + +LevelData* ExternalFileLevelStorageSource::getDataTagFor( const std::string& levelId ) +{ + return NULL; +} + +bool ExternalFileLevelStorageSource::isNewLevelIdAcceptable( const std::string& levelId ) +{ + return true; +} + +std::string ExternalFileLevelStorageSource::getFullPath(const std::string& levelId) { + return ((TempLevelId == levelId)? tmpBasePath : basePath) + "/" + levelId; +} + + +#endif /*DEMO_MODE*/ diff --git a/src/world/level/storage/ExternalFileLevelStorageSource.h b/src/world/level/storage/ExternalFileLevelStorageSource.hpp similarity index 93% rename from src/world/level/storage/ExternalFileLevelStorageSource.h rename to src/world/level/storage/ExternalFileLevelStorageSource.hpp index 72c442a..95c1b46 100755 --- a/src/world/level/storage/ExternalFileLevelStorageSource.h +++ b/src/world/level/storage/ExternalFileLevelStorageSource.hpp @@ -1,45 +1,45 @@ -#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) - -#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__ -#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__ - -//package net.minecraft.world.level.storage; - -#include "LevelStorageSource.h" -#include "MemoryLevelStorage.h" - -class ProgressListener; - -class ExternalFileLevelStorageSource: public LevelStorageSource -{ -public: - ExternalFileLevelStorageSource(const std::string& externalPath, const std::string& temporaryFilesPath); - - std::string getName(); - void getLevelList(LevelSummaryList& dest); - - LevelStorage* selectLevel(const std::string& levelId, bool createPlayerDir); - LevelData* getDataTagFor(const std::string& levelId); - - bool isNewLevelIdAcceptable(const std::string& levelId); - - void clearAll() {} - void deleteLevel(const std::string& levelId); - void renameLevel(const std::string& levelId, const std::string& newLevelName); - - bool isConvertible(const std::string& levelId) { return false; } - bool requiresConversion(const std::string& levelId) { return false; } - bool convertLevel(const std::string& levelId, ProgressListener* progress) { return false; } -private: - void addLevelSummaryIfExists(LevelSummaryList& dest, const char* dirName); - bool hasTempDirectory() { return _hasTempDirectory; } - std::string getFullPath(const std::string& levelId); - - std::string basePath; - std::string tmpBasePath; - bool _hasTempDirectory; -}; - -#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__*/ - -#endif /*DEMO_MODE*/ +#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) + +#ifndef NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__ +#define NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__ + +//package net.minecraft.world.level.storage; + +#include "LevelStorageSource.hpp" +#include "MemoryLevelStorage.hpp" + +class ProgressListener; + +class ExternalFileLevelStorageSource: public LevelStorageSource +{ +public: + ExternalFileLevelStorageSource(const std::string& externalPath, const std::string& temporaryFilesPath); + + std::string getName(); + void getLevelList(LevelSummaryList& dest); + + LevelStorage* selectLevel(const std::string& levelId, bool createPlayerDir); + LevelData* getDataTagFor(const std::string& levelId); + + bool isNewLevelIdAcceptable(const std::string& levelId); + + void clearAll() {} + void deleteLevel(const std::string& levelId); + void renameLevel(const std::string& levelId, const std::string& newLevelName); + + bool isConvertible(const std::string& levelId) { return false; } + bool requiresConversion(const std::string& levelId) { return false; } + bool convertLevel(const std::string& levelId, ProgressListener* progress) { return false; } +private: + void addLevelSummaryIfExists(LevelSummaryList& dest, const char* dirName); + bool hasTempDirectory() { return _hasTempDirectory; } + std::string getFullPath(const std::string& levelId); + + std::string basePath; + std::string tmpBasePath; + bool _hasTempDirectory; +}; + +#endif /*NET_MINECRAFT_WORLD_LEVEL_STORAGE__ExternalFileLevelStorageSource_H__*/ + +#endif /*DEMO_MODE*/ diff --git a/src/world/level/storage/FolderMethods.cpp b/src/world/level/storage/FolderMethods.cpp index 5dbfda6..8d059b3 100755 --- a/src/world/level/storage/FolderMethods.cpp +++ b/src/world/level/storage/FolderMethods.cpp @@ -1,77 +1,77 @@ -#include "FolderMethods.h" -#include - -#ifndef WIN32 - -#include -#include -#include - -int _mkdir( const char* name ) { - return mkdir(name, 0755); -} - -int _access( const char* name, int mode ) { - return access(name, mode); -} - -int _errno() { - return errno; -} - -#else - #include - #include - #include -#endif - -bool exists(const char* name) { - return _access(name, 0) == 0; -} - -bool createFolderIfNotExists( const char* name ) { - if (exists(name)) - return true; - - int errorCode = 0; - if ((errorCode = _mkdir(name)) != 0) { - LOGI("FAILED to create folder %s, %d! Escape plan?\n", name, _errno()); - return false; - } - - LOGI("Created folder %s\n", name); - return true; -} - -int getRemainingFileSize( FILE* fp ) { - if (!fp) return 0; - int current = ftell(fp); - fseek(fp, 0, SEEK_END); - int end = ftell(fp); - fseek(fp, current, SEEK_SET); - return end - current; -} - -int getFileSize( const char* filename ) { - FILE* fp = fopen(filename, "rb"); - if (!fp) - return -1; - - fseek(fp, 0, SEEK_END); - int size = ftell(fp); - fclose(fp); - return size; -} - -bool createTree( const char* base, const char* tree[], int treeLength ) { - if (!createFolderIfNotExists(base)) - return false; - - std::string p(base); - for (int i = 0; i < treeLength; ++i && tree[i]) { - p += tree[i]; - if (!createFolderIfNotExists(p.c_str())) - return false; - } - return true; -} +#include "FolderMethods.hpp" +#include + +#ifndef WIN32 + +#include +#include +#include + +int _mkdir( const char* name ) { + return mkdir(name, 0755); +} + +int _access( const char* name, int mode ) { + return access(name, mode); +} + +int _errno() { + return errno; +} + +#else + #include + #include + #include +#endif + +bool exists(const char* name) { + return _access(name, 0) == 0; +} + +bool createFolderIfNotExists( const char* name ) { + if (exists(name)) + return true; + + int errorCode = 0; + if ((errorCode = _mkdir(name)) != 0) { + LOGI("FAILED to create folder %s, %d! Escape plan?\n", name, _errno()); + return false; + } + + LOGI("Created folder %s\n", name); + return true; +} + +int getRemainingFileSize( FILE* fp ) { + if (!fp) return 0; + int current = ftell(fp); + fseek(fp, 0, SEEK_END); + int end = ftell(fp); + fseek(fp, current, SEEK_SET); + return end - current; +} + +int getFileSize( const char* filename ) { + FILE* fp = fopen(filename, "rb"); + if (!fp) + return -1; + + fseek(fp, 0, SEEK_END); + int size = ftell(fp); + fclose(fp); + return size; +} + +bool createTree( const char* base, const char* tree[], int treeLength ) { + if (!createFolderIfNotExists(base)) + return false; + + std::string p(base); + for (int i = 0; i < treeLength; ++i && tree[i]) { + p += tree[i]; + if (!createFolderIfNotExists(p.c_str())) + return false; + } + return true; +} diff --git a/src/world/level/storage/FolderMethods.h b/src/world/level/storage/FolderMethods.hpp similarity index 91% rename from src/world/level/storage/FolderMethods.h rename to src/world/level/storage/FolderMethods.hpp index edc80bf..8070a81 100755 --- a/src/world/level/storage/FolderMethods.h +++ b/src/world/level/storage/FolderMethods.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../../platform/log.h" +#include "platform/log.hpp" #ifdef WIN32 #include diff --git a/src/world/level/storage/LevelData.cpp b/src/world/level/storage/LevelData.cpp index 4cafdf9..25afffe 100755 --- a/src/world/level/storage/LevelData.cpp +++ b/src/world/level/storage/LevelData.cpp @@ -1,377 +1,377 @@ -#include "LevelData.h" - -LevelData::LevelData() -: xSpawn(128), - ySpawn(64), - zSpawn(128), - - seed(0), - lastPlayed(0), - generatorVersion(SharedConstants::GeneratorVersion), - time(0), - dimension(Dimension::NORMAL), - playerDataVersion(-1), - storageVersion(0), - gameType(GameType::Default), spawnMobs(false), - allowCheats(false), loadedPlayerTag(NULL) -{ - //LOGI("ctor 1: %p\n", this); - spawnMobs = (gameType == GameType::Survival); -} - -LevelData::LevelData( const LevelSettings& settings, const std::string& levelName, int generatorVersion /*= -1*/ ) -: seed(settings.getSeed()), - gameType(settings.getGameType()), allowCheats(settings.getAllowCheats()), levelName(levelName), - xSpawn(128), - ySpawn(64), - zSpawn(128), - lastPlayed(0), - time(0), - dimension(Dimension::NORMAL), - playerDataVersion(-1), - loadedPlayerTag(NULL) -{ - //LOGI("ctor 2: %p\n", this); - - if (generatorVersion < 0) - generatorVersion = SharedConstants::GeneratorVersion; - - this->generatorVersion = generatorVersion; - spawnMobs = (gameType == GameType::Survival); -} - -LevelData::LevelData( CompoundTag* tag ) -: loadedPlayerTag(NULL) -{ - //LOGI("ctor 3: %p (%p)\n", this, tag); - getTagData(tag); -} - -LevelData::LevelData( const LevelData& rhs ) -: seed(rhs.seed), - gameType(rhs.gameType), - levelName(rhs.levelName), - xSpawn(rhs.xSpawn), - ySpawn(rhs.ySpawn), - zSpawn(rhs.zSpawn), - lastPlayed(rhs.lastPlayed), - time(rhs.time), - dimension(rhs.dimension), - storageVersion(rhs.storageVersion), - playerDataVersion(rhs.playerDataVersion), - generatorVersion(rhs.generatorVersion), - spawnMobs(rhs.spawnMobs), - allowCheats(rhs.allowCheats), - loadedPlayerTag(NULL), - playerData(rhs.playerData) -{ - //LOGI("c-ctor: %p (%p)\n", this, &rhs); - setPlayerTag(rhs.loadedPlayerTag); - //PlayerData playerData; -} - -LevelData& LevelData::operator=( const LevelData& rhs ) -{ - //LOGI("as-op: %p (%p)\n", this, &rhs); - if (this != &rhs) { - seed = rhs.seed; - gameType = rhs.gameType; - levelName = rhs.levelName; - xSpawn = rhs.xSpawn; - ySpawn = rhs.ySpawn; - zSpawn = rhs.zSpawn; - lastPlayed = rhs.lastPlayed; - time = rhs.time; - dimension = rhs.dimension; - spawnMobs = rhs.spawnMobs; - allowCheats = rhs.allowCheats; - playerData = rhs.playerData; - playerDataVersion = rhs.playerDataVersion; - generatorVersion = rhs.generatorVersion; - storageVersion = rhs.storageVersion; - setPlayerTag(rhs.loadedPlayerTag); - } - - return *this; -} - -LevelData::~LevelData() -{ - //LOGI("dtor: %p\n", this); - setPlayerTag(NULL); -} - -void LevelData::v1_write( RakNet::BitStream& bitStream ) -{ - bitStream.Write(seed); - bitStream.Write(xSpawn); - bitStream.Write(ySpawn); - bitStream.Write(zSpawn); - bitStream.Write(time); - bitStream.Write(sizeOnDisk); - bitStream.Write(getEpochTimeS()); - RakNet::RakString rakName = levelName.c_str(); - bitStream.Write(rakName); - //LOGI("WBS: %d, %d, %d, %d, %d, %d\n", seed, xSpawn, ySpawn, zSpawn, time, sizeOnDisk); -} - -void LevelData::v1_read( RakNet::BitStream& bitStream, int storageVersion ) -{ - this->storageVersion = storageVersion; - bitStream.Read(seed); - bitStream.Read(xSpawn); - bitStream.Read(ySpawn); - bitStream.Read(zSpawn); - bitStream.Read(time); - bitStream.Read(sizeOnDisk); - bitStream.Read(lastPlayed); - RakNet::RakString rakName; - bitStream.Read(rakName); - levelName = rakName.C_String(); - //LOGI("RBS: %d, %d, %d, %d, %d, %d\n", seed, xSpawn, ySpawn, zSpawn, time, sizeOnDisk); -} - -// Caller's responsibility to destroy this Tag -CompoundTag* LevelData::createTag() -{ - CompoundTag* tag = new CompoundTag(); - CompoundTag* player = loadedPlayerTag? (CompoundTag*)loadedPlayerTag->copy() : NULL; - setTagData(tag, player); - return tag; -} - -CompoundTag* LevelData::createTag( const std::vector& players ) -{ - CompoundTag* tag = new CompoundTag(); - - Player* player = NULL; - CompoundTag* playerTag = NULL; - - if (!players.empty()) player = players[0]; - if (player != NULL) { - playerTag = new CompoundTag(); - player->saveWithoutId(playerTag); - } - setTagData(tag, playerTag); - - return tag; -} - -void LevelData::setTagData( CompoundTag* tag, CompoundTag* playerTag ) -{ - if (!tag) return; - tag->putLong("RandomSeed", seed); - tag->putInt("GameType", gameType); - tag->putBoolean("AllowCommands", allowCheats); - tag->putInt("SpawnX", xSpawn); - tag->putInt("SpawnY", ySpawn); - tag->putInt("SpawnZ", zSpawn); - tag->putLong("Time", time); - tag->putLong("SizeOnDisk", sizeOnDisk); - tag->putLong("LastPlayed", getEpochTimeS()); - tag->putString("LevelName", levelName); - tag->putInt("StorageVersion", storageVersion); - tag->putInt("Platform", 2); - - if (playerTag != NULL) { - tag->putCompound("Player", playerTag); - } -} - -void LevelData::getTagData( const CompoundTag* tag ) -{ - if (!tag) return; - seed = (long)tag->getLong("RandomSeed"); - gameType = tag->getInt("GameType"); - allowCheats = tag->getBoolean("AllowCommands"); - xSpawn = tag->getInt("SpawnX"); - ySpawn = tag->getInt("SpawnY"); - zSpawn = tag->getInt("SpawnZ"); - time = (long)tag->getLong("Time"); - lastPlayed = (int)tag->getLong("LastPlayed"); - sizeOnDisk = (int)tag->getLong("SizeOnDisk"); - levelName = tag->getString("LevelName"); - storageVersion = tag->getInt("StorageVersion"); - - spawnMobs = (gameType == GameType::Survival); - - if (tag->contains("Player", Tag::TAG_Compound)) { - setPlayerTag(tag->getCompound("Player")); - - //dimension = loadedPlayerTag.getInt("Dimension"); - } -} - -void LevelData::setPlayerTag( CompoundTag* tag ) -{ - if (loadedPlayerTag) { - loadedPlayerTag->deleteChildren(); - delete loadedPlayerTag; - loadedPlayerTag = NULL; - } - if (tag) - loadedPlayerTag = (CompoundTag*)tag->copy(); -} - -long LevelData::getSeed() const -{ - return seed; -} - -int LevelData::getXSpawn() const -{ - return xSpawn; -} - -int LevelData::getYSpawn() const -{ - return ySpawn; -} - -int LevelData::getZSpawn() const -{ - return zSpawn; -} - -long LevelData::getTime() const -{ - return time; -} - -long LevelData::getSizeOnDisk() const -{ - return sizeOnDisk; -} - -CompoundTag* LevelData::getLoadedPlayerTag() -{ - return loadedPlayerTag; -} - -void LevelData::setLoadedPlayerTo( Player* p ) -{ - if (playerDataVersion == 1) - playerData.loadPlayer(p); -} - -int LevelData::getDimension() -{ - return dimension; -} - -void LevelData::setSeed( long seed ) -{ - this->seed = seed; -} - -void LevelData::setXSpawn( int xSpawn ) -{ - this->xSpawn = xSpawn; -} - -void LevelData::setYSpawn( int ySpawn ) -{ - this->ySpawn = ySpawn; -} - -void LevelData::setZSpawn( int zSpawn ) -{ - this->zSpawn = zSpawn; -} - -void LevelData::setTime( long time ) -{ - this->time = time; -} - -void LevelData::setSizeOnDisk( long sizeOnDisk ) -{ - this->sizeOnDisk = sizeOnDisk; -} - -void LevelData::setLoadedPlayerTag( CompoundTag* playerTag ) -{ - LOGI("set-p: %p (%p <- %p)\n", this, loadedPlayerTag, playerTag); - if (loadedPlayerTag) { - loadedPlayerTag->deleteChildren(); - delete loadedPlayerTag; - } - loadedPlayerTag = playerTag; -} - -void LevelData::setDimension( int dimension ) -{ - this->dimension = dimension; -} - -void LevelData::setSpawn( int xSpawn, int ySpawn, int zSpawn ) -{ - this->xSpawn = xSpawn; - this->ySpawn = ySpawn; - this->zSpawn = zSpawn; -} - -std::string LevelData::getLevelName() -{ - return levelName; -} - -void LevelData::setLevelName( const std::string& levelName ) -{ - this->levelName = levelName; -} - -int LevelData::getGeneratorVersion() const -{ - return generatorVersion; -} - -void LevelData::setGeneratorVersion( int version ) -{ - this->generatorVersion = version; -} - -long LevelData::getLastPlayed() const -{ - return lastPlayed; -} - -int LevelData::getStorageVersion() const -{ - return storageVersion; -} - -void LevelData::setStorageVersion( int version ) -{ - storageVersion = version; -} - -int LevelData::getGameType() const -{ - return gameType; -} - -void LevelData::setGameType( int type ) -{ - gameType = type; -} - -bool LevelData::getSpawnMobs() const -{ - return spawnMobs; -} - -void LevelData::setSpawnMobs( bool doSpawn ) -{ - spawnMobs = doSpawn; -} - -bool LevelData::getAllowCheats() const -{ - return allowCheats; -} - -void LevelData::setAllowCheats( bool allow ) -{ - allowCheats = allow; -} +#include "LevelData.hpp" + +LevelData::LevelData() +: xSpawn(128), + ySpawn(64), + zSpawn(128), + + seed(0), + lastPlayed(0), + generatorVersion(SharedConstants::GeneratorVersion), + time(0), + dimension(Dimension::NORMAL), + playerDataVersion(-1), + storageVersion(0), + gameType(GameType::Default), spawnMobs(false), + allowCheats(false), loadedPlayerTag(NULL) +{ + //LOGI("ctor 1: %p\n", this); + spawnMobs = (gameType == GameType::Survival); +} + +LevelData::LevelData( const LevelSettings& settings, const std::string& levelName, int generatorVersion /*= -1*/ ) +: seed(settings.getSeed()), + gameType(settings.getGameType()), allowCheats(settings.getAllowCheats()), levelName(levelName), + xSpawn(128), + ySpawn(64), + zSpawn(128), + lastPlayed(0), + time(0), + dimension(Dimension::NORMAL), + playerDataVersion(-1), + loadedPlayerTag(NULL) +{ + //LOGI("ctor 2: %p\n", this); + + if (generatorVersion < 0) + generatorVersion = SharedConstants::GeneratorVersion; + + this->generatorVersion = generatorVersion; + spawnMobs = (gameType == GameType::Survival); +} + +LevelData::LevelData( CompoundTag* tag ) +: loadedPlayerTag(NULL) +{ + //LOGI("ctor 3: %p (%p)\n", this, tag); + getTagData(tag); +} + +LevelData::LevelData( const LevelData& rhs ) +: seed(rhs.seed), + gameType(rhs.gameType), + levelName(rhs.levelName), + xSpawn(rhs.xSpawn), + ySpawn(rhs.ySpawn), + zSpawn(rhs.zSpawn), + lastPlayed(rhs.lastPlayed), + time(rhs.time), + dimension(rhs.dimension), + storageVersion(rhs.storageVersion), + playerDataVersion(rhs.playerDataVersion), + generatorVersion(rhs.generatorVersion), + spawnMobs(rhs.spawnMobs), + allowCheats(rhs.allowCheats), + loadedPlayerTag(NULL), + playerData(rhs.playerData) +{ + //LOGI("c-ctor: %p (%p)\n", this, &rhs); + setPlayerTag(rhs.loadedPlayerTag); + //PlayerData playerData; +} + +LevelData& LevelData::operator=( const LevelData& rhs ) +{ + //LOGI("as-op: %p (%p)\n", this, &rhs); + if (this != &rhs) { + seed = rhs.seed; + gameType = rhs.gameType; + levelName = rhs.levelName; + xSpawn = rhs.xSpawn; + ySpawn = rhs.ySpawn; + zSpawn = rhs.zSpawn; + lastPlayed = rhs.lastPlayed; + time = rhs.time; + dimension = rhs.dimension; + spawnMobs = rhs.spawnMobs; + allowCheats = rhs.allowCheats; + playerData = rhs.playerData; + playerDataVersion = rhs.playerDataVersion; + generatorVersion = rhs.generatorVersion; + storageVersion = rhs.storageVersion; + setPlayerTag(rhs.loadedPlayerTag); + } + + return *this; +} + +LevelData::~LevelData() +{ + //LOGI("dtor: %p\n", this); + setPlayerTag(NULL); +} + +void LevelData::v1_write( RakNet::BitStream& bitStream ) +{ + bitStream.Write(seed); + bitStream.Write(xSpawn); + bitStream.Write(ySpawn); + bitStream.Write(zSpawn); + bitStream.Write(time); + bitStream.Write(sizeOnDisk); + bitStream.Write(getEpochTimeS()); + RakNet::RakString rakName = levelName.c_str(); + bitStream.Write(rakName); + //LOGI("WBS: %d, %d, %d, %d, %d, %d\n", seed, xSpawn, ySpawn, zSpawn, time, sizeOnDisk); +} + +void LevelData::v1_read( RakNet::BitStream& bitStream, int storageVersion ) +{ + this->storageVersion = storageVersion; + bitStream.Read(seed); + bitStream.Read(xSpawn); + bitStream.Read(ySpawn); + bitStream.Read(zSpawn); + bitStream.Read(time); + bitStream.Read(sizeOnDisk); + bitStream.Read(lastPlayed); + RakNet::RakString rakName; + bitStream.Read(rakName); + levelName = rakName.C_String(); + //LOGI("RBS: %d, %d, %d, %d, %d, %d\n", seed, xSpawn, ySpawn, zSpawn, time, sizeOnDisk); +} + +// Caller's responsibility to destroy this Tag +CompoundTag* LevelData::createTag() +{ + CompoundTag* tag = new CompoundTag(); + CompoundTag* player = loadedPlayerTag? (CompoundTag*)loadedPlayerTag->copy() : NULL; + setTagData(tag, player); + return tag; +} + +CompoundTag* LevelData::createTag( const std::vector& players ) +{ + CompoundTag* tag = new CompoundTag(); + + Player* player = NULL; + CompoundTag* playerTag = NULL; + + if (!players.empty()) player = players[0]; + if (player != NULL) { + playerTag = new CompoundTag(); + player->saveWithoutId(playerTag); + } + setTagData(tag, playerTag); + + return tag; +} + +void LevelData::setTagData( CompoundTag* tag, CompoundTag* playerTag ) +{ + if (!tag) return; + tag->putLong("RandomSeed", seed); + tag->putInt("GameType", gameType); + tag->putBoolean("AllowCommands", allowCheats); + tag->putInt("SpawnX", xSpawn); + tag->putInt("SpawnY", ySpawn); + tag->putInt("SpawnZ", zSpawn); + tag->putLong("Time", time); + tag->putLong("SizeOnDisk", sizeOnDisk); + tag->putLong("LastPlayed", getEpochTimeS()); + tag->putString("LevelName", levelName); + tag->putInt("StorageVersion", storageVersion); + tag->putInt("Platform", 2); + + if (playerTag != NULL) { + tag->putCompound("Player", playerTag); + } +} + +void LevelData::getTagData( const CompoundTag* tag ) +{ + if (!tag) return; + seed = (long)tag->getLong("RandomSeed"); + gameType = tag->getInt("GameType"); + allowCheats = tag->getBoolean("AllowCommands"); + xSpawn = tag->getInt("SpawnX"); + ySpawn = tag->getInt("SpawnY"); + zSpawn = tag->getInt("SpawnZ"); + time = (long)tag->getLong("Time"); + lastPlayed = (int)tag->getLong("LastPlayed"); + sizeOnDisk = (int)tag->getLong("SizeOnDisk"); + levelName = tag->getString("LevelName"); + storageVersion = tag->getInt("StorageVersion"); + + spawnMobs = (gameType == GameType::Survival); + + if (tag->contains("Player", Tag::TAG_Compound)) { + setPlayerTag(tag->getCompound("Player")); + + //dimension = loadedPlayerTag.getInt("Dimension"); + } +} + +void LevelData::setPlayerTag( CompoundTag* tag ) +{ + if (loadedPlayerTag) { + loadedPlayerTag->deleteChildren(); + delete loadedPlayerTag; + loadedPlayerTag = NULL; + } + if (tag) + loadedPlayerTag = (CompoundTag*)tag->copy(); +} + +long LevelData::getSeed() const +{ + return seed; +} + +int LevelData::getXSpawn() const +{ + return xSpawn; +} + +int LevelData::getYSpawn() const +{ + return ySpawn; +} + +int LevelData::getZSpawn() const +{ + return zSpawn; +} + +long LevelData::getTime() const +{ + return time; +} + +long LevelData::getSizeOnDisk() const +{ + return sizeOnDisk; +} + +CompoundTag* LevelData::getLoadedPlayerTag() +{ + return loadedPlayerTag; +} + +void LevelData::setLoadedPlayerTo( Player* p ) +{ + if (playerDataVersion == 1) + playerData.loadPlayer(p); +} + +int LevelData::getDimension() +{ + return dimension; +} + +void LevelData::setSeed( long seed ) +{ + this->seed = seed; +} + +void LevelData::setXSpawn( int xSpawn ) +{ + this->xSpawn = xSpawn; +} + +void LevelData::setYSpawn( int ySpawn ) +{ + this->ySpawn = ySpawn; +} + +void LevelData::setZSpawn( int zSpawn ) +{ + this->zSpawn = zSpawn; +} + +void LevelData::setTime( long time ) +{ + this->time = time; +} + +void LevelData::setSizeOnDisk( long sizeOnDisk ) +{ + this->sizeOnDisk = sizeOnDisk; +} + +void LevelData::setLoadedPlayerTag( CompoundTag* playerTag ) +{ + LOGI("set-p: %p (%p <- %p)\n", this, loadedPlayerTag, playerTag); + if (loadedPlayerTag) { + loadedPlayerTag->deleteChildren(); + delete loadedPlayerTag; + } + loadedPlayerTag = playerTag; +} + +void LevelData::setDimension( int dimension ) +{ + this->dimension = dimension; +} + +void LevelData::setSpawn( int xSpawn, int ySpawn, int zSpawn ) +{ + this->xSpawn = xSpawn; + this->ySpawn = ySpawn; + this->zSpawn = zSpawn; +} + +std::string LevelData::getLevelName() +{ + return levelName; +} + +void LevelData::setLevelName( const std::string& levelName ) +{ + this->levelName = levelName; +} + +int LevelData::getGeneratorVersion() const +{ + return generatorVersion; +} + +void LevelData::setGeneratorVersion( int version ) +{ + this->generatorVersion = version; +} + +long LevelData::getLastPlayed() const +{ + return lastPlayed; +} + +int LevelData::getStorageVersion() const +{ + return storageVersion; +} + +void LevelData::setStorageVersion( int version ) +{ + storageVersion = version; +} + +int LevelData::getGameType() const +{ + return gameType; +} + +void LevelData::setGameType( int type ) +{ + gameType = type; +} + +bool LevelData::getSpawnMobs() const +{ + return spawnMobs; +} + +void LevelData::setSpawnMobs( bool doSpawn ) +{ + spawnMobs = doSpawn; +} + +bool LevelData::getAllowCheats() const +{ + return allowCheats; +} + +void LevelData::setAllowCheats( bool allow ) +{ + allowCheats = allow; +} diff --git a/src/world/level/storage/LevelData.h b/src/world/level/storage/LevelData.hpp similarity index 92% rename from src/world/level/storage/LevelData.h rename to src/world/level/storage/LevelData.hpp index 1cfc6a3..7d6ef3f 100755 --- a/src/world/level/storage/LevelData.h +++ b/src/world/level/storage/LevelData.hpp @@ -3,14 +3,14 @@ //package net.minecraft.world.level.storage; #include -#include "PlayerData.h" -#include "../LevelSettings.h" -#include "../dimension/Dimension.h" +#include "PlayerData.hpp" +#include "world/level/LevelSettings.hpp" +#include "world/level/dimension/Dimension.hpp" // sorry for RakNet dependency, but I really like using BitStream -#include "../../../raknet/BitStream.h" -#include "../../../platform/time.h" -#include "../../../nbt/CompoundTag.h" +#include "raknet/BitStream.h" +#include "platform/time.hpp" +#include "nbt/CompoundTag.hpp" class LevelData { diff --git a/src/world/level/storage/LevelStorage.h b/src/world/level/storage/LevelStorage.hpp similarity index 100% rename from src/world/level/storage/LevelStorage.h rename to src/world/level/storage/LevelStorage.hpp diff --git a/src/world/level/storage/LevelStorageSource.cpp b/src/world/level/storage/LevelStorageSource.cpp index 169e181..f1b341a 100755 --- a/src/world/level/storage/LevelStorageSource.cpp +++ b/src/world/level/storage/LevelStorageSource.cpp @@ -1,3 +1,3 @@ -#include "LevelStorageSource.h" - -const std::string LevelStorageSource::TempLevelId = "_LastJoinedServer"; +#include "LevelStorageSource.hpp" + +const std::string LevelStorageSource::TempLevelId = "_LastJoinedServer"; diff --git a/src/world/level/storage/LevelStorageSource.h b/src/world/level/storage/LevelStorageSource.hpp similarity index 100% rename from src/world/level/storage/LevelStorageSource.h rename to src/world/level/storage/LevelStorageSource.hpp diff --git a/src/world/level/storage/MemoryLevelStorage.h b/src/world/level/storage/MemoryLevelStorage.hpp similarity index 91% rename from src/world/level/storage/MemoryLevelStorage.h rename to src/world/level/storage/MemoryLevelStorage.hpp index 8eb57f9..ce75881 100755 --- a/src/world/level/storage/MemoryLevelStorage.h +++ b/src/world/level/storage/MemoryLevelStorage.hpp @@ -4,8 +4,8 @@ #include -#include "LevelStorage.h" -#include "../chunk/storage/MemoryChunkStorage.h" +#include "LevelStorage.hpp" +#include "world/level/chunk/storage/MemoryChunkStorage.hpp" class Player; class Dimension; diff --git a/src/world/level/storage/MemoryLevelStorageSource.h b/src/world/level/storage/MemoryLevelStorageSource.hpp similarity index 94% rename from src/world/level/storage/MemoryLevelStorageSource.h rename to src/world/level/storage/MemoryLevelStorageSource.hpp index e03897b..43fdb4b 100755 --- a/src/world/level/storage/MemoryLevelStorageSource.h +++ b/src/world/level/storage/MemoryLevelStorageSource.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.storage; -#include "LevelStorageSource.h" -#include "MemoryLevelStorage.h" +#include "LevelStorageSource.hpp" +#include "MemoryLevelStorage.hpp" class ProgressListener; class MemoryLevelStorageSource: public LevelStorageSource diff --git a/src/world/level/storage/MoveFolder.h b/src/world/level/storage/MoveFolder.hpp similarity index 100% rename from src/world/level/storage/MoveFolder.h rename to src/world/level/storage/MoveFolder.hpp diff --git a/src/world/level/storage/PlayerData.h b/src/world/level/storage/PlayerData.hpp similarity index 89% rename from src/world/level/storage/PlayerData.h rename to src/world/level/storage/PlayerData.hpp index 4973943..afae16f 100755 --- a/src/world/level/storage/PlayerData.h +++ b/src/world/level/storage/PlayerData.hpp @@ -1,9 +1,9 @@ #pragma once -#include "../../entity/player/Player.h" -#include "../../entity/player/Inventory.h" -#include "../../phys/Vec3.h" -#include "../../../util/Mth.h" +#include "world/entity/player/Player.hpp" +#include "world/entity/player/Inventory.hpp" +#include "world/phys/Vec3.hpp" +#include "util/Mth.hpp" static float clampRot(float r) { return Mth::clamp(r, -100000.0f, 100000.0f); diff --git a/src/world/level/storage/RegionFile.cpp b/src/world/level/storage/RegionFile.cpp index 3edecce..df3d3ed 100755 --- a/src/world/level/storage/RegionFile.cpp +++ b/src/world/level/storage/RegionFile.cpp @@ -1,216 +1,216 @@ -#include "RegionFile.h" -#include "../../../platform/log.h" - -const int SECTOR_BYTES = 4096; -const int SECTOR_INTS = SECTOR_BYTES / 4; -const int SECTOR_COLS = 32; - -static const char* const REGION_DAT_NAME = "chunks.dat"; - -static void logAssert(int actual, int expected) { - if (actual != expected) { - LOGI("ERROR: I/O operation failed (%d vs %d)\n", actual, expected); - } -} - -RegionFile::RegionFile(const std::string& basePath) -: file(NULL) -{ - filename = basePath; - filename += "/"; - filename += REGION_DAT_NAME; - - offsets = new int[SECTOR_INTS]; - - emptyChunk = new int[SECTOR_INTS]; - memset(emptyChunk, 0, SECTOR_INTS * sizeof(int)); -} - -RegionFile::~RegionFile() -{ - close(); - delete [] offsets; - delete [] emptyChunk; -} - -bool RegionFile::open() -{ - close(); - - memset(offsets, 0, SECTOR_INTS * sizeof(int)); - - // attempt to open file - file = fopen(filename.c_str(), "r+b"); - if (file) - { - // read offset table - logAssert(fread(offsets, sizeof(int), SECTOR_INTS, file), SECTOR_INTS); - - // mark initial sector as blocked - sectorFree[0] = false; - - // setup blocked sectors - for (int sector = 0; sector < SECTOR_INTS; sector++) - { - int offset = offsets[sector]; - if (offset) - { - int base = offset >> 8; - int count = offset & 0xff; - - for (int i = 0; i < count; i++) - { - sectorFree[base + i] = false; - } - } - } - } - else - { - // new world - file = fopen(filename.c_str(), "w+b"); - if (!file) - { - LOGI("Failed to create chunk file %s\n", filename.c_str()); - return false; - } - - // write sector header (all zeroes) - logAssert(fwrite(offsets, sizeof(int), SECTOR_INTS, file), SECTOR_INTS); - - // mark initial sector as blocked - sectorFree[0] = false; - } - - return file != NULL; -} - -void RegionFile::close() -{ - if (file) - { - fclose(file); - file = NULL; - } -} - -bool RegionFile::readChunk(int x, int z, RakNet::BitStream** destChunkData) -{ - int offset = offsets[x + z * SECTOR_COLS]; - - if (offset == 0) - { - // not written to file yet - return false; - } - - int sectorNum = offset >> 8; - - fseek(file, sectorNum * SECTOR_BYTES, SEEK_SET); - int length = 0; - fread(&length, sizeof(int), 1, file); - - assert(length < ((offset & 0xff) * SECTOR_BYTES)); - length -= sizeof(int); - if (length <= 0) { - //*destChunkData = NULL; - //return false; - } - - unsigned char* data = new unsigned char[length]; - logAssert(fread(data, 1, length, file), length); - *destChunkData = new RakNet::BitStream(data, length, false); - //delete [] data; - - return true; -} - -bool RegionFile::writeChunk(int x, int z, RakNet::BitStream& chunkData) -{ - int size = chunkData.GetNumberOfBytesUsed() + sizeof(int); - - int offset = offsets[x + z * SECTOR_COLS]; - int sectorNum = offset >> 8; - int sectorCount = offset & 0xff; - int sectorsNeeded = (size / SECTOR_BYTES) + 1; - - if (sectorsNeeded > 256) - { - LOGI("ERROR: Chunk is too big to be saved to file\n"); - return false; - } - - if (sectorNum != 0 && sectorCount == sectorsNeeded) { - // the sector can be written on top of its old data - write(sectorNum, chunkData); - } - else - { - // we need a new location - - // mark old sectors as free - for (int i = 0; i < sectorCount; i++) - { - sectorFree[sectorNum + i] = true; - } - - // find an available slot with enough run length - int slot = 0; - int runLength = 0; - bool extendFile = false; - while (runLength < sectorsNeeded) - { - if (sectorFree.find(slot + runLength) == sectorFree.end()) - { - extendFile = true; - break; - } - if (sectorFree[slot + runLength] == true) - { - runLength++; - } - else - { - slot = slot + runLength + 1; - runLength = 0; - } - } - - if (extendFile) - { - fseek(file, 0, SEEK_END); - for (int i = 0; i < (sectorsNeeded - runLength); i++) - { - fwrite(emptyChunk, sizeof(int), SECTOR_INTS, file); - sectorFree[slot + i] = true; - } - } - offsets[x + z * SECTOR_COLS] = (slot << 8) | sectorsNeeded; - // mark slots as taken - for (int i = 0; i < sectorsNeeded; i++) - { - sectorFree[slot + i] = false; - } - - // write! - write(slot, chunkData); - - // write sector data - fseek(file, (x + z * SECTOR_COLS) * sizeof(int), SEEK_SET); - fwrite(&offsets[x + z * SECTOR_COLS], sizeof(int), 1, file); - } - - - return true; -} - -bool RegionFile::write(int sector, RakNet::BitStream& chunkData) -{ - fseek(file, sector * SECTOR_BYTES, SEEK_SET); - //LOGI("writing %d B to sector %d\n", chunkData.GetNumberOfBytesUsed(), sector); - int size = chunkData.GetNumberOfBytesUsed() + sizeof(int); - logAssert(fwrite(&size, sizeof(int), 1, file), 1); - logAssert(fwrite(chunkData.GetData(), 1, chunkData.GetNumberOfBytesUsed(), file), chunkData.GetNumberOfBytesUsed()); - - return true; -} +#include "RegionFile.hpp" +#include "platform/log.hpp" + +const int SECTOR_BYTES = 4096; +const int SECTOR_INTS = SECTOR_BYTES / 4; +const int SECTOR_COLS = 32; + +static const char* const REGION_DAT_NAME = "chunks.dat"; + +static void logAssert(int actual, int expected) { + if (actual != expected) { + LOGI("ERROR: I/O operation failed (%d vs %d)\n", actual, expected); + } +} + +RegionFile::RegionFile(const std::string& basePath) +: file(NULL) +{ + filename = basePath; + filename += "/"; + filename += REGION_DAT_NAME; + + offsets = new int[SECTOR_INTS]; + + emptyChunk = new int[SECTOR_INTS]; + memset(emptyChunk, 0, SECTOR_INTS * sizeof(int)); +} + +RegionFile::~RegionFile() +{ + close(); + delete [] offsets; + delete [] emptyChunk; +} + +bool RegionFile::open() +{ + close(); + + memset(offsets, 0, SECTOR_INTS * sizeof(int)); + + // attempt to open file + file = fopen(filename.c_str(), "r+b"); + if (file) + { + // read offset table + logAssert(fread(offsets, sizeof(int), SECTOR_INTS, file), SECTOR_INTS); + + // mark initial sector as blocked + sectorFree[0] = false; + + // setup blocked sectors + for (int sector = 0; sector < SECTOR_INTS; sector++) + { + int offset = offsets[sector]; + if (offset) + { + int base = offset >> 8; + int count = offset & 0xff; + + for (int i = 0; i < count; i++) + { + sectorFree[base + i] = false; + } + } + } + } + else + { + // new world + file = fopen(filename.c_str(), "w+b"); + if (!file) + { + LOGI("Failed to create chunk file %s\n", filename.c_str()); + return false; + } + + // write sector header (all zeroes) + logAssert(fwrite(offsets, sizeof(int), SECTOR_INTS, file), SECTOR_INTS); + + // mark initial sector as blocked + sectorFree[0] = false; + } + + return file != NULL; +} + +void RegionFile::close() +{ + if (file) + { + fclose(file); + file = NULL; + } +} + +bool RegionFile::readChunk(int x, int z, RakNet::BitStream** destChunkData) +{ + int offset = offsets[x + z * SECTOR_COLS]; + + if (offset == 0) + { + // not written to file yet + return false; + } + + int sectorNum = offset >> 8; + + fseek(file, sectorNum * SECTOR_BYTES, SEEK_SET); + int length = 0; + fread(&length, sizeof(int), 1, file); + + assert(length < ((offset & 0xff) * SECTOR_BYTES)); + length -= sizeof(int); + if (length <= 0) { + //*destChunkData = NULL; + //return false; + } + + unsigned char* data = new unsigned char[length]; + logAssert(fread(data, 1, length, file), length); + *destChunkData = new RakNet::BitStream(data, length, false); + //delete [] data; + + return true; +} + +bool RegionFile::writeChunk(int x, int z, RakNet::BitStream& chunkData) +{ + int size = chunkData.GetNumberOfBytesUsed() + sizeof(int); + + int offset = offsets[x + z * SECTOR_COLS]; + int sectorNum = offset >> 8; + int sectorCount = offset & 0xff; + int sectorsNeeded = (size / SECTOR_BYTES) + 1; + + if (sectorsNeeded > 256) + { + LOGI("ERROR: Chunk is too big to be saved to file\n"); + return false; + } + + if (sectorNum != 0 && sectorCount == sectorsNeeded) { + // the sector can be written on top of its old data + write(sectorNum, chunkData); + } + else + { + // we need a new location + + // mark old sectors as free + for (int i = 0; i < sectorCount; i++) + { + sectorFree[sectorNum + i] = true; + } + + // find an available slot with enough run length + int slot = 0; + int runLength = 0; + bool extendFile = false; + while (runLength < sectorsNeeded) + { + if (sectorFree.find(slot + runLength) == sectorFree.end()) + { + extendFile = true; + break; + } + if (sectorFree[slot + runLength] == true) + { + runLength++; + } + else + { + slot = slot + runLength + 1; + runLength = 0; + } + } + + if (extendFile) + { + fseek(file, 0, SEEK_END); + for (int i = 0; i < (sectorsNeeded - runLength); i++) + { + fwrite(emptyChunk, sizeof(int), SECTOR_INTS, file); + sectorFree[slot + i] = true; + } + } + offsets[x + z * SECTOR_COLS] = (slot << 8) | sectorsNeeded; + // mark slots as taken + for (int i = 0; i < sectorsNeeded; i++) + { + sectorFree[slot + i] = false; + } + + // write! + write(slot, chunkData); + + // write sector data + fseek(file, (x + z * SECTOR_COLS) * sizeof(int), SEEK_SET); + fwrite(&offsets[x + z * SECTOR_COLS], sizeof(int), 1, file); + } + + + return true; +} + +bool RegionFile::write(int sector, RakNet::BitStream& chunkData) +{ + fseek(file, sector * SECTOR_BYTES, SEEK_SET); + //LOGI("writing %d B to sector %d\n", chunkData.GetNumberOfBytesUsed(), sector); + int size = chunkData.GetNumberOfBytesUsed() + sizeof(int); + logAssert(fwrite(&size, sizeof(int), 1, file), 1); + logAssert(fwrite(chunkData.GetData(), 1, chunkData.GetNumberOfBytesUsed(), file), chunkData.GetNumberOfBytesUsed()); + + return true; +} diff --git a/src/world/level/storage/RegionFile.h b/src/world/level/storage/RegionFile.hpp similarity index 92% rename from src/world/level/storage/RegionFile.h rename to src/world/level/storage/RegionFile.hpp index 9e99cbc..e6c75e1 100755 --- a/src/world/level/storage/RegionFile.h +++ b/src/world/level/storage/RegionFile.hpp @@ -2,7 +2,7 @@ #include #include -#include "../../../raknet/BitStream.h" +#include "raknet/BitStream.h" typedef std::map FreeSectorMap; diff --git a/src/world/level/tile/BedTile.cpp b/src/world/level/tile/BedTile.cpp index 51bbf5e..72f5d23 100755 --- a/src/world/level/tile/BedTile.cpp +++ b/src/world/level/tile/BedTile.cpp @@ -1,213 +1,213 @@ -#include "BedTile.h" -#include "../Level.h" -#include "../dimension/Dimension.h" -#include "../../entity/player/Player.h" -#include "../../Facing.h" -#include "../../Direction.h" - -const int BedTile::HEAD_DIRECTION_OFFSETS[4][2] = { - { 0, 1 }, - { -1, 0 }, - { 0, -1 }, - { 1, 0 } -}; - -BedTile::BedTile( int id ) : super(id, 6 + 8 * 16, Material::cloth) { - setShape(); -} - -bool BedTile::use(Level* level, int x, int y, int z, Player* player) { - if(player->isSleeping()) { - int dimensionsMatch = player->bedPosition.x == x ? 1 : 0; - dimensionsMatch += player->bedPosition.y == y ? 1 : 0; - dimensionsMatch += player->bedPosition.z == z ? 1 : 0; - int maxDistance = Mth::abs(player->bedPosition.x - x); - maxDistance = Mth::Max(maxDistance, Mth::abs(player->bedPosition.y - y)); - maxDistance = Mth::Max(maxDistance, Mth::abs(player->bedPosition.z - z)); - if(dimensionsMatch >= 2 && maxDistance < 3) { - player->stopSleepInBed(false, true, true); - return true; - } - } - if(level->isClientSide) return true; - int data = level->getData(x, y, z); - - if(!isHeadPiece(data)) { - int direction = DirectionalTile::getDirection(data); - x += HEAD_DIRECTION_OFFSETS[direction][0]; - z += HEAD_DIRECTION_OFFSETS[direction][1]; - if(level->getTile(x, y, z) != id) { - return true; - } - data = level->getData(x, y, z); - } - if(!level->dimension->mayRespawn()) { - float xc = x + 0.5f; - float yc = y + 0.5f; - float zc = z + 0.5f; - level->setTile(x, y, z, 0); - int direction = DirectionalTile::getDirection(data); - x += HEAD_DIRECTION_OFFSETS[direction][0]; - y += HEAD_DIRECTION_OFFSETS[direction][1]; - if(level->getTile(x, y, z) == id) { - level->setTile(x, y, z, 0); - xc = (xc + x + 0.5f) / 2; - yc = (yc + y + 0.5f) / 2; - zc = (zc + z + 0.5f) / 2; - } - level->explode(NULL, x + 0.5f, y + 0.5f, z + 0.5f, 5, true); - return true; - } - if(isOccupied(data)) { - Player* sleepingPlayer = NULL; - for(PlayerList::iterator i = level->players.begin(); i != level->players.end(); ++i) { - if((*i)->isSleeping()) { - Pos pos = (*i)->bedPosition; - if(pos.x == x && pos.y == y && pos.z == z) { - sleepingPlayer = (*i); - break; - } - } - } - if(sleepingPlayer == NULL) { - BedTile::setOccupied(level, x, y, z, false); - } - else { - sleepingPlayer->displayClientMessage("This bed is occupied"/*"tile.bed.occupied"*/); - return true; - } - } - int result = player->startSleepInBed(x, y, z); - if(result == BedSleepingResult::OK) { - BedTile::setOccupied(level, x, y, z, true); - return true; - } - if(result == BedSleepingResult::NOT_POSSIBLE_NOW) { - player->displayClientMessage("You can only sleep at night" /*tile.bed.noSleep"*/); - } else if(result == BedSleepingResult::NOT_SAFE) { - player->displayClientMessage("You may not rest now, there are monsters nearby"/*"tile.bed.notSafe"*/); - } - return true; -} - -void BedTile::setOccupied( Level* level, int x, int y, int z, bool occupied ) { - int data = level->getData(x, y, z); - if(occupied) { - data |= OCCUPIED_DATA; - } else { - data &= ~OCCUPIED_DATA; - } - level->setData(x, y, z, data); -} - -int BedTile::getTexture( int face, int data ) { - if(face == Facing::DOWN) { - return Tile::wood->tex; - } - int direction = getDirection(data); - int tileFacing = Direction::RELATIVE_DIRECTION_FACING[direction][face]; - if (isHeadPiece(data)) { - if (tileFacing == Facing::NORTH) { - return tex + 2 + 16; - } - if (tileFacing == Facing::EAST || tileFacing == Facing::WEST) { - return tex + 1 + 16; - } - return tex + 1; - } else { - if (tileFacing == Facing::SOUTH) { - return tex - 1 + 16; - } - if (tileFacing == Facing::EAST || tileFacing == Facing::WEST) { - return tex + 16; - } - return tex; - } -} - -int BedTile::getRenderShape() { - return Tile::SHAPE_BED; -} - -bool BedTile::isCubeShaped() { - return false; -} - -bool BedTile::isSolidRender() { - return false; -} - -void BedTile::neighborChanged( Level* level, int x, int y, int z, int type ) { - int data = level->getData(x, y, z); - int direction = getDirection(data); - if(isHeadPiece(data)) { - if(level->getTile(x - HEAD_DIRECTION_OFFSETS[direction][0], y, z - HEAD_DIRECTION_OFFSETS[direction][1]) != id) { - level->setTile(x, y, z, 0); - } - } else { - if(level->getTile(x + HEAD_DIRECTION_OFFSETS[direction][0], y, z + HEAD_DIRECTION_OFFSETS[direction][1]) != id) { - level->setTile(x, y, z, 0); - if(!level->isClientSide) { - //spawnResources(level, x, y, z, data, 1); - popResource(level, x, y, z, ItemInstance(Item::bed)); - } - } - } -} - -int BedTile::getResource( int data, Random* random ) { - if(isHeadPiece(data)) { - return 0; - } - return Item::bed->id; -} - -bool BedTile::findStandUpPosition( Level* level, int x, int y, int z, int skipCount, Pos& position) { - int data = level->getData(x, y, z); - int direction = DirectionalTile::getDirection(data); - for(int step = 0; step <= 1; ++step) { - int startX = x - BedTile::HEAD_DIRECTION_OFFSETS[direction][0] * step - 1; - int startZ = z - BedTile::HEAD_DIRECTION_OFFSETS[direction][1] * step - 1; - int endX = startX + 2; - int endZ = startZ + 2; - for(int standX = startX; standX <= endX; ++standX) { - for (int standZ = startZ; standZ <= endZ; ++standZ) { - if (level->isSolidBlockingTile(standX, y - 1, standZ) && level->isEmptyTile(standX, y, standZ) && level->isEmptyTile(standX, y + 1, standZ)) { - if (skipCount > 0) { - skipCount--; - continue; - } - position = Pos(standX, y, standZ); - return true; - } - } - } - } - return false; -} - -void BedTile::spawnResources( Level* level, int x, int y, int z, int data, float odds ) { - if(!isHeadPiece(data)) { - //super::spawnResources(level, x, y, z, data, odds); - popResource(level, x, y, z, ItemInstance(Item::bed)); - } -} - -void BedTile::updateShape( LevelSource* level, int x, int y, int z ) { - setShape(); -} - -int BedTile::getRenderLayer() { - return Tile::RENDERLAYER_ALPHATEST; -} -void BedTile::setShape() { - super::setShape(0, 0, 0, 1, 9.0f / 16.0f, 1); -} - -bool BedTile::isHeadPiece( int data ) { - return (data & HEAD_PIECE_DATA) != 0; -} - -bool BedTile::isOccupied( int data ) { - return (data & OCCUPIED_DATA) != 0; -} +#include "BedTile.hpp" +#include "world/level/Level.hpp" +#include "world/level/dimension/Dimension.hpp" +#include "world/entity/player/Player.hpp" +#include "world/Facing.hpp" +#include "world/Direction.hpp" + +const int BedTile::HEAD_DIRECTION_OFFSETS[4][2] = { + { 0, 1 }, + { -1, 0 }, + { 0, -1 }, + { 1, 0 } +}; + +BedTile::BedTile( int id ) : super(id, 6 + 8 * 16, Material::cloth) { + setShape(); +} + +bool BedTile::use(Level* level, int x, int y, int z, Player* player) { + if(player->isSleeping()) { + int dimensionsMatch = player->bedPosition.x == x ? 1 : 0; + dimensionsMatch += player->bedPosition.y == y ? 1 : 0; + dimensionsMatch += player->bedPosition.z == z ? 1 : 0; + int maxDistance = Mth::abs(player->bedPosition.x - x); + maxDistance = Mth::Max(maxDistance, Mth::abs(player->bedPosition.y - y)); + maxDistance = Mth::Max(maxDistance, Mth::abs(player->bedPosition.z - z)); + if(dimensionsMatch >= 2 && maxDistance < 3) { + player->stopSleepInBed(false, true, true); + return true; + } + } + if(level->isClientSide) return true; + int data = level->getData(x, y, z); + + if(!isHeadPiece(data)) { + int direction = DirectionalTile::getDirection(data); + x += HEAD_DIRECTION_OFFSETS[direction][0]; + z += HEAD_DIRECTION_OFFSETS[direction][1]; + if(level->getTile(x, y, z) != id) { + return true; + } + data = level->getData(x, y, z); + } + if(!level->dimension->mayRespawn()) { + float xc = x + 0.5f; + float yc = y + 0.5f; + float zc = z + 0.5f; + level->setTile(x, y, z, 0); + int direction = DirectionalTile::getDirection(data); + x += HEAD_DIRECTION_OFFSETS[direction][0]; + y += HEAD_DIRECTION_OFFSETS[direction][1]; + if(level->getTile(x, y, z) == id) { + level->setTile(x, y, z, 0); + xc = (xc + x + 0.5f) / 2; + yc = (yc + y + 0.5f) / 2; + zc = (zc + z + 0.5f) / 2; + } + level->explode(NULL, x + 0.5f, y + 0.5f, z + 0.5f, 5, true); + return true; + } + if(isOccupied(data)) { + Player* sleepingPlayer = NULL; + for(PlayerList::iterator i = level->players.begin(); i != level->players.end(); ++i) { + if((*i)->isSleeping()) { + Pos pos = (*i)->bedPosition; + if(pos.x == x && pos.y == y && pos.z == z) { + sleepingPlayer = (*i); + break; + } + } + } + if(sleepingPlayer == NULL) { + BedTile::setOccupied(level, x, y, z, false); + } + else { + sleepingPlayer->displayClientMessage("This bed is occupied"/*"tile.bed.occupied"*/); + return true; + } + } + int result = player->startSleepInBed(x, y, z); + if(result == BedSleepingResult::OK) { + BedTile::setOccupied(level, x, y, z, true); + return true; + } + if(result == BedSleepingResult::NOT_POSSIBLE_NOW) { + player->displayClientMessage("You can only sleep at night" /*tile.bed.noSleep"*/); + } else if(result == BedSleepingResult::NOT_SAFE) { + player->displayClientMessage("You may not rest now, there are monsters nearby"/*"tile.bed.notSafe"*/); + } + return true; +} + +void BedTile::setOccupied( Level* level, int x, int y, int z, bool occupied ) { + int data = level->getData(x, y, z); + if(occupied) { + data |= OCCUPIED_DATA; + } else { + data &= ~OCCUPIED_DATA; + } + level->setData(x, y, z, data); +} + +int BedTile::getTexture( int face, int data ) { + if(face == Facing::DOWN) { + return Tile::wood->tex; + } + int direction = getDirection(data); + int tileFacing = Direction::RELATIVE_DIRECTION_FACING[direction][face]; + if (isHeadPiece(data)) { + if (tileFacing == Facing::NORTH) { + return tex + 2 + 16; + } + if (tileFacing == Facing::EAST || tileFacing == Facing::WEST) { + return tex + 1 + 16; + } + return tex + 1; + } else { + if (tileFacing == Facing::SOUTH) { + return tex - 1 + 16; + } + if (tileFacing == Facing::EAST || tileFacing == Facing::WEST) { + return tex + 16; + } + return tex; + } +} + +int BedTile::getRenderShape() { + return Tile::SHAPE_BED; +} + +bool BedTile::isCubeShaped() { + return false; +} + +bool BedTile::isSolidRender() { + return false; +} + +void BedTile::neighborChanged( Level* level, int x, int y, int z, int type ) { + int data = level->getData(x, y, z); + int direction = getDirection(data); + if(isHeadPiece(data)) { + if(level->getTile(x - HEAD_DIRECTION_OFFSETS[direction][0], y, z - HEAD_DIRECTION_OFFSETS[direction][1]) != id) { + level->setTile(x, y, z, 0); + } + } else { + if(level->getTile(x + HEAD_DIRECTION_OFFSETS[direction][0], y, z + HEAD_DIRECTION_OFFSETS[direction][1]) != id) { + level->setTile(x, y, z, 0); + if(!level->isClientSide) { + //spawnResources(level, x, y, z, data, 1); + popResource(level, x, y, z, ItemInstance(Item::bed)); + } + } + } +} + +int BedTile::getResource( int data, Random* random ) { + if(isHeadPiece(data)) { + return 0; + } + return Item::bed->id; +} + +bool BedTile::findStandUpPosition( Level* level, int x, int y, int z, int skipCount, Pos& position) { + int data = level->getData(x, y, z); + int direction = DirectionalTile::getDirection(data); + for(int step = 0; step <= 1; ++step) { + int startX = x - BedTile::HEAD_DIRECTION_OFFSETS[direction][0] * step - 1; + int startZ = z - BedTile::HEAD_DIRECTION_OFFSETS[direction][1] * step - 1; + int endX = startX + 2; + int endZ = startZ + 2; + for(int standX = startX; standX <= endX; ++standX) { + for (int standZ = startZ; standZ <= endZ; ++standZ) { + if (level->isSolidBlockingTile(standX, y - 1, standZ) && level->isEmptyTile(standX, y, standZ) && level->isEmptyTile(standX, y + 1, standZ)) { + if (skipCount > 0) { + skipCount--; + continue; + } + position = Pos(standX, y, standZ); + return true; + } + } + } + } + return false; +} + +void BedTile::spawnResources( Level* level, int x, int y, int z, int data, float odds ) { + if(!isHeadPiece(data)) { + //super::spawnResources(level, x, y, z, data, odds); + popResource(level, x, y, z, ItemInstance(Item::bed)); + } +} + +void BedTile::updateShape( LevelSource* level, int x, int y, int z ) { + setShape(); +} + +int BedTile::getRenderLayer() { + return Tile::RENDERLAYER_ALPHATEST; +} +void BedTile::setShape() { + super::setShape(0, 0, 0, 1, 9.0f / 16.0f, 1); +} + +bool BedTile::isHeadPiece( int data ) { + return (data & HEAD_PIECE_DATA) != 0; +} + +bool BedTile::isOccupied( int data ) { + return (data & OCCUPIED_DATA) != 0; +} diff --git a/src/world/level/tile/BedTile.h b/src/world/level/tile/BedTile.hpp similarity index 92% rename from src/world/level/tile/BedTile.h rename to src/world/level/tile/BedTile.hpp index 1c5655c..0fad81b 100755 --- a/src/world/level/tile/BedTile.h +++ b/src/world/level/tile/BedTile.hpp @@ -1,7 +1,7 @@ #pragma once -#include "DirectionalTile.h" -#include "../material/Material.h" +#include "DirectionalTile.hpp" +#include "world/level/material/Material.hpp" class Pos; class BedTile : public DirectionalTile diff --git a/src/world/level/tile/BookshelfTile.h b/src/world/level/tile/BookshelfTile.hpp similarity index 86% rename from src/world/level/tile/BookshelfTile.h rename to src/world/level/tile/BookshelfTile.hpp index 92c928c..e4f460a 100755 --- a/src/world/level/tile/BookshelfTile.h +++ b/src/world/level/tile/BookshelfTile.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.tile; -#include "../../item/Item.h" -#include "../material/Material.h" +#include "world/item/Item.hpp" +#include "world/level/material/Material.hpp" class BookshelfTile: public Tile { diff --git a/src/world/level/tile/Bush.h b/src/world/level/tile/Bush.hpp similarity index 95% rename from src/world/level/tile/Bush.h rename to src/world/level/tile/Bush.hpp index 7c7f060..88cc869 100755 --- a/src/world/level/tile/Bush.h +++ b/src/world/level/tile/Bush.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.tile; -#include "../Level.h" -#include "Tile.h" -#include "../material/Material.h" +#include "world/level/Level.hpp" +#include "Tile.hpp" +#include "world/level/material/Material.hpp" class Bush: public Tile { diff --git a/src/world/level/tile/CactusTile.h b/src/world/level/tile/CactusTile.hpp similarity index 93% rename from src/world/level/tile/CactusTile.h rename to src/world/level/tile/CactusTile.hpp index 80a4346..2357d29 100755 --- a/src/world/level/tile/CactusTile.h +++ b/src/world/level/tile/CactusTile.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level->tile; -//#include "world/damagesource/DamageSource.h" -#include "Tile.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../entity/Entity.h" -#include "../../phys/AABB.h" +//#include "world/damagesource/DamageSource.hpp" +#include "Tile.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/entity/Entity.hpp" +#include "world/phys/AABB.hpp" class Random; diff --git a/src/world/level/tile/CarriedTile.h b/src/world/level/tile/CarriedTile.hpp similarity index 86% rename from src/world/level/tile/CarriedTile.h rename to src/world/level/tile/CarriedTile.hpp index 7917942..78c0b4e 100755 --- a/src/world/level/tile/CarriedTile.h +++ b/src/world/level/tile/CarriedTile.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" -#include "Tile.h" +#include "Tile.hpp" class CarriedTile: public Tile { diff --git a/src/world/level/tile/ChestTile.cpp b/src/world/level/tile/ChestTile.cpp index adc4137..4679067 100755 --- a/src/world/level/tile/ChestTile.cpp +++ b/src/world/level/tile/ChestTile.cpp @@ -1,321 +1,321 @@ -#include "ChestTile.h" -#include "entity/ChestTileEntity.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../Facing.h" -#include "../../entity/item/ItemEntity.h" - -ChestTile::ChestTile( int id ) -: super(id, Material::wood) -{ - tex = 10 + 16; - const float m = 0.025f; - setShape(m, 0, m, 1-m, 1-m-m, 1-m); -} - -bool ChestTile::isSolidRender() -{ - return false; -} - -bool ChestTile::isCubeShaped() -{ - return false; -} - -int ChestTile::getRenderShape() -{ - return super::getRenderShape(); - //return Tile::SHAPE_ENTITYTILE_ANIMATED; -} - -void ChestTile::onPlace( Level* level, int x, int y, int z ) -{ - super::onPlace(level, x, y, z); - recalcLockDir(level, x, y, z); - - //@fullchest - //int n = level->getTile(x, y, z - 1); // face = 2 - //int s = level->getTile(x, y, z + 1); // face = 3 - //int w = level->getTile(x - 1, y, z); // face = 4 - //int e = level->getTile(x + 1, y, z); // face = 5 - //if (n == id) recalcLockDir(level, x, y, z - 1); - //if (s == id) recalcLockDir(level, x, y, z + 1); - //if (w == id) recalcLockDir(level, x - 1, y, z); - //if (e == id) recalcLockDir(level, x + 1, y, z); -} - -void ChestTile::setPlacedBy( Level* level, int x, int y, int z, Mob* by ) -{ - int n = level->getTile(x, y, z - 1); // face = 2 - int s = level->getTile(x, y, z + 1); // face = 3 - int w = level->getTile(x - 1, y, z); // face = 4 - int e = level->getTile(x + 1, y, z); // face = 5 - - int facing = 0; - int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5f)) & 3; - - if (dir == 0) facing = Facing::NORTH; - if (dir == 1) facing = Facing::EAST; - if (dir == 2) facing = Facing::SOUTH; - if (dir == 3) facing = Facing::WEST; - - if (n != id && s != id && w != id && e != id) { - level->setData(x, y, z, facing); - } else { - if ((n == id || s == id) && (facing == Facing::WEST || facing == Facing::EAST)) { - if (n == id) level->setData(x, y, z - 1, facing); - else level->setData(x, y, z + 1, facing); - level->setData(x, y, z, facing); - } - if ((w == id || e == id) && (facing == Facing::NORTH || facing == Facing::SOUTH)) { - if (w == id) level->setData(x - 1, y, z, facing); - else level->setData(x + 1, y, z, facing); - level->setData(x, y, z, facing); - } - } -} - -void ChestTile::recalcLockDir( Level* level, int x, int y, int z ) -{ - if (level->isClientSide) - return; - - int n = level->getTile(x, y, z - 1); // face = 2 - int s = level->getTile(x, y, z + 1); // face = 3 - int w = level->getTile(x - 1, y, z); // face = 4 - int e = level->getTile(x + 1, y, z); // face = 5 - - // Long! - //@fullchest - int lockDir = 4; - /* - if (n == id || s == id) { - int w2 = level->getTile(x - 1, y, n == id ? z - 1 : z + 1); - int e2 = level->getTile(x + 1, y, n == id ? z - 1 : z + 1); - - lockDir = 5; - - int otherDir = -1; - if (n == id) otherDir = level->getData(x, y, z - 1); - else otherDir = level->getData(x, y, z + 1); - if (otherDir == 4) lockDir = 4; - - if ((Tile::solid[w] || Tile::solid[w2]) && !Tile::solid[e] && !Tile::solid[e2]) lockDir = 5; - if ((Tile::solid[e] || Tile::solid[e2]) && !Tile::solid[w] && !Tile::solid[w2]) lockDir = 4; - } else if (w == id || e == id) { - int n2 = level->getTile(w == id ? x - 1 : x + 1, y, z - 1); - int s2 = level->getTile(w == id ? x - 1 : x + 1, y, z + 1); - - lockDir = 3; - int otherDir = -1; - if (w == id) otherDir = level->getData(x - 1, y, z); - else otherDir = level->getData(x + 1, y, z); - if (otherDir == 2) lockDir = 2; - - if ((Tile::solid[n] || Tile::solid[n2]) && !Tile::solid[s] && !Tile::solid[s2]) lockDir = 3; - if ((Tile::solid[s] || Tile::solid[s2]) && !Tile::solid[n] && !Tile::solid[n2]) lockDir = 2; - } else */ { - lockDir = level->getData(x, y, z); - if ((lockDir == Facing::NORTH && Tile::solid[n]) - || (lockDir == Facing::SOUTH && Tile::solid[s]) - || (lockDir == Facing::WEST && Tile::solid[w]) - || (lockDir == Facing::EAST && Tile::solid[e])) { - if (Tile::solid[n] && !Tile::solid[s]) lockDir = Facing::SOUTH; - if (Tile::solid[s] && !Tile::solid[n]) lockDir = Facing::NORTH; - if (Tile::solid[w] && !Tile::solid[e]) lockDir = Facing::EAST; - if (Tile::solid[e] && !Tile::solid[w]) lockDir = Facing::WEST; - } - } - - level->setData(x, y, z, lockDir); -} - -int ChestTile::getTexture( LevelSource* level, int x, int y, int z, int face ) -{ - if (face == 1) return tex - 1; - if (face == 0) return tex - 1; - - /* - int n = level->getTile(x, y, z - 1); // face = 2 - int s = level->getTile(x, y, z + 1); // face = 3 - int w = level->getTile(x - 1, y, z); // face = 4 - int e = level->getTile(x + 1, y, z); // face = 5 - */ - - // Long! - //@fullchest - /* - if (n == id || s == id) { - if (face == 2 || face == 3) return tex; - int offs = 0; - if (n == id) { - offs = -1; - } - - int w2 = level->getTile(x - 1, y, n == id ? z - 1 : z + 1); - int e2 = level->getTile(x + 1, y, n == id ? z - 1 : z + 1); - - if (face == 4) offs = -1 - offs; - - int lockDir = 5; - if ((Tile::solid[w] || Tile::solid[w2]) && !Tile::solid[e] && !Tile::solid[e2]) lockDir = 5; - if ((Tile::solid[e] || Tile::solid[e2]) && !Tile::solid[w] && !Tile::solid[w2]) lockDir = 4; - return (face == lockDir ? tex + 16 : tex + 32) + offs; - } else if (w == id || e == id) { - if (face == 4 || face == 5) return tex; - int offs = 0; - if (w == id) { - offs = -1; - } - - int n2 = level->getTile(w == id ? x - 1 : x + 1, y, z - 1); - int s2 = level->getTile(w == id ? x - 1 : x + 1, y, z + 1); - - if (face == 3) offs = -1 - offs; - int lockDir = 3; - if ((Tile::solid[n] || Tile::solid[n2]) && !Tile::solid[s] && !Tile::solid[s2]) lockDir = 3; - if ((Tile::solid[s] || Tile::solid[s2]) && !Tile::solid[n] && !Tile::solid[n2]) lockDir = 2; - - return (face == lockDir ? tex + 16 : tex + 32) + offs; - } else { */ - //int lockDir = 3; - int lockDir = level->getData(x, y, z); - - /* - if ((lockDir == Facing::NORTH && Tile::solid[n]) - || (lockDir == Facing::SOUTH && Tile::solid[s]) - || (lockDir == Facing::WEST && Tile::solid[w]) - || (lockDir == Facing::EAST && Tile::solid[e])) { - if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; - if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; - if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; - if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; - } - */ - - /* - if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; - if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; - if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; - if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; - */ - return (face == lockDir)? tex + 1 : tex; -} - -int ChestTile::getTexture( int face ) -{ - if (face == 1) return tex - 1; - if (face == 0) return tex - 1; - if (face == 3) return tex + 1; - return tex; -} - -bool ChestTile::mayPlace( Level* level, int x, int y, int z, unsigned char face ) -{ - int chestCount = 0; - - if (level->getTile(x - 1, y, z) == id) chestCount++; - if (level->getTile(x + 1, y, z) == id) chestCount++; - if (level->getTile(x, y, z - 1) == id) chestCount++; - if (level->getTile(x, y, z + 1) == id) chestCount++; - - //@fullchest - if (chestCount > 0) return false; - - //if (isFullChest(level, x - 1, y, z)) return false; - //if (isFullChest(level, x + 1, y, z)) return false; - //if (isFullChest(level, x, y, z - 1)) return false; - //if (isFullChest(level, x, y, z + 1)) return false; - return true; -} - -void ChestTile::neighborChanged( Level* level, int x, int y, int z, int type ) -{ - super::neighborChanged(level, x, y, z, type); - recalcLockDir(level, x, y, z); - TileEntity* te = level->getTileEntity(x, y, z); - if (te != NULL) te->clearCache(); -} - -void ChestTile::onRemove( Level* level, int x, int y, int z ) -{ - if (!level->isClientSide) { - TileEntity* te = level->getTileEntity(x, y, z); - if (te != NULL && te->type == TileEntityType::Chest) { - Container* container = (ChestTileEntity*) te; - for (int i = 0; i < container->getContainerSize(); i++) { - ItemInstance* item = container->getItem(i); - if (item != NULL) { - float xo = random.nextFloat() * 0.8f + 0.1f; - float yo = random.nextFloat() * 0.8f + 0.1f; - float zo = random.nextFloat() * 0.8f + 0.1f; - - while (item->count > 0) { - int count = random.nextInt(21) + 10; - if (count > item->count) count = item->count; - item->count -= count; - ItemEntity* itemEntity = new ItemEntity(level, x + xo, y + yo, z + zo, ItemInstance(item->id, count, item->getAuxValue())); - float pow = 0.05f; - itemEntity->xd = (float) random.nextGaussian() * pow; - itemEntity->yd = (float) random.nextGaussian() * pow + 0.2f; - itemEntity->zd = (float) random.nextGaussian() * pow; - //if (item->hasTag()) { - // itemEntity->item->setTag((CompoundTag*) item->getTag()->copy()); - //} - level->addEntity(itemEntity); - } - } - } - } - } - super::onRemove(level, x, y, z); -} - -bool ChestTile::use( Level* level, int x, int y, int z, Player* player ) -{ - TileEntity* te = level->getTileEntity(x, y, z); - if (!TileEntity::isType(te, TileEntityType::Chest)) - return true; - - ChestTileEntity* chest = (ChestTileEntity*) te; - - if (level->isSolidBlockingTile(x, y + 1, z)) return true; - - // @fullchest - //if (level->getTile(x - 1, y, z) == id && (level->isSolidBlockingTile(x - 1, y + 1, z))) return true; - //if (level->getTile(x + 1, y, z) == id && (level->isSolidBlockingTile(x + 1, y + 1, z))) return true; - //if (level->getTile(x, y, z - 1) == id && (level->isSolidBlockingTile(x, y + 1, z - 1))) return true; - //if (level->getTile(x, y, z + 1) == id && (level->isSolidBlockingTile(x, y + 1, z + 1))) return true; - - //if (level->getTile(x - 1, y, z) == id) container = /*new*/ CompoundContainer("Large chest", (ChestTileEntity) level->getTileEntity(x - 1, y, z), container); - //if (level->getTile(x + 1, y, z) == id) container = /*new*/ CompoundContainer("Large chest", container, (ChestTileEntity) level->getTileEntity(x + 1, y, z)); - //if (level->getTile(x, y, z - 1) == id) container = /*new*/ CompoundContainer("Large chest", (ChestTileEntity) level->getTileEntity(x, y, z - 1), container); - //if (level->getTile(x, y, z + 1) == id) container = /*new*/ CompoundContainer("Large chest", container, (ChestTileEntity) level->getTileEntity(x, y, z + 1)); - - if (level->isClientSide) { - return true; - } - - player->openContainer(chest); - - return true; -} - -TileEntity* ChestTile::newTileEntity() -{ - return TileEntityFactory::createTileEntity(TileEntityType::Chest); -} - -bool ChestTile::isFullChest( Level* level, int x, int y, int z ) -{ - return false; //@fullchest - /* - if (level->getTile(x, y, z) != id) return false; - if (level->getTile(x - 1, y, z) == id) return true; - if (level->getTile(x + 1, y, z) == id) return true; - if (level->getTile(x, y, z - 1) == id) return true; - if (level->getTile(x, y, z + 1) == id) return true; - return false; - */ -} +#include "ChestTile.hpp" +#include "entity/ChestTileEntity.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/Facing.hpp" +#include "world/entity/item/ItemEntity.hpp" + +ChestTile::ChestTile( int id ) +: super(id, Material::wood) +{ + tex = 10 + 16; + const float m = 0.025f; + setShape(m, 0, m, 1-m, 1-m-m, 1-m); +} + +bool ChestTile::isSolidRender() +{ + return false; +} + +bool ChestTile::isCubeShaped() +{ + return false; +} + +int ChestTile::getRenderShape() +{ + return super::getRenderShape(); + //return Tile::SHAPE_ENTITYTILE_ANIMATED; +} + +void ChestTile::onPlace( Level* level, int x, int y, int z ) +{ + super::onPlace(level, x, y, z); + recalcLockDir(level, x, y, z); + + //@fullchest + //int n = level->getTile(x, y, z - 1); // face = 2 + //int s = level->getTile(x, y, z + 1); // face = 3 + //int w = level->getTile(x - 1, y, z); // face = 4 + //int e = level->getTile(x + 1, y, z); // face = 5 + //if (n == id) recalcLockDir(level, x, y, z - 1); + //if (s == id) recalcLockDir(level, x, y, z + 1); + //if (w == id) recalcLockDir(level, x - 1, y, z); + //if (e == id) recalcLockDir(level, x + 1, y, z); +} + +void ChestTile::setPlacedBy( Level* level, int x, int y, int z, Mob* by ) +{ + int n = level->getTile(x, y, z - 1); // face = 2 + int s = level->getTile(x, y, z + 1); // face = 3 + int w = level->getTile(x - 1, y, z); // face = 4 + int e = level->getTile(x + 1, y, z); // face = 5 + + int facing = 0; + int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5f)) & 3; + + if (dir == 0) facing = Facing::NORTH; + if (dir == 1) facing = Facing::EAST; + if (dir == 2) facing = Facing::SOUTH; + if (dir == 3) facing = Facing::WEST; + + if (n != id && s != id && w != id && e != id) { + level->setData(x, y, z, facing); + } else { + if ((n == id || s == id) && (facing == Facing::WEST || facing == Facing::EAST)) { + if (n == id) level->setData(x, y, z - 1, facing); + else level->setData(x, y, z + 1, facing); + level->setData(x, y, z, facing); + } + if ((w == id || e == id) && (facing == Facing::NORTH || facing == Facing::SOUTH)) { + if (w == id) level->setData(x - 1, y, z, facing); + else level->setData(x + 1, y, z, facing); + level->setData(x, y, z, facing); + } + } +} + +void ChestTile::recalcLockDir( Level* level, int x, int y, int z ) +{ + if (level->isClientSide) + return; + + int n = level->getTile(x, y, z - 1); // face = 2 + int s = level->getTile(x, y, z + 1); // face = 3 + int w = level->getTile(x - 1, y, z); // face = 4 + int e = level->getTile(x + 1, y, z); // face = 5 + + // Long! + //@fullchest + int lockDir = 4; + /* + if (n == id || s == id) { + int w2 = level->getTile(x - 1, y, n == id ? z - 1 : z + 1); + int e2 = level->getTile(x + 1, y, n == id ? z - 1 : z + 1); + + lockDir = 5; + + int otherDir = -1; + if (n == id) otherDir = level->getData(x, y, z - 1); + else otherDir = level->getData(x, y, z + 1); + if (otherDir == 4) lockDir = 4; + + if ((Tile::solid[w] || Tile::solid[w2]) && !Tile::solid[e] && !Tile::solid[e2]) lockDir = 5; + if ((Tile::solid[e] || Tile::solid[e2]) && !Tile::solid[w] && !Tile::solid[w2]) lockDir = 4; + } else if (w == id || e == id) { + int n2 = level->getTile(w == id ? x - 1 : x + 1, y, z - 1); + int s2 = level->getTile(w == id ? x - 1 : x + 1, y, z + 1); + + lockDir = 3; + int otherDir = -1; + if (w == id) otherDir = level->getData(x - 1, y, z); + else otherDir = level->getData(x + 1, y, z); + if (otherDir == 2) lockDir = 2; + + if ((Tile::solid[n] || Tile::solid[n2]) && !Tile::solid[s] && !Tile::solid[s2]) lockDir = 3; + if ((Tile::solid[s] || Tile::solid[s2]) && !Tile::solid[n] && !Tile::solid[n2]) lockDir = 2; + } else */ { + lockDir = level->getData(x, y, z); + if ((lockDir == Facing::NORTH && Tile::solid[n]) + || (lockDir == Facing::SOUTH && Tile::solid[s]) + || (lockDir == Facing::WEST && Tile::solid[w]) + || (lockDir == Facing::EAST && Tile::solid[e])) { + if (Tile::solid[n] && !Tile::solid[s]) lockDir = Facing::SOUTH; + if (Tile::solid[s] && !Tile::solid[n]) lockDir = Facing::NORTH; + if (Tile::solid[w] && !Tile::solid[e]) lockDir = Facing::EAST; + if (Tile::solid[e] && !Tile::solid[w]) lockDir = Facing::WEST; + } + } + + level->setData(x, y, z, lockDir); +} + +int ChestTile::getTexture( LevelSource* level, int x, int y, int z, int face ) +{ + if (face == 1) return tex - 1; + if (face == 0) return tex - 1; + + /* + int n = level->getTile(x, y, z - 1); // face = 2 + int s = level->getTile(x, y, z + 1); // face = 3 + int w = level->getTile(x - 1, y, z); // face = 4 + int e = level->getTile(x + 1, y, z); // face = 5 + */ + + // Long! + //@fullchest + /* + if (n == id || s == id) { + if (face == 2 || face == 3) return tex; + int offs = 0; + if (n == id) { + offs = -1; + } + + int w2 = level->getTile(x - 1, y, n == id ? z - 1 : z + 1); + int e2 = level->getTile(x + 1, y, n == id ? z - 1 : z + 1); + + if (face == 4) offs = -1 - offs; + + int lockDir = 5; + if ((Tile::solid[w] || Tile::solid[w2]) && !Tile::solid[e] && !Tile::solid[e2]) lockDir = 5; + if ((Tile::solid[e] || Tile::solid[e2]) && !Tile::solid[w] && !Tile::solid[w2]) lockDir = 4; + return (face == lockDir ? tex + 16 : tex + 32) + offs; + } else if (w == id || e == id) { + if (face == 4 || face == 5) return tex; + int offs = 0; + if (w == id) { + offs = -1; + } + + int n2 = level->getTile(w == id ? x - 1 : x + 1, y, z - 1); + int s2 = level->getTile(w == id ? x - 1 : x + 1, y, z + 1); + + if (face == 3) offs = -1 - offs; + int lockDir = 3; + if ((Tile::solid[n] || Tile::solid[n2]) && !Tile::solid[s] && !Tile::solid[s2]) lockDir = 3; + if ((Tile::solid[s] || Tile::solid[s2]) && !Tile::solid[n] && !Tile::solid[n2]) lockDir = 2; + + return (face == lockDir ? tex + 16 : tex + 32) + offs; + } else { */ + //int lockDir = 3; + int lockDir = level->getData(x, y, z); + + /* + if ((lockDir == Facing::NORTH && Tile::solid[n]) + || (lockDir == Facing::SOUTH && Tile::solid[s]) + || (lockDir == Facing::WEST && Tile::solid[w]) + || (lockDir == Facing::EAST && Tile::solid[e])) { + if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; + if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; + if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; + if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; + } + */ + + /* + if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; + if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; + if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; + if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; + */ + return (face == lockDir)? tex + 1 : tex; +} + +int ChestTile::getTexture( int face ) +{ + if (face == 1) return tex - 1; + if (face == 0) return tex - 1; + if (face == 3) return tex + 1; + return tex; +} + +bool ChestTile::mayPlace( Level* level, int x, int y, int z, unsigned char face ) +{ + int chestCount = 0; + + if (level->getTile(x - 1, y, z) == id) chestCount++; + if (level->getTile(x + 1, y, z) == id) chestCount++; + if (level->getTile(x, y, z - 1) == id) chestCount++; + if (level->getTile(x, y, z + 1) == id) chestCount++; + + //@fullchest + if (chestCount > 0) return false; + + //if (isFullChest(level, x - 1, y, z)) return false; + //if (isFullChest(level, x + 1, y, z)) return false; + //if (isFullChest(level, x, y, z - 1)) return false; + //if (isFullChest(level, x, y, z + 1)) return false; + return true; +} + +void ChestTile::neighborChanged( Level* level, int x, int y, int z, int type ) +{ + super::neighborChanged(level, x, y, z, type); + recalcLockDir(level, x, y, z); + TileEntity* te = level->getTileEntity(x, y, z); + if (te != NULL) te->clearCache(); +} + +void ChestTile::onRemove( Level* level, int x, int y, int z ) +{ + if (!level->isClientSide) { + TileEntity* te = level->getTileEntity(x, y, z); + if (te != NULL && te->type == TileEntityType::Chest) { + Container* container = (ChestTileEntity*) te; + for (int i = 0; i < container->getContainerSize(); i++) { + ItemInstance* item = container->getItem(i); + if (item != NULL) { + float xo = random.nextFloat() * 0.8f + 0.1f; + float yo = random.nextFloat() * 0.8f + 0.1f; + float zo = random.nextFloat() * 0.8f + 0.1f; + + while (item->count > 0) { + int count = random.nextInt(21) + 10; + if (count > item->count) count = item->count; + item->count -= count; + ItemEntity* itemEntity = new ItemEntity(level, x + xo, y + yo, z + zo, ItemInstance(item->id, count, item->getAuxValue())); + float pow = 0.05f; + itemEntity->xd = (float) random.nextGaussian() * pow; + itemEntity->yd = (float) random.nextGaussian() * pow + 0.2f; + itemEntity->zd = (float) random.nextGaussian() * pow; + //if (item->hasTag()) { + // itemEntity->item->setTag((CompoundTag*) item->getTag()->copy()); + //} + level->addEntity(itemEntity); + } + } + } + } + } + super::onRemove(level, x, y, z); +} + +bool ChestTile::use( Level* level, int x, int y, int z, Player* player ) +{ + TileEntity* te = level->getTileEntity(x, y, z); + if (!TileEntity::isType(te, TileEntityType::Chest)) + return true; + + ChestTileEntity* chest = (ChestTileEntity*) te; + + if (level->isSolidBlockingTile(x, y + 1, z)) return true; + + // @fullchest + //if (level->getTile(x - 1, y, z) == id && (level->isSolidBlockingTile(x - 1, y + 1, z))) return true; + //if (level->getTile(x + 1, y, z) == id && (level->isSolidBlockingTile(x + 1, y + 1, z))) return true; + //if (level->getTile(x, y, z - 1) == id && (level->isSolidBlockingTile(x, y + 1, z - 1))) return true; + //if (level->getTile(x, y, z + 1) == id && (level->isSolidBlockingTile(x, y + 1, z + 1))) return true; + + //if (level->getTile(x - 1, y, z) == id) container = /*new*/ CompoundContainer("Large chest", (ChestTileEntity) level->getTileEntity(x - 1, y, z), container); + //if (level->getTile(x + 1, y, z) == id) container = /*new*/ CompoundContainer("Large chest", container, (ChestTileEntity) level->getTileEntity(x + 1, y, z)); + //if (level->getTile(x, y, z - 1) == id) container = /*new*/ CompoundContainer("Large chest", (ChestTileEntity) level->getTileEntity(x, y, z - 1), container); + //if (level->getTile(x, y, z + 1) == id) container = /*new*/ CompoundContainer("Large chest", container, (ChestTileEntity) level->getTileEntity(x, y, z + 1)); + + if (level->isClientSide) { + return true; + } + + player->openContainer(chest); + + return true; +} + +TileEntity* ChestTile::newTileEntity() +{ + return TileEntityFactory::createTileEntity(TileEntityType::Chest); +} + +bool ChestTile::isFullChest( Level* level, int x, int y, int z ) +{ + return false; //@fullchest + /* + if (level->getTile(x, y, z) != id) return false; + if (level->getTile(x - 1, y, z) == id) return true; + if (level->getTile(x + 1, y, z) == id) return true; + if (level->getTile(x, y, z - 1) == id) return true; + if (level->getTile(x, y, z + 1) == id) return true; + return false; + */ +} diff --git a/src/world/level/tile/ChestTile.h b/src/world/level/tile/ChestTile.hpp similarity index 94% rename from src/world/level/tile/ChestTile.h rename to src/world/level/tile/ChestTile.hpp index a3fe65e..5ed271a 100755 --- a/src/world/level/tile/ChestTile.h +++ b/src/world/level/tile/ChestTile.hpp @@ -1,11 +1,11 @@ #pragma once -#include "EntityTile.h" +#include "EntityTile.hpp" class Level; class LevelSource; class Mob; -#include "../../../util/Random.h" +#include "util/Random.hpp" //package net.minecraft.world.level->tile; diff --git a/src/world/level/tile/ClayTile.h b/src/world/level/tile/ClayTile.hpp similarity index 78% rename from src/world/level/tile/ClayTile.h rename to src/world/level/tile/ClayTile.hpp index bc7bd38..d7125ef 100755 --- a/src/world/level/tile/ClayTile.h +++ b/src/world/level/tile/ClayTile.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" -#include "Tile.h" +#include "Tile.hpp" class ClayTile: public Tile { public: diff --git a/src/world/level/tile/ClothTile.h b/src/world/level/tile/ClothTile.hpp similarity index 94% rename from src/world/level/tile/ClothTile.h rename to src/world/level/tile/ClothTile.hpp index 4337565..47e1fa0 100755 --- a/src/world/level/tile/ClothTile.h +++ b/src/world/level/tile/ClothTile.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.tile; -#include "../material/Material.h" +#include "world/level/material/Material.hpp" class ClothTile: public Tile { diff --git a/src/world/level/tile/CropTile.cpp b/src/world/level/tile/CropTile.cpp index 8dfad0f..b83bfdc 100755 --- a/src/world/level/tile/CropTile.cpp +++ b/src/world/level/tile/CropTile.cpp @@ -1,113 +1,113 @@ -#include "CropTile.h" -#include "Tile.h" -#include "../../entity/item/ItemEntity.h" - -CropTile::CropTile( int id, int tex ) : super(id, tex) { - this->tex = tex; - setTicking(true); - float ss = 0.5f; - setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); -} - -void CropTile::tick( Level* level, int x, int y, int z, Random* random ) { - super::tick(level, x, y, z, random); - if(level->getRawBrightness(x, y, z) >= Level::MAX_BRIGHTNESS - 6) { - int age = level->getData(x, y, z); - if(age < 7) { - float growthSpeed = getGrowthSpeed(level, x, y, z); - if(random->nextInt(int(25 / growthSpeed)) == 0) { - age++; - level->setData(x, y, z, age); - } - } - } -} - -void CropTile::growCropsToMax( Level* level, int x, int y, int z ) { - level->setData(x, y, z, 7); -} - -float CropTile::getGrowthSpeed( Level* level, int x, int y, int z ) { - float speed = 1; - - int n = level->getTile(x, y, z - 1); - int s = level->getTile(x, y, z + 1); - int w = level->getTile(x - 1, y, z); - int e = level->getTile(x + 1, y, z); - - int d0 = level->getTile(x - 1, y, z - 1); - int d1 = level->getTile(x + 1, y, z - 1); - int d2 = level->getTile(x + 1, y, z + 1); - int d3 = level->getTile(x - 1, y, z + 1); - - bool horizontal = w == this->id || e == this->id; - bool vertical = n == this->id || s == this->id; - bool diagonal = d0 == this->id || d1 == this->id || d2 == this->id || d3 == this->id; - - for (int xx = x - 1; xx <= x + 1; xx++) { - for (int zz = z - 1; zz <= z + 1; zz++) { - int t = level->getTile(xx, y - 1, zz); - - float tileSpeed = 0; - if (t == Tile::farmland->id) { - tileSpeed = 1; - if (level->getData(xx, y - 1, zz) > 0) tileSpeed = 3; - } - - if (xx != x || zz != z) tileSpeed /= 4; - - speed += tileSpeed; - } - } - if (diagonal || (horizontal && vertical)) speed /= 2; - - return speed; -} - -int CropTile::getTexture( LevelSource* level, int x, int y, int z, int face ) { - int data = level->getData(x, y, z); - if (data < 0) data = 7; - return tex + data; -} - -int CropTile::getTexture( int face, int data ) { - if (data < 0) data = 7; - return tex + data; -} - -int CropTile::getRenderShape() { - return Tile::SHAPE_ROWS; -} -void CropTile::spawnResources( Level* level, int x, int y, int z, int data, float odds ) { - super::spawnResources(level, x, y, z, data, odds); - - if (level->isClientSide) { - return; - } - int count = 3; - for (int i = 0; i < count; i++) { - if (level->random.nextInt(5 * 3) > data) continue; - float s = 0.7f; - float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; - float yo = level->random.nextFloat() * s + (1 - s) * 0.5f; - float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; - ItemEntity* item = new ItemEntity(level, float(x) + xo, float(y) + yo, float(z) + zo, ItemInstance(Item::seeds_wheat)); - item->throwTime = 10; - level->addEntity(item); - } -} - -int CropTile::getResource( int data, Random* random ) { - if (data == 7) { - return Item::wheat->id; - } - return -1; -} - -int CropTile::getResourceCount( Random* random ) { - return 1; -} - -bool CropTile::mayPlaceOn( int tile ) { - return tile == Tile::farmland->id; -} +#include "CropTile.hpp" +#include "Tile.hpp" +#include "world/entity/item/ItemEntity.hpp" + +CropTile::CropTile( int id, int tex ) : super(id, tex) { + this->tex = tex; + setTicking(true); + float ss = 0.5f; + setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); +} + +void CropTile::tick( Level* level, int x, int y, int z, Random* random ) { + super::tick(level, x, y, z, random); + if(level->getRawBrightness(x, y, z) >= Level::MAX_BRIGHTNESS - 6) { + int age = level->getData(x, y, z); + if(age < 7) { + float growthSpeed = getGrowthSpeed(level, x, y, z); + if(random->nextInt(int(25 / growthSpeed)) == 0) { + age++; + level->setData(x, y, z, age); + } + } + } +} + +void CropTile::growCropsToMax( Level* level, int x, int y, int z ) { + level->setData(x, y, z, 7); +} + +float CropTile::getGrowthSpeed( Level* level, int x, int y, int z ) { + float speed = 1; + + int n = level->getTile(x, y, z - 1); + int s = level->getTile(x, y, z + 1); + int w = level->getTile(x - 1, y, z); + int e = level->getTile(x + 1, y, z); + + int d0 = level->getTile(x - 1, y, z - 1); + int d1 = level->getTile(x + 1, y, z - 1); + int d2 = level->getTile(x + 1, y, z + 1); + int d3 = level->getTile(x - 1, y, z + 1); + + bool horizontal = w == this->id || e == this->id; + bool vertical = n == this->id || s == this->id; + bool diagonal = d0 == this->id || d1 == this->id || d2 == this->id || d3 == this->id; + + for (int xx = x - 1; xx <= x + 1; xx++) { + for (int zz = z - 1; zz <= z + 1; zz++) { + int t = level->getTile(xx, y - 1, zz); + + float tileSpeed = 0; + if (t == Tile::farmland->id) { + tileSpeed = 1; + if (level->getData(xx, y - 1, zz) > 0) tileSpeed = 3; + } + + if (xx != x || zz != z) tileSpeed /= 4; + + speed += tileSpeed; + } + } + if (diagonal || (horizontal && vertical)) speed /= 2; + + return speed; +} + +int CropTile::getTexture( LevelSource* level, int x, int y, int z, int face ) { + int data = level->getData(x, y, z); + if (data < 0) data = 7; + return tex + data; +} + +int CropTile::getTexture( int face, int data ) { + if (data < 0) data = 7; + return tex + data; +} + +int CropTile::getRenderShape() { + return Tile::SHAPE_ROWS; +} +void CropTile::spawnResources( Level* level, int x, int y, int z, int data, float odds ) { + super::spawnResources(level, x, y, z, data, odds); + + if (level->isClientSide) { + return; + } + int count = 3; + for (int i = 0; i < count; i++) { + if (level->random.nextInt(5 * 3) > data) continue; + float s = 0.7f; + float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; + float yo = level->random.nextFloat() * s + (1 - s) * 0.5f; + float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; + ItemEntity* item = new ItemEntity(level, float(x) + xo, float(y) + yo, float(z) + zo, ItemInstance(Item::seeds_wheat)); + item->throwTime = 10; + level->addEntity(item); + } +} + +int CropTile::getResource( int data, Random* random ) { + if (data == 7) { + return Item::wheat->id; + } + return -1; +} + +int CropTile::getResourceCount( Random* random ) { + return 1; +} + +bool CropTile::mayPlaceOn( int tile ) { + return tile == Tile::farmland->id; +} diff --git a/src/world/level/tile/CropTile.h b/src/world/level/tile/CropTile.hpp similarity index 96% rename from src/world/level/tile/CropTile.h rename to src/world/level/tile/CropTile.hpp index e4095a1..bd2db19 100755 --- a/src/world/level/tile/CropTile.h +++ b/src/world/level/tile/CropTile.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Bush.h" +#include "Bush.hpp" class CropTile : public Bush { diff --git a/src/world/level/tile/DirectionalTile.h b/src/world/level/tile/DirectionalTile.hpp similarity index 95% rename from src/world/level/tile/DirectionalTile.h rename to src/world/level/tile/DirectionalTile.hpp index e7fd027..72f8553 100755 --- a/src/world/level/tile/DirectionalTile.h +++ b/src/world/level/tile/DirectionalTile.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Tile.h" +#include "Tile.hpp" class Material; class DirectionalTile : public Tile { public: diff --git a/src/world/level/tile/DirtTile.h b/src/world/level/tile/DirtTile.hpp similarity index 74% rename from src/world/level/tile/DirtTile.h rename to src/world/level/tile/DirtTile.hpp index 6043cbf..7982109 100755 --- a/src/world/level/tile/DirtTile.h +++ b/src/world/level/tile/DirtTile.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.tile; -#include "../material/Material.h" +#include "world/level/material/Material.hpp" -#include "Tile.h" +#include "Tile.hpp" class DirtTile: public Tile { diff --git a/src/world/level/tile/DoorTile.cpp b/src/world/level/tile/DoorTile.cpp index 7aea82f..1f88cce 100755 --- a/src/world/level/tile/DoorTile.cpp +++ b/src/world/level/tile/DoorTile.cpp @@ -1,242 +1,242 @@ -#include "DoorTile.h" -#include "LevelEvent.h" -#include "../Level.h" -#include "../../item/Item.h" -#include "../../entity/player/Player.h" - -DoorTile::DoorTile(int id, const Material* material) -: super(id, material) -{ - tex = 1 + 6 * 16; - if (material == Material::metal) tex++; - - float r = 0.5f; - float h = 1.0f; - super::setShape(0.5f - r, 0, 0.5f - r, 0.5f + r, h, 0.5f + r); -} - -int DoorTile::getTexture(LevelSource* level, int x, int y, int z, int face) { - if (face == 0 || face == 1) return tex; - - int compositeData = getCompositeData(level, x, y, z); - int texture = tex; - if ((compositeData & C_IS_UPPER_MASK) != 0) texture -= 16; - - int dir = compositeData & C_DIR_MASK; - bool isOpen = (compositeData & C_OPEN_MASK) != 0; - if (isOpen) { - if (dir == 0 && face == 2) texture = -texture; - else if (dir == 1 && face == 5) texture = -texture; - else if (dir == 2 && face == 3) texture = -texture; - else if (dir == 3 && face == 4) texture = -texture; - } else { - if (dir == 0 && face == 5) texture = -texture; - else if (dir == 1 && face == 3) texture = -texture; - else if (dir == 2 && face == 4) texture = -texture; - else if (dir == 3 && face == 2) texture = -texture; - if ((compositeData & C_RIGHT_HINGE_MASK) != 0) texture = -texture; - } - - return texture; -} - -bool DoorTile::blocksLight() { - return false; -} - -bool DoorTile::isSolidRender() { - return false; -} - -bool DoorTile::isCubeShaped() { - return false; -} - -int DoorTile::getRenderShape() { - return Tile::SHAPE_DOOR; -} - -int DoorTile::getRenderLayer() { - return Tile::RENDERLAYER_ALPHATEST; -} - -AABB DoorTile::getTileAABB(Level* level, int x, int y, int z) { - updateShape(level, x, y, z); - return super::getTileAABB(level, x, y, z); -} - -AABB* DoorTile::getAABB(Level* level, int x, int y, int z) { - updateShape(level, x, y, z); - return super::getAABB(level, x, y, z); -} - -void DoorTile::updateShape(LevelSource* level, int x, int y, int z) { - setShape(getCompositeData(level, x, y, z)); -} - -void DoorTile::setShape(int compositeData) { - float r = 3 / 16.0f; - super::setShape(0, 0, 0, 1, 2, 1); - int dir = compositeData & C_DIR_MASK; - bool open = (compositeData & C_OPEN_MASK) != 0; - bool hasRightHinge = (compositeData & C_RIGHT_HINGE_MASK) != 0; - if (dir == 0) { - if (open) { - if (!hasRightHinge) super::setShape(0, 0, 0, 1, 1, r); - else super::setShape(0, 0, 1 - r, 1, 1, 1); - } else super::setShape(0, 0, 0, r, 1, 1); - } else if (dir == 1) { - if (open) { - if (!hasRightHinge) super::setShape(1 - r, 0, 0, 1, 1, 1); - else super::setShape(0, 0, 0, r, 1, 1); - } else super::setShape(0, 0, 0, 1, 1, r); - } else if (dir == 2) { - if (open) { - if (!hasRightHinge) super::setShape(0, 0, 1 - r, 1, 1, 1); - else super::setShape(0, 0, 0, 1, 1, r); - } else super::setShape(1 - r, 0, 0, 1, 1, 1); - } else if (dir == 3) { - if (open) { - if (!hasRightHinge) super::setShape(0, 0, 0, r, 1, 1); - else super::setShape(1 - r, 0, 0, 1, 1, 1); - } else super::setShape(0, 0, 1 - r, 1, 1, 1); - } -} - -void DoorTile::attack(Level* level, int x, int y, int z, Player* player) { - use(level, x, y, z, player); -} - -bool DoorTile::use(Level* level, int x, int y, int z, Player* player) { - if (material == Material::metal) return true; - - int compositeData = getCompositeData(level, x, y, z); - int lowerData = compositeData & C_LOWER_DATA_MASK; - lowerData ^= 4; - if ((compositeData & C_IS_UPPER_MASK) == 0) { - level->setData(x, y, z, lowerData); - level->setTilesDirty(x, y, z, x, y, z); - } else { - level->setData(x, y - 1, z, lowerData); - level->setTilesDirty(x, y - 1, z, x, y, z); - } - - level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); - return true; -} - -bool DoorTile::isOpen( LevelSource* level, int x, int y, int z ) -{ - return (getCompositeData(level, x, y, z) & C_OPEN_MASK) != 0; -} - -void DoorTile::setOpen(Level* level, int x, int y, int z, bool shouldOpen) { - int compositeData = getCompositeData(level, x, y, z); - bool isOpen = (compositeData & C_OPEN_MASK) != 0; - if (isOpen == shouldOpen) return; - - int lowerData = compositeData & C_LOWER_DATA_MASK; - lowerData ^= 4; - if ((compositeData & C_IS_UPPER_MASK) == 0) { - level->setData(x, y, z, lowerData); - level->setTilesDirty(x, y, z, x, y, z); - } else { - level->setData(x, y - 1, z, lowerData); - level->setTilesDirty(x, y - 1, z, x, y, z); - } - - level->levelEvent(NULL, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); -} - -void DoorTile::neighborChanged(Level* level, int x, int y, int z, int type) { - int data = level->getData(x, y, z); - if ((data & UPPER_BIT) == 0) { - bool spawn = false; - if (level->getTile(x, y + 1, z) != id) { - level->setTile(x, y, z, 0); - spawn = true; - } - if (!level->isSolidBlockingTile(x, y - 1, z)) { - level->setTile(x, y, z, 0); - spawn = true; - if (level->getTile(x, y + 1, z) == id) { - level->setTile(x, y + 1, z, 0); - } - } - if (spawn) { - if (!level->isClientSide) { - // use default chance (1.0) so the drop always occurs - spawnResources(level, x, y, z, data); - } - } else { - bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z); - if ((signal || ((type > 0 && Tile::tiles[type]->isSignalSource()) || type == 0)) && type != id) { - setOpen(level, x, y, z, signal); - } - } - } else { - // upper half: removal should not drop a second door. the - // lower half neighbour handler takes care of spawning the item - // whenever the door is broken from either end. - if (level->getTile(x, y - 1, z) != id) { - level->setTile(x, y, z, 0); - // no resource spawn here - } - if (type > 0 && type != id) { - neighborChanged(level, x, y - 1, z, type); - } - } -} - -int DoorTile::getResource(int data, Random* random) { - // only the lower half should return a resource ID; the upper half - // itself never drops anything and playerDestroy suppresses spawning - // from the top. This prevents duplicate drops if the bottom half is - // mined. - if ((data & UPPER_BIT) != 0) return 0; - if (material == Material::metal) return Item::door_iron->id; - return Item::door_wood->id; -} - -HitResult DoorTile::clip(Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b) { - updateShape(level, xt, yt, zt); - return super::clip(level, xt, yt, zt, a, b); -} - -// override to prevent double-dropping when top half is directly mined -void DoorTile::playerDestroy(Level* level, Player* player, int x, int y, int z, int data) { - if ((data & UPPER_BIT) == 0) { - // only let the lower half handle the actual spawning - super::playerDestroy(level, player, x, y, z, data); - } -} - -int DoorTile::getDir(LevelSource* level, int x, int y, int z) { - return getCompositeData(level, x, y, z) & C_DIR_MASK; -} - -bool DoorTile::mayPlace(Level* level, int x, int y, int z, unsigned char face) { - if (y >= Level::DEPTH - 1) return false; - - return (level->isSolidBlockingTile(x, y - 1, z) - && super::mayPlace(level, x, y, z) - && super::mayPlace(level, x, y + 1, z)); -} - -int DoorTile::getCompositeData( LevelSource* level, int x, int y, int z ) { - int data = level->getData(x, y, z); - bool isUpper = (data & UPPER_BIT) != 0; - int lowerData; - int upperData; - if (isUpper) { - lowerData = level->getData(x, y - 1, z); - upperData = data; - } else { - lowerData = data; - upperData = level->getData(x, y + 1, z); - } - - // bits: dir, dir, open/closed, isUpper, isRightHinge - bool isRightHinge = (upperData & 1) != 0; - return lowerData & C_LOWER_DATA_MASK | (isUpper ? 8 : 0) | (isRightHinge ? 16 : 0); -} +#include "DoorTile.hpp" +#include "LevelEvent.hpp" +#include "world/level/Level.hpp" +#include "world/item/Item.hpp" +#include "world/entity/player/Player.hpp" + +DoorTile::DoorTile(int id, const Material* material) +: super(id, material) +{ + tex = 1 + 6 * 16; + if (material == Material::metal) tex++; + + float r = 0.5f; + float h = 1.0f; + super::setShape(0.5f - r, 0, 0.5f - r, 0.5f + r, h, 0.5f + r); +} + +int DoorTile::getTexture(LevelSource* level, int x, int y, int z, int face) { + if (face == 0 || face == 1) return tex; + + int compositeData = getCompositeData(level, x, y, z); + int texture = tex; + if ((compositeData & C_IS_UPPER_MASK) != 0) texture -= 16; + + int dir = compositeData & C_DIR_MASK; + bool isOpen = (compositeData & C_OPEN_MASK) != 0; + if (isOpen) { + if (dir == 0 && face == 2) texture = -texture; + else if (dir == 1 && face == 5) texture = -texture; + else if (dir == 2 && face == 3) texture = -texture; + else if (dir == 3 && face == 4) texture = -texture; + } else { + if (dir == 0 && face == 5) texture = -texture; + else if (dir == 1 && face == 3) texture = -texture; + else if (dir == 2 && face == 4) texture = -texture; + else if (dir == 3 && face == 2) texture = -texture; + if ((compositeData & C_RIGHT_HINGE_MASK) != 0) texture = -texture; + } + + return texture; +} + +bool DoorTile::blocksLight() { + return false; +} + +bool DoorTile::isSolidRender() { + return false; +} + +bool DoorTile::isCubeShaped() { + return false; +} + +int DoorTile::getRenderShape() { + return Tile::SHAPE_DOOR; +} + +int DoorTile::getRenderLayer() { + return Tile::RENDERLAYER_ALPHATEST; +} + +AABB DoorTile::getTileAABB(Level* level, int x, int y, int z) { + updateShape(level, x, y, z); + return super::getTileAABB(level, x, y, z); +} + +AABB* DoorTile::getAABB(Level* level, int x, int y, int z) { + updateShape(level, x, y, z); + return super::getAABB(level, x, y, z); +} + +void DoorTile::updateShape(LevelSource* level, int x, int y, int z) { + setShape(getCompositeData(level, x, y, z)); +} + +void DoorTile::setShape(int compositeData) { + float r = 3 / 16.0f; + super::setShape(0, 0, 0, 1, 2, 1); + int dir = compositeData & C_DIR_MASK; + bool open = (compositeData & C_OPEN_MASK) != 0; + bool hasRightHinge = (compositeData & C_RIGHT_HINGE_MASK) != 0; + if (dir == 0) { + if (open) { + if (!hasRightHinge) super::setShape(0, 0, 0, 1, 1, r); + else super::setShape(0, 0, 1 - r, 1, 1, 1); + } else super::setShape(0, 0, 0, r, 1, 1); + } else if (dir == 1) { + if (open) { + if (!hasRightHinge) super::setShape(1 - r, 0, 0, 1, 1, 1); + else super::setShape(0, 0, 0, r, 1, 1); + } else super::setShape(0, 0, 0, 1, 1, r); + } else if (dir == 2) { + if (open) { + if (!hasRightHinge) super::setShape(0, 0, 1 - r, 1, 1, 1); + else super::setShape(0, 0, 0, 1, 1, r); + } else super::setShape(1 - r, 0, 0, 1, 1, 1); + } else if (dir == 3) { + if (open) { + if (!hasRightHinge) super::setShape(0, 0, 0, r, 1, 1); + else super::setShape(1 - r, 0, 0, 1, 1, 1); + } else super::setShape(0, 0, 1 - r, 1, 1, 1); + } +} + +void DoorTile::attack(Level* level, int x, int y, int z, Player* player) { + use(level, x, y, z, player); +} + +bool DoorTile::use(Level* level, int x, int y, int z, Player* player) { + if (material == Material::metal) return true; + + int compositeData = getCompositeData(level, x, y, z); + int lowerData = compositeData & C_LOWER_DATA_MASK; + lowerData ^= 4; + if ((compositeData & C_IS_UPPER_MASK) == 0) { + level->setData(x, y, z, lowerData); + level->setTilesDirty(x, y, z, x, y, z); + } else { + level->setData(x, y - 1, z, lowerData); + level->setTilesDirty(x, y - 1, z, x, y, z); + } + + level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); + return true; +} + +bool DoorTile::isOpen( LevelSource* level, int x, int y, int z ) +{ + return (getCompositeData(level, x, y, z) & C_OPEN_MASK) != 0; +} + +void DoorTile::setOpen(Level* level, int x, int y, int z, bool shouldOpen) { + int compositeData = getCompositeData(level, x, y, z); + bool isOpen = (compositeData & C_OPEN_MASK) != 0; + if (isOpen == shouldOpen) return; + + int lowerData = compositeData & C_LOWER_DATA_MASK; + lowerData ^= 4; + if ((compositeData & C_IS_UPPER_MASK) == 0) { + level->setData(x, y, z, lowerData); + level->setTilesDirty(x, y, z, x, y, z); + } else { + level->setData(x, y - 1, z, lowerData); + level->setTilesDirty(x, y - 1, z, x, y, z); + } + + level->levelEvent(NULL, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); +} + +void DoorTile::neighborChanged(Level* level, int x, int y, int z, int type) { + int data = level->getData(x, y, z); + if ((data & UPPER_BIT) == 0) { + bool spawn = false; + if (level->getTile(x, y + 1, z) != id) { + level->setTile(x, y, z, 0); + spawn = true; + } + if (!level->isSolidBlockingTile(x, y - 1, z)) { + level->setTile(x, y, z, 0); + spawn = true; + if (level->getTile(x, y + 1, z) == id) { + level->setTile(x, y + 1, z, 0); + } + } + if (spawn) { + if (!level->isClientSide) { + // use default chance (1.0) so the drop always occurs + spawnResources(level, x, y, z, data); + } + } else { + bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z); + if ((signal || ((type > 0 && Tile::tiles[type]->isSignalSource()) || type == 0)) && type != id) { + setOpen(level, x, y, z, signal); + } + } + } else { + // upper half: removal should not drop a second door. the + // lower half neighbour handler takes care of spawning the item + // whenever the door is broken from either end. + if (level->getTile(x, y - 1, z) != id) { + level->setTile(x, y, z, 0); + // no resource spawn here + } + if (type > 0 && type != id) { + neighborChanged(level, x, y - 1, z, type); + } + } +} + +int DoorTile::getResource(int data, Random* random) { + // only the lower half should return a resource ID; the upper half + // itself never drops anything and playerDestroy suppresses spawning + // from the top. This prevents duplicate drops if the bottom half is + // mined. + if ((data & UPPER_BIT) != 0) return 0; + if (material == Material::metal) return Item::door_iron->id; + return Item::door_wood->id; +} + +HitResult DoorTile::clip(Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b) { + updateShape(level, xt, yt, zt); + return super::clip(level, xt, yt, zt, a, b); +} + +// override to prevent double-dropping when top half is directly mined +void DoorTile::playerDestroy(Level* level, Player* player, int x, int y, int z, int data) { + if ((data & UPPER_BIT) == 0) { + // only let the lower half handle the actual spawning + super::playerDestroy(level, player, x, y, z, data); + } +} + +int DoorTile::getDir(LevelSource* level, int x, int y, int z) { + return getCompositeData(level, x, y, z) & C_DIR_MASK; +} + +bool DoorTile::mayPlace(Level* level, int x, int y, int z, unsigned char face) { + if (y >= Level::DEPTH - 1) return false; + + return (level->isSolidBlockingTile(x, y - 1, z) + && super::mayPlace(level, x, y, z) + && super::mayPlace(level, x, y + 1, z)); +} + +int DoorTile::getCompositeData( LevelSource* level, int x, int y, int z ) { + int data = level->getData(x, y, z); + bool isUpper = (data & UPPER_BIT) != 0; + int lowerData; + int upperData; + if (isUpper) { + lowerData = level->getData(x, y - 1, z); + upperData = data; + } else { + lowerData = data; + upperData = level->getData(x, y + 1, z); + } + + // bits: dir, dir, open/closed, isUpper, isRightHinge + bool isRightHinge = (upperData & 1) != 0; + return lowerData & C_LOWER_DATA_MASK | (isUpper ? 8 : 0) | (isRightHinge ? 16 : 0); +} diff --git a/src/world/level/tile/DoorTile.h b/src/world/level/tile/DoorTile.hpp similarity index 95% rename from src/world/level/tile/DoorTile.h rename to src/world/level/tile/DoorTile.hpp index b49c985..49fe150 100755 --- a/src/world/level/tile/DoorTile.h +++ b/src/world/level/tile/DoorTile.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level->tile; -#include "Tile.h" -#include "../material/Material.h" -#include "../../../util/Random.h" +#include "Tile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Random.hpp" class Item; class Level; diff --git a/src/world/level/tile/EntityTile.cpp b/src/world/level/tile/EntityTile.cpp index 9c1f266..6a90430 100755 --- a/src/world/level/tile/EntityTile.cpp +++ b/src/world/level/tile/EntityTile.cpp @@ -1,38 +1,38 @@ -#include "EntityTile.h" -#include "entity/TileEntity.h" -#include "../Level.h" -#include "../material/Material.h" - -void EntityTile::onPlace( Level* level, int x, int y, int z ) -{ - super::onPlace(level, x, y, z); - level->setTileEntity(x, y, z, newTileEntity()); -} - -void EntityTile::onRemove( Level* level, int x, int y, int z ) -{ - super::onRemove(level, x, y, z); - level->removeTileEntity(x, y, z); -} - -void EntityTile::triggerEvent( Level* level, int x, int y, int z, int b0, int b1 ) -{ - super::triggerEvent(level, x, y, z, b0, b1); - TileEntity* te = level->getTileEntity(x, y, z); - if (te != NULL) { - te->triggerEvent(b0, b1); - } -} - -EntityTile::EntityTile( int id, const Material* material ) -: super(id, material) -{ - isEntityTile[this->id] = true; -} - -EntityTile::EntityTile( int id, int tex, const Material* material ) -: super(id, tex, material) -{ - isEntityTile[this->id] = true; -} - +#include "EntityTile.hpp" +#include "entity/TileEntity.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" + +void EntityTile::onPlace( Level* level, int x, int y, int z ) +{ + super::onPlace(level, x, y, z); + level->setTileEntity(x, y, z, newTileEntity()); +} + +void EntityTile::onRemove( Level* level, int x, int y, int z ) +{ + super::onRemove(level, x, y, z); + level->removeTileEntity(x, y, z); +} + +void EntityTile::triggerEvent( Level* level, int x, int y, int z, int b0, int b1 ) +{ + super::triggerEvent(level, x, y, z, b0, b1); + TileEntity* te = level->getTileEntity(x, y, z); + if (te != NULL) { + te->triggerEvent(b0, b1); + } +} + +EntityTile::EntityTile( int id, const Material* material ) +: super(id, material) +{ + isEntityTile[this->id] = true; +} + +EntityTile::EntityTile( int id, int tex, const Material* material ) +: super(id, tex, material) +{ + isEntityTile[this->id] = true; +} + diff --git a/src/world/level/tile/EntityTile.h b/src/world/level/tile/EntityTile.hpp similarity index 96% rename from src/world/level/tile/EntityTile.h rename to src/world/level/tile/EntityTile.hpp index 0b70697..b2fe62e 100755 --- a/src/world/level/tile/EntityTile.h +++ b/src/world/level/tile/EntityTile.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level->tile; -#include "Tile.h" +#include "Tile.hpp" class Level; class TileEntity; diff --git a/src/world/level/tile/FarmTile.h b/src/world/level/tile/FarmTile.hpp similarity index 95% rename from src/world/level/tile/FarmTile.h rename to src/world/level/tile/FarmTile.hpp index 5a8a7cb..7978228 100755 --- a/src/world/level/tile/FarmTile.h +++ b/src/world/level/tile/FarmTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" +#include "Tile.hpp" class FarmTile: public Tile { public: diff --git a/src/world/level/tile/FenceGateTile.h b/src/world/level/tile/FenceGateTile.hpp similarity index 88% rename from src/world/level/tile/FenceGateTile.h rename to src/world/level/tile/FenceGateTile.hpp index 2c3304b..5666fbd 100755 --- a/src/world/level/tile/FenceGateTile.h +++ b/src/world/level/tile/FenceGateTile.hpp @@ -1,14 +1,14 @@ #pragma once -#include "Tile.h" -#include "LevelEvent.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../Direction.h" -#include "../../entity/Mob.h" -#include "../../entity/player/Player.h" -#include "../../phys/AABB.h" -#include "../../../util/Mth.h" +#include "Tile.hpp" +#include "LevelEvent.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/Direction.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/player/Player.hpp" +#include "world/phys/AABB.hpp" +#include "util/Mth.hpp" class FenceGateTile: public Tile { diff --git a/src/world/level/tile/FenceTile.h b/src/world/level/tile/FenceTile.hpp similarity index 96% rename from src/world/level/tile/FenceTile.h rename to src/world/level/tile/FenceTile.hpp index 68df66d..627434c 100755 --- a/src/world/level/tile/FenceTile.h +++ b/src/world/level/tile/FenceTile.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level->tile; -#include "Tile.h" +#include "Tile.hpp" /* import net.minecraft.world.level->* */ -#include "../material/Material.h" -#include "../../phys/AABB.h" +#include "world/level/material/Material.hpp" +#include "world/phys/AABB.hpp" class FenceTile: public Tile { diff --git a/src/world/level/tile/FireTile.h b/src/world/level/tile/FireTile.hpp similarity index 98% rename from src/world/level/tile/FireTile.h rename to src/world/level/tile/FireTile.hpp index 13ee6bf..6ce197c 100755 --- a/src/world/level/tile/FireTile.h +++ b/src/world/level/tile/FireTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" +#include "Tile.hpp" class FireTile: public Tile { diff --git a/src/world/level/tile/FurnaceTile.cpp b/src/world/level/tile/FurnaceTile.cpp index b50c7ad..ac3c08a 100755 --- a/src/world/level/tile/FurnaceTile.cpp +++ b/src/world/level/tile/FurnaceTile.cpp @@ -1,175 +1,175 @@ -#include "FurnaceTile.h" -#include "entity/FurnaceTileEntity.h" -#include "../material/Material.h" -#include "../../Facing.h" -#include "../../entity/Mob.h" -#include "../../entity/item/ItemEntity.h" -#include "../../entity/player/Player.h" -#include "../../item/ItemInstance.h" -#include "../../../util/Mth.h" -#include "../LevelSource.h" -#include "../Level.h" - -bool FurnaceTile::noDrop = false; - -FurnaceTile::FurnaceTile( int id, bool lit ) -: super(id, Material::stone), - lit(lit) -{ - tex = 13 + 16 * 2; -} - -int FurnaceTile::getResource( int data, Random* random/*, int playerBonusLevel*/ ) -{ - return Tile::furnace->id; -} - -void FurnaceTile::onPlace( Level* level, int x, int y, int z ) -{ - super::onPlace(level, x, y, z); - recalcLockDir(level, x, y, z); -} - -int FurnaceTile::getTexture( LevelSource* level, int x, int y, int z, int face ) -{ - if (face == 1) return tex + 17; - if (face == 0) return tex + 17; - - int lockDir = level->getData(x, y, z); - - if (face != lockDir) return tex; - if (lit) return tex + 16; - else return tex - 1; -} - -int FurnaceTile::getTexture( int face ) -{ - if (face == 1) return tex + 17; - if (face == 0) return tex + 17; - if (face == 3) return tex - 1; - return tex; -} - -void FurnaceTile::animateTick( Level* level, int xt, int yt, int zt, Random* random ) -{ - if (!lit) return; - - int dir = level->getData(xt, yt, zt); - - float x = xt + 0.5f; - float y = yt + 0.0f + random->nextFloat() * 6 / 16.0f; - float z = zt + 0.5f; - float r = 0.52f; - float ss = random->nextFloat() * 0.6f - 0.3f; - - if (dir == 4) { - level->addParticle(PARTICLETYPE(smoke), x - r, y, z + ss, 0, 0, 0); - level->addParticle(PARTICLETYPE(flame), x - r, y, z + ss, 0, 0, 0); - } else if (dir == 5) { - level->addParticle(PARTICLETYPE(smoke), x + r, y, z + ss, 0, 0, 0); - level->addParticle(PARTICLETYPE(flame), x + r, y, z + ss, 0, 0, 0); - } else if (dir == 2) { - level->addParticle(PARTICLETYPE(smoke), x + ss, y, z - r, 0, 0, 0); - level->addParticle(PARTICLETYPE(flame), x + ss, y, z - r, 0, 0, 0); - } else if (dir == 3) { - level->addParticle(PARTICLETYPE(smoke), x + ss, y, z + r, 0, 0, 0); - level->addParticle(PARTICLETYPE(flame), x + ss, y, z + r, 0, 0, 0); - } -} - -bool FurnaceTile::use( Level* level, int x, int y, int z, Player* player ) -{ - if (level->isClientSide) - return true; - - FurnaceTileEntity* furnace = static_cast(level->getTileEntity(x, y, z)); - if (furnace != NULL) player->openFurnace(furnace); - return true; -} - -/*static*/ -void FurnaceTile::setLit( bool lit, Level* level, int x, int y, int z ) -{ - int data = level->getData(x, y, z); - TileEntity* te = level->getTileEntity(x, y, z); - - noDrop = true; - if (lit) level->setTile(x, y, z, Tile::furnace_lit->id); - else level->setTile(x, y, z, Tile::furnace->id); - noDrop = false; - - level->setData(x, y, z, data); - - LOGI("lit? %d @ %d, %d, %d\n", lit, x, y, z); - - if (te != NULL) { - te->clearRemoved(); - level->setTileEntity(x, y, z, te); - } -} - -TileEntity* FurnaceTile::newTileEntity() -{ - return TileEntityFactory::createTileEntity(TileEntityType::Furnace); -} - -void FurnaceTile::setPlacedBy( Level* level, int x, int y, int z, Mob* by ) -{ - int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5f)) & 3; - - if (dir == 0) level->setData(x, y, z, Facing::NORTH); - if (dir == 1) level->setData(x, y, z, Facing::EAST); - if (dir == 2) level->setData(x, y, z, Facing::SOUTH); - if (dir == 3) level->setData(x, y, z, Facing::WEST); -} - -void FurnaceTile::onRemove( Level* level, int x, int y, int z ) -{ - if (!noDrop && !level->isClientSide) { - FurnaceTileEntity* container = (FurnaceTileEntity*) level->getTileEntity(x, y, z); - if (container != NULL) { - for (int i = 0; i < container->getContainerSize(); i++) { - ItemInstance* item = container->getItem(i); - if (item) { - float xo = random.nextFloat() * 0.8f + 0.1f; - float yo = random.nextFloat() * 0.8f + 0.1f; - float zo = random.nextFloat() * 0.8f + 0.1f; - - while (item->count > 0) { - int count = random.nextInt(21) + 10; - if (count > item->count) count = item->count; - item->count -= count; - - ItemEntity* itemEntity = new ItemEntity(level, x + xo, y + yo, z + zo, ItemInstance(item->id, count, item->getAuxValue())); - float pow = 0.05f; - itemEntity->xd = random.nextGaussian() * pow; - itemEntity->yd = random.nextGaussian() * pow + 0.2f; - itemEntity->zd = random.nextGaussian() * pow; - level->addEntity(itemEntity); - } - } - } - } - } - super::onRemove(level, x, y, z); -} - -void FurnaceTile::recalcLockDir( Level* level, int x, int y, int z ) -{ - if (level->isClientSide) { - return; - } - - int n = level->getTile(x, y, z - 1); // face = 2 - int s = level->getTile(x, y, z + 1); // face = 3 - int w = level->getTile(x - 1, y, z); // face = 4 - int e = level->getTile(x + 1, y, z); // face = 5 - - int lockDir = 3; - if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; - else if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; - else if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; - else if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; - - level->setData(x, y, z, lockDir); -} +#include "FurnaceTile.hpp" +#include "entity/FurnaceTileEntity.hpp" +#include "world/level/material/Material.hpp" +#include "world/Facing.hpp" +#include "world/entity/Mob.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/ItemInstance.hpp" +#include "util/Mth.hpp" +#include "world/level/LevelSource.hpp" +#include "world/level/Level.hpp" + +bool FurnaceTile::noDrop = false; + +FurnaceTile::FurnaceTile( int id, bool lit ) +: super(id, Material::stone), + lit(lit) +{ + tex = 13 + 16 * 2; +} + +int FurnaceTile::getResource( int data, Random* random/*, int playerBonusLevel*/ ) +{ + return Tile::furnace->id; +} + +void FurnaceTile::onPlace( Level* level, int x, int y, int z ) +{ + super::onPlace(level, x, y, z); + recalcLockDir(level, x, y, z); +} + +int FurnaceTile::getTexture( LevelSource* level, int x, int y, int z, int face ) +{ + if (face == 1) return tex + 17; + if (face == 0) return tex + 17; + + int lockDir = level->getData(x, y, z); + + if (face != lockDir) return tex; + if (lit) return tex + 16; + else return tex - 1; +} + +int FurnaceTile::getTexture( int face ) +{ + if (face == 1) return tex + 17; + if (face == 0) return tex + 17; + if (face == 3) return tex - 1; + return tex; +} + +void FurnaceTile::animateTick( Level* level, int xt, int yt, int zt, Random* random ) +{ + if (!lit) return; + + int dir = level->getData(xt, yt, zt); + + float x = xt + 0.5f; + float y = yt + 0.0f + random->nextFloat() * 6 / 16.0f; + float z = zt + 0.5f; + float r = 0.52f; + float ss = random->nextFloat() * 0.6f - 0.3f; + + if (dir == 4) { + level->addParticle(PARTICLETYPE(smoke), x - r, y, z + ss, 0, 0, 0); + level->addParticle(PARTICLETYPE(flame), x - r, y, z + ss, 0, 0, 0); + } else if (dir == 5) { + level->addParticle(PARTICLETYPE(smoke), x + r, y, z + ss, 0, 0, 0); + level->addParticle(PARTICLETYPE(flame), x + r, y, z + ss, 0, 0, 0); + } else if (dir == 2) { + level->addParticle(PARTICLETYPE(smoke), x + ss, y, z - r, 0, 0, 0); + level->addParticle(PARTICLETYPE(flame), x + ss, y, z - r, 0, 0, 0); + } else if (dir == 3) { + level->addParticle(PARTICLETYPE(smoke), x + ss, y, z + r, 0, 0, 0); + level->addParticle(PARTICLETYPE(flame), x + ss, y, z + r, 0, 0, 0); + } +} + +bool FurnaceTile::use( Level* level, int x, int y, int z, Player* player ) +{ + if (level->isClientSide) + return true; + + FurnaceTileEntity* furnace = static_cast(level->getTileEntity(x, y, z)); + if (furnace != NULL) player->openFurnace(furnace); + return true; +} + +/*static*/ +void FurnaceTile::setLit( bool lit, Level* level, int x, int y, int z ) +{ + int data = level->getData(x, y, z); + TileEntity* te = level->getTileEntity(x, y, z); + + noDrop = true; + if (lit) level->setTile(x, y, z, Tile::furnace_lit->id); + else level->setTile(x, y, z, Tile::furnace->id); + noDrop = false; + + level->setData(x, y, z, data); + + LOGI("lit? %d @ %d, %d, %d\n", lit, x, y, z); + + if (te != NULL) { + te->clearRemoved(); + level->setTileEntity(x, y, z, te); + } +} + +TileEntity* FurnaceTile::newTileEntity() +{ + return TileEntityFactory::createTileEntity(TileEntityType::Furnace); +} + +void FurnaceTile::setPlacedBy( Level* level, int x, int y, int z, Mob* by ) +{ + int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5f)) & 3; + + if (dir == 0) level->setData(x, y, z, Facing::NORTH); + if (dir == 1) level->setData(x, y, z, Facing::EAST); + if (dir == 2) level->setData(x, y, z, Facing::SOUTH); + if (dir == 3) level->setData(x, y, z, Facing::WEST); +} + +void FurnaceTile::onRemove( Level* level, int x, int y, int z ) +{ + if (!noDrop && !level->isClientSide) { + FurnaceTileEntity* container = (FurnaceTileEntity*) level->getTileEntity(x, y, z); + if (container != NULL) { + for (int i = 0; i < container->getContainerSize(); i++) { + ItemInstance* item = container->getItem(i); + if (item) { + float xo = random.nextFloat() * 0.8f + 0.1f; + float yo = random.nextFloat() * 0.8f + 0.1f; + float zo = random.nextFloat() * 0.8f + 0.1f; + + while (item->count > 0) { + int count = random.nextInt(21) + 10; + if (count > item->count) count = item->count; + item->count -= count; + + ItemEntity* itemEntity = new ItemEntity(level, x + xo, y + yo, z + zo, ItemInstance(item->id, count, item->getAuxValue())); + float pow = 0.05f; + itemEntity->xd = random.nextGaussian() * pow; + itemEntity->yd = random.nextGaussian() * pow + 0.2f; + itemEntity->zd = random.nextGaussian() * pow; + level->addEntity(itemEntity); + } + } + } + } + } + super::onRemove(level, x, y, z); +} + +void FurnaceTile::recalcLockDir( Level* level, int x, int y, int z ) +{ + if (level->isClientSide) { + return; + } + + int n = level->getTile(x, y, z - 1); // face = 2 + int s = level->getTile(x, y, z + 1); // face = 3 + int w = level->getTile(x - 1, y, z); // face = 4 + int e = level->getTile(x + 1, y, z); // face = 5 + + int lockDir = 3; + if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; + else if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; + else if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; + else if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; + + level->setData(x, y, z, lockDir); +} diff --git a/src/world/level/tile/FurnaceTile.h b/src/world/level/tile/FurnaceTile.hpp similarity index 94% rename from src/world/level/tile/FurnaceTile.h rename to src/world/level/tile/FurnaceTile.hpp index 641c017..a0120ea 100755 --- a/src/world/level/tile/FurnaceTile.h +++ b/src/world/level/tile/FurnaceTile.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level->tile; -#include "EntityTile.h" -#include "../../../util/Random.h" +#include "EntityTile.hpp" +#include "util/Random.hpp" class Level; class Mob; diff --git a/src/world/level/tile/GlassTile.h b/src/world/level/tile/GlassTile.hpp similarity index 79% rename from src/world/level/tile/GlassTile.h rename to src/world/level/tile/GlassTile.hpp index 4dfe810..651a1ae 100755 --- a/src/world/level/tile/GlassTile.h +++ b/src/world/level/tile/GlassTile.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.tile; -#include "HalfTransparentTile.h" -#include "../material/Material.h" -#include "../../../util/Random.h" +#include "HalfTransparentTile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Random.hpp" class GlassTile: public HalfTransparentTile { diff --git a/src/world/level/tile/GrassTile.cpp b/src/world/level/tile/GrassTile.cpp index 7a293ea..6259669 100755 --- a/src/world/level/tile/GrassTile.cpp +++ b/src/world/level/tile/GrassTile.cpp @@ -1,54 +1,54 @@ -#include "GrassTile.h" -#include "../material/Material.h" -#include "../../entity/item/ItemEntity.h" - -GrassTile::GrassTile(int id) -: super(id, Material::dirt) -{ - tex = 3; - setTicking(true); -} - -int GrassTile::getTexture( LevelSource* level, int x, int y, int z, int face ) { - if (face == 1) return 0; - if (face == 0) return 2; - const Material* above = level->getMaterial(x, y + 1, z); - if (above == Material::topSnow || above == Material::snow) return 4 * 16 + 4; - else return 3; -} - -int GrassTile::getTexture( int face, int data ) { - if (face == 1) return 0; - if (face == 0) return 2; - return 3; -} - -int GrassTile::getColor( LevelSource* level, int x, int y, int z ) { - //level.getBiomeSource().getBiomeBlock(x, z, 1, 1); - //float temp = level.getBiomeSource().temperatures[0]; - //float rain = level.getBiomeSource().downfalls[0]; - - return 0x339933;//GrassColor.get(temp, rain); -} - -void GrassTile::tick( Level* level, int x, int y, int z, Random* random ) { - if (level->isClientSide) return; - - if (level->getRawBrightness(x, y + 1, z) < MIN_BRIGHTNESS && level->getMaterial(x, y + 1, z)->blocksLight()) { - if (random->nextInt(4) != 0) return; - level->setTile(x, y, z, Tile::dirt->id); - } else { - if (level->getRawBrightness(x, y + 1, z) >= level->MAX_BRIGHTNESS - 6) { - int xt = x + random->nextInt(3) - 1; - int yt = y + random->nextInt(5) - 3; - int zt = z + random->nextInt(3) - 1; - if (level->getTile(xt, yt, zt) == Tile::dirt->id && level->getRawBrightness(xt, yt + 1, zt) >= MIN_BRIGHTNESS && !level->getMaterial(xt, yt + 1, zt)->blocksLight()) { - level->setTile(xt, yt, zt, Tile::grass->id); - } - } - } -} - -int GrassTile::getResource( int data, Random* random ) { - return Tile::dirt->getResource(0, random); -} +#include "GrassTile.hpp" +#include "world/level/material/Material.hpp" +#include "world/entity/item/ItemEntity.hpp" + +GrassTile::GrassTile(int id) +: super(id, Material::dirt) +{ + tex = 3; + setTicking(true); +} + +int GrassTile::getTexture( LevelSource* level, int x, int y, int z, int face ) { + if (face == 1) return 0; + if (face == 0) return 2; + const Material* above = level->getMaterial(x, y + 1, z); + if (above == Material::topSnow || above == Material::snow) return 4 * 16 + 4; + else return 3; +} + +int GrassTile::getTexture( int face, int data ) { + if (face == 1) return 0; + if (face == 0) return 2; + return 3; +} + +int GrassTile::getColor( LevelSource* level, int x, int y, int z ) { + //level.getBiomeSource().getBiomeBlock(x, z, 1, 1); + //float temp = level.getBiomeSource().temperatures[0]; + //float rain = level.getBiomeSource().downfalls[0]; + + return 0x339933;//GrassColor.get(temp, rain); +} + +void GrassTile::tick( Level* level, int x, int y, int z, Random* random ) { + if (level->isClientSide) return; + + if (level->getRawBrightness(x, y + 1, z) < MIN_BRIGHTNESS && level->getMaterial(x, y + 1, z)->blocksLight()) { + if (random->nextInt(4) != 0) return; + level->setTile(x, y, z, Tile::dirt->id); + } else { + if (level->getRawBrightness(x, y + 1, z) >= level->MAX_BRIGHTNESS - 6) { + int xt = x + random->nextInt(3) - 1; + int yt = y + random->nextInt(5) - 3; + int zt = z + random->nextInt(3) - 1; + if (level->getTile(xt, yt, zt) == Tile::dirt->id && level->getRawBrightness(xt, yt + 1, zt) >= MIN_BRIGHTNESS && !level->getMaterial(xt, yt + 1, zt)->blocksLight()) { + level->setTile(xt, yt, zt, Tile::grass->id); + } + } + } +} + +int GrassTile::getResource( int data, Random* random ) { + return Tile::dirt->getResource(0, random); +} diff --git a/src/world/level/tile/GrassTile.h b/src/world/level/tile/GrassTile.hpp similarity index 73% rename from src/world/level/tile/GrassTile.h rename to src/world/level/tile/GrassTile.hpp index 299871c..22512f1 100755 --- a/src/world/level/tile/GrassTile.h +++ b/src/world/level/tile/GrassTile.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" -#include "../LevelSource.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" +#include "world/level/LevelSource.hpp" -#include "Tile.h" +#include "Tile.hpp" class GrassTile: public Tile { diff --git a/src/world/level/tile/GravelTile.h b/src/world/level/tile/GravelTile.hpp similarity index 77% rename from src/world/level/tile/GravelTile.h rename to src/world/level/tile/GravelTile.hpp index cde2c7f..22af0d2 100755 --- a/src/world/level/tile/GravelTile.h +++ b/src/world/level/tile/GravelTile.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" -#include "HeavyTile.h" +#include "HeavyTile.hpp" class GravelTile: public HeavyTile { diff --git a/src/world/level/tile/HalfTransparentTile.h b/src/world/level/tile/HalfTransparentTile.hpp similarity index 89% rename from src/world/level/tile/HalfTransparentTile.h rename to src/world/level/tile/HalfTransparentTile.hpp index 1094326..d4b01d3 100755 --- a/src/world/level/tile/HalfTransparentTile.h +++ b/src/world/level/tile/HalfTransparentTile.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.tile; -#include "../LevelSource.h" -#include "../material/Material.h" +#include "world/level/LevelSource.hpp" +#include "world/level/material/Material.hpp" class HalfTransparentTile: public Tile { bool allowSame; diff --git a/src/world/level/tile/HeavyTile.cpp b/src/world/level/tile/HeavyTile.cpp index 720f4f2..0ab8263 100755 --- a/src/world/level/tile/HeavyTile.cpp +++ b/src/world/level/tile/HeavyTile.cpp @@ -1,72 +1,72 @@ -#include "HeavyTile.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../entity/item/FallingTile.h" - -bool HeavyTile::instaFall = false; - -HeavyTile::HeavyTile( int id, int tex ) -: super(id, tex, Material::sand) -{ -} - -HeavyTile::HeavyTile( int id, int tex, const Material* material ) -: super(id, tex, material) -{ -} - -void HeavyTile::onPlace( Level* level, int x, int y, int z ) { - level->addToTickNextTick(x, y, z, id, getTickDelay(level)); -} - -void HeavyTile::neighborChanged( Level* level, int x, int y, int z, int type ) { - level->addToTickNextTick(x, y, z, id, getTickDelay(level)); -} - -void HeavyTile::tick( Level* level, int x, int y, int z, Random* random ) { - if (!level->isClientSide) { - checkSlide(level, x, y, z); - } -} - -int HeavyTile::getTickDelay( Level* level ) { - return 2; -} - -bool HeavyTile::isFree( Level* level, int x, int y, int z ) { - int t = level->getTile(x, y, z); - if (t == 0) return true; - if (t == ((Tile*)Tile::fire)->id) return true; - const Material* material = Tile::tiles[t]->material; - if (material == Material::water) return true; - if (material == Material::lava) return true; - return false; -} - -void HeavyTile::checkSlide( Level* level, int x, int y, int z ) { - int x2 = x; - int y2 = y; - int z2 = z; - if (isFree(level, x2, y2 - 1, z2) && y2 >= 0) { - int r = 32; - if (instaFall || !level->hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { - level->setTile(x, y, z, 0); - while (isFree(level, x, y - 1, z) && y > 0) - y--; - if (y > 0) { - level->setTile(x, y, z, id); - //level->setTileAndUpdate(x, y, z, id); - } - } else if (!level->isClientSide) { - FallingTile* e = new FallingTile(level, x + 0.5f, y + 0.5f, z + 0.5f, id, level->getData(x, y, z)); - falling(e); - level->addEntity(e); - } - } -} - -void HeavyTile::falling( FallingTile* entity ) { -} - -void HeavyTile::onLand( Level* level, int xt, int yt, int zt, int data ) { -} +#include "HeavyTile.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/entity/item/FallingTile.hpp" + +bool HeavyTile::instaFall = false; + +HeavyTile::HeavyTile( int id, int tex ) +: super(id, tex, Material::sand) +{ +} + +HeavyTile::HeavyTile( int id, int tex, const Material* material ) +: super(id, tex, material) +{ +} + +void HeavyTile::onPlace( Level* level, int x, int y, int z ) { + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); +} + +void HeavyTile::neighborChanged( Level* level, int x, int y, int z, int type ) { + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); +} + +void HeavyTile::tick( Level* level, int x, int y, int z, Random* random ) { + if (!level->isClientSide) { + checkSlide(level, x, y, z); + } +} + +int HeavyTile::getTickDelay( Level* level ) { + return 2; +} + +bool HeavyTile::isFree( Level* level, int x, int y, int z ) { + int t = level->getTile(x, y, z); + if (t == 0) return true; + if (t == ((Tile*)Tile::fire)->id) return true; + const Material* material = Tile::tiles[t]->material; + if (material == Material::water) return true; + if (material == Material::lava) return true; + return false; +} + +void HeavyTile::checkSlide( Level* level, int x, int y, int z ) { + int x2 = x; + int y2 = y; + int z2 = z; + if (isFree(level, x2, y2 - 1, z2) && y2 >= 0) { + int r = 32; + if (instaFall || !level->hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { + level->setTile(x, y, z, 0); + while (isFree(level, x, y - 1, z) && y > 0) + y--; + if (y > 0) { + level->setTile(x, y, z, id); + //level->setTileAndUpdate(x, y, z, id); + } + } else if (!level->isClientSide) { + FallingTile* e = new FallingTile(level, x + 0.5f, y + 0.5f, z + 0.5f, id, level->getData(x, y, z)); + falling(e); + level->addEntity(e); + } + } +} + +void HeavyTile::falling( FallingTile* entity ) { +} + +void HeavyTile::onLand( Level* level, int xt, int yt, int zt, int data ) { +} diff --git a/src/world/level/tile/HeavyTile.h b/src/world/level/tile/HeavyTile.hpp similarity index 97% rename from src/world/level/tile/HeavyTile.h rename to src/world/level/tile/HeavyTile.hpp index 9a2c189..269c5d1 100755 --- a/src/world/level/tile/HeavyTile.h +++ b/src/world/level/tile/HeavyTile.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.tile; -#include "Tile.h" +#include "Tile.hpp" class FallingTile; diff --git a/src/world/level/tile/IceTile.h b/src/world/level/tile/IceTile.hpp similarity index 87% rename from src/world/level/tile/IceTile.h rename to src/world/level/tile/IceTile.hpp index 82d2cd8..b7a3e88 100755 --- a/src/world/level/tile/IceTile.h +++ b/src/world/level/tile/IceTile.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.tile; -#include "Tile.h" -#include "../material/Material.h" -#include "../LightLayer.h" -#include "../../../util/Random.h" +#include "Tile.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/LightLayer.hpp" +#include "util/Random.hpp" class IceTile: public Tile { diff --git a/src/world/level/tile/InvisibleTile.h b/src/world/level/tile/InvisibleTile.hpp similarity index 92% rename from src/world/level/tile/InvisibleTile.h rename to src/world/level/tile/InvisibleTile.hpp index d0b41c5..5a556c0 100755 --- a/src/world/level/tile/InvisibleTile.h +++ b/src/world/level/tile/InvisibleTile.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Tile.h" +#include "Tile.hpp" class InvisibleTile : public Tile { diff --git a/src/world/level/tile/LadderTile.h b/src/world/level/tile/LadderTile.hpp similarity index 96% rename from src/world/level/tile/LadderTile.h rename to src/world/level/tile/LadderTile.hpp index 66d1619..98bd7d1 100755 --- a/src/world/level/tile/LadderTile.h +++ b/src/world/level/tile/LadderTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level->tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" +#include "Tile.hpp" class LadderTile: public Tile { diff --git a/src/world/level/tile/LeafTile.h b/src/world/level/tile/LeafTile.hpp similarity index 97% rename from src/world/level/tile/LeafTile.h rename to src/world/level/tile/LeafTile.hpp index e3c3ba0..24d3de0 100755 --- a/src/world/level/tile/LeafTile.h +++ b/src/world/level/tile/LeafTile.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.tile; -#include "TransparentTile.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../item/Item.h" -#include "../../item/ItemInstance.h" -#include "../FoliageColor.h" +#include "TransparentTile.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/item/Item.hpp" +#include "world/item/ItemInstance.hpp" +#include "world/level/FoliageColor.hpp" class Entity; diff --git a/src/world/level/tile/LevelEvent.h b/src/world/level/tile/LevelEvent.hpp similarity index 100% rename from src/world/level/tile/LevelEvent.h rename to src/world/level/tile/LevelEvent.hpp diff --git a/src/world/level/tile/LightGemTile.cpp b/src/world/level/tile/LightGemTile.cpp index ee7fc80..9218d4a 100755 --- a/src/world/level/tile/LightGemTile.cpp +++ b/src/world/level/tile/LightGemTile.cpp @@ -1,15 +1,15 @@ -#include "LightGemTile.h" -#include "../../../util/Random.h" -#include "../../item/Item.h" -LightGemTile::LightGemTile( int id, int tex, const Material* material ) -: super(id, tex, material) -{ } - -int LightGemTile::getResourceCount( Random* random ) { - return 2 + random->nextInt(3); -} - -int LightGemTile::getResource( int data, Random* random ) { - return Item::yellowDust->id; -} - +#include "LightGemTile.hpp" +#include "util/Random.hpp" +#include "world/item/Item.hpp" +LightGemTile::LightGemTile( int id, int tex, const Material* material ) +: super(id, tex, material) +{ } + +int LightGemTile::getResourceCount( Random* random ) { + return 2 + random->nextInt(3); +} + +int LightGemTile::getResource( int data, Random* random ) { + return Item::yellowDust->id; +} + diff --git a/src/world/level/tile/LightGemTile.h b/src/world/level/tile/LightGemTile.hpp similarity index 91% rename from src/world/level/tile/LightGemTile.h rename to src/world/level/tile/LightGemTile.hpp index d625cd1..a060f70 100755 --- a/src/world/level/tile/LightGemTile.h +++ b/src/world/level/tile/LightGemTile.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Tile.h" +#include "Tile.hpp" class LightGemTile : public Tile { typedef Tile super; public: diff --git a/src/world/level/tile/LiquidTile.h b/src/world/level/tile/LiquidTile.hpp similarity index 98% rename from src/world/level/tile/LiquidTile.h rename to src/world/level/tile/LiquidTile.hpp index 1c157cb..3d04913 100755 --- a/src/world/level/tile/LiquidTile.h +++ b/src/world/level/tile/LiquidTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" -#include "../Level.h" -#include "Tile.h" +#include "world/level/Level.hpp" +#include "Tile.hpp" /*abstract*/ class LiquidTile: public Tile diff --git a/src/world/level/tile/LiquidTileDynamic.h b/src/world/level/tile/LiquidTileDynamic.hpp similarity index 99% rename from src/world/level/tile/LiquidTileDynamic.h rename to src/world/level/tile/LiquidTileDynamic.hpp index 1a9eb2b..6dab12a 100755 --- a/src/world/level/tile/LiquidTileDynamic.h +++ b/src/world/level/tile/LiquidTileDynamic.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.tile; -#include "LiquidTile.h" -#include "../Level.h" +#include "LiquidTile.hpp" +#include "world/level/Level.hpp" class LiquidTileDynamic: public LiquidTile { diff --git a/src/world/level/tile/LiquidTileStatic.h b/src/world/level/tile/LiquidTileStatic.hpp similarity index 95% rename from src/world/level/tile/LiquidTileStatic.h rename to src/world/level/tile/LiquidTileStatic.hpp index ac8b7bc..8b29af7 100755 --- a/src/world/level/tile/LiquidTileStatic.h +++ b/src/world/level/tile/LiquidTileStatic.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.tile; -#include "LiquidTile.h" -#include "../Level.h" -#include "FireTile.h" +#include "LiquidTile.hpp" +#include "world/level/Level.hpp" +#include "FireTile.hpp" class LiquidTileStatic: public LiquidTile { diff --git a/src/world/level/tile/MelonTile.cpp b/src/world/level/tile/MelonTile.cpp index 9ea535b..b11e3d9 100755 --- a/src/world/level/tile/MelonTile.cpp +++ b/src/world/level/tile/MelonTile.cpp @@ -1,27 +1,27 @@ -#include "MelonTile.h" -#include "../material/Material.h" -#include "../../../util/Random.h" -#include "../../Facing.h" -#include "../../item/Item.h" -MelonTile::MelonTile( int id ) -:super(id, Material::vegetable){ - tex = TEX; -} - -int MelonTile::getTexture( LevelSource* level, int x, int y, int z, int face ) { - return getTexture(face); -} - -int MelonTile::getTexture( int face ) { - if(face == Facing::UP || face == Facing::DOWN) return TEX_TOP; - return TEX; -} - -int MelonTile::getResource( int data, Random* random ) { - return Item::melon->id; -} - -int MelonTile::getResourceCount( Random* random ) { - return 3 + random->nextInt(5); -} - +#include "MelonTile.hpp" +#include "world/level/material/Material.hpp" +#include "util/Random.hpp" +#include "world/Facing.hpp" +#include "world/item/Item.hpp" +MelonTile::MelonTile( int id ) +:super(id, Material::vegetable){ + tex = TEX; +} + +int MelonTile::getTexture( LevelSource* level, int x, int y, int z, int face ) { + return getTexture(face); +} + +int MelonTile::getTexture( int face ) { + if(face == Facing::UP || face == Facing::DOWN) return TEX_TOP; + return TEX; +} + +int MelonTile::getResource( int data, Random* random ) { + return Item::melon->id; +} + +int MelonTile::getResourceCount( Random* random ) { + return 3 + random->nextInt(5); +} + diff --git a/src/world/level/tile/MelonTile.h b/src/world/level/tile/MelonTile.hpp similarity index 94% rename from src/world/level/tile/MelonTile.h rename to src/world/level/tile/MelonTile.hpp index 844202a..0d36e22 100755 --- a/src/world/level/tile/MelonTile.h +++ b/src/world/level/tile/MelonTile.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Tile.h" +#include "Tile.hpp" class MelonTile : public Tile { typedef Tile super; public: diff --git a/src/world/level/tile/MetalTile.h b/src/world/level/tile/MetalTile.hpp similarity index 77% rename from src/world/level/tile/MetalTile.h rename to src/world/level/tile/MetalTile.hpp index fa2f3a4..326da03 100755 --- a/src/world/level/tile/MetalTile.h +++ b/src/world/level/tile/MetalTile.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.tile; -#include "Tile.h" -#include "../material/Material.h" +#include "Tile.hpp" +#include "world/level/material/Material.hpp" class MetalTile: public Tile { diff --git a/src/world/level/tile/MultiTextureTile.h b/src/world/level/tile/MultiTextureTile.hpp similarity index 94% rename from src/world/level/tile/MultiTextureTile.h rename to src/world/level/tile/MultiTextureTile.hpp index d964feb..66e717b 100755 --- a/src/world/level/tile/MultiTextureTile.h +++ b/src/world/level/tile/MultiTextureTile.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.tile; -#include "../material/Material.h" +#include "world/level/material/Material.hpp" class MultiTextureTile: public Tile { diff --git a/src/world/level/tile/Mushroom.cpp b/src/world/level/tile/Mushroom.cpp index 6de05ce..ac6d42a 100755 --- a/src/world/level/tile/Mushroom.cpp +++ b/src/world/level/tile/Mushroom.cpp @@ -1,56 +1,56 @@ -#include "Mushroom.h" - -Mushroom::Mushroom(int id, int tex) -: super(id, tex) -{ - float ss = 0.2f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, ss * 2, 0.5f + ss); - this->setTicking(true); -} - -void Mushroom::tick( Level* level, int x, int y, int z, Random* random ) { - if(random->nextInt(25) == 0) { - int r = 4; - int max = 5; - for (int xx = x - r; xx <= x + r; xx++) - for (int zz = z - r; zz <= z + r; zz++) - for (int yy = y - 1; yy <= y + 1; yy++) { - if (level->getTile(xx, yy, zz) == id && --max <= 0) return; - } - - int x2 = x + random->nextInt(3) - 1; - int y2 = y + random->nextInt(2) - random->nextInt(2); - int z2 = z + random->nextInt(3) - 1; - for (int i = 0; i < 4; i++) { - if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) { - x = x2; - y = y2; - z = z2; - } - x2 = x + random->nextInt(3) - 1; - y2 = y + random->nextInt(2) - random->nextInt(2); - z2 = z + random->nextInt(3) - 1; - } - - if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) { - level->setTile(x2, y2, z2, id); - } - } -} - -bool Mushroom::mayPlace( Level* level, int x, int y, int z, unsigned char face ) { - return super::mayPlace(level, x, y, z, face) && canSurvive(level, x, y, z); -} - -bool Mushroom::mayPlaceOn( int tile ) { - return Tile::solid[tile]; -} - -bool Mushroom::canSurvive( Level* level, int x, int y, int z ) { - if (y < 0 || y >= LEVEL_HEIGHT/*Level::maxBuildHeight*/) - return false; - - int below = level->getTile(x, y - 1, z); - return (level->getRawBrightness(x, y, z) < 13 && mayPlaceOn(below)); -} - +#include "Mushroom.hpp" + +Mushroom::Mushroom(int id, int tex) +: super(id, tex) +{ + float ss = 0.2f; + this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, ss * 2, 0.5f + ss); + this->setTicking(true); +} + +void Mushroom::tick( Level* level, int x, int y, int z, Random* random ) { + if(random->nextInt(25) == 0) { + int r = 4; + int max = 5; + for (int xx = x - r; xx <= x + r; xx++) + for (int zz = z - r; zz <= z + r; zz++) + for (int yy = y - 1; yy <= y + 1; yy++) { + if (level->getTile(xx, yy, zz) == id && --max <= 0) return; + } + + int x2 = x + random->nextInt(3) - 1; + int y2 = y + random->nextInt(2) - random->nextInt(2); + int z2 = z + random->nextInt(3) - 1; + for (int i = 0; i < 4; i++) { + if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) { + x = x2; + y = y2; + z = z2; + } + x2 = x + random->nextInt(3) - 1; + y2 = y + random->nextInt(2) - random->nextInt(2); + z2 = z + random->nextInt(3) - 1; + } + + if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) { + level->setTile(x2, y2, z2, id); + } + } +} + +bool Mushroom::mayPlace( Level* level, int x, int y, int z, unsigned char face ) { + return super::mayPlace(level, x, y, z, face) && canSurvive(level, x, y, z); +} + +bool Mushroom::mayPlaceOn( int tile ) { + return Tile::solid[tile]; +} + +bool Mushroom::canSurvive( Level* level, int x, int y, int z ) { + if (y < 0 || y >= LEVEL_HEIGHT/*Level::maxBuildHeight*/) + return false; + + int below = level->getTile(x, y - 1, z); + return (level->getRawBrightness(x, y, z) < 13 && mayPlaceOn(below)); +} + diff --git a/src/world/level/tile/Mushroom.h b/src/world/level/tile/Mushroom.hpp similarity index 94% rename from src/world/level/tile/Mushroom.h rename to src/world/level/tile/Mushroom.hpp index 813b36e..3bf4b46 100755 --- a/src/world/level/tile/Mushroom.h +++ b/src/world/level/tile/Mushroom.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Bush.h" +#include "Bush.hpp" class Mushroom : public Bush { diff --git a/src/world/level/tile/NetherReactor.cpp b/src/world/level/tile/NetherReactor.cpp index 04404eb..504452d 100755 --- a/src/world/level/tile/NetherReactor.cpp +++ b/src/world/level/tile/NetherReactor.cpp @@ -1,74 +1,74 @@ -#include "NetherReactor.h" -#include "../../entity/player/Player.h" -#include "../Level.h" -#include "entity/NetherReactorTileEntity.h" -#include "NetherReactorPattern.h" -NetherReactor::NetherReactor( int id, int tex, const Material* material ) : super(id, tex, material) { } - -bool NetherReactor::use( Level* level, int x, int y, int z, Player* player ) { - if(level->getLevelData()->getGameType() != GameType::Survival) - return false; - - // Level, X, Z - NetherReactorPattern pattern; - for(int checkLevel = 0; checkLevel <= 2; ++checkLevel) { - for(int checkX = -1; checkX <= 1; ++checkX) { - for(int checkZ = -1; checkZ <= 1; ++checkZ) { - if(level->getTile(x + checkX, y + checkLevel - 1, z + checkZ) != pattern.getTileAt(checkLevel, checkX + 1, checkZ + 1)) { - player->displayClientMessage("Not the correct pattern!"); - return false; - } - } - } - } - if(!canSpawnStartNetherReactor(level, x, y, z, player)) return false; - player->displayClientMessage("Active!"); - NetherReactorTileEntity* reactor = static_cast(level->getTileEntity(x, y, z)); - if (reactor != NULL) { - reactor->lightItUp(x, y, z); - } - return true; -} - -TileEntity* NetherReactor::newTileEntity() { - return TileEntityFactory::createTileEntity(TileEntityType::NetherReactor); -} - -void NetherReactor::setPhase(Level* level, int x, int y, int z, int phase) { - int curPhase = level->getData(x, y, z); - if(curPhase != phase) { - level->setData(x, y, z, phase); - } -} - -int NetherReactor::getTexture( int face, int data ) { - switch(data) { - case 1: return tex-1; - case 2: return tex-2; - default: return tex; - } -} - -bool NetherReactor::canSpawnStartNetherReactor( Level* level, int x, int y, int z, Player* player ) { - if(!allPlayersCloseToReactor(level, x, y, z)) { - player->displayClientMessage("All players need to be close to the reactor."); - return false; - } else if(y > LEVEL_HEIGHT - 28) { - player->displayClientMessage("The nether reactor needs to be built lower down."); - return false; - } else if(y < 2) { - player->displayClientMessage("The nether reactor needs to be built higher up."); - return false; - } - return true; -} - -bool NetherReactor::allPlayersCloseToReactor( Level* level, int x, int y, int z ) { - for(PlayerList::const_iterator i = level->players.begin(); i != level->players.end(); ++i) { - Player* currentPlayer = (*i); - if(!(currentPlayer->x >= x - 5 && currentPlayer->x <= x + 5)) return false; - if(!(currentPlayer->y - currentPlayer->heightOffset >= y -1 && currentPlayer->y - currentPlayer->heightOffset <= y + 1)) return false; - if(!(currentPlayer->z >= z - 5 && currentPlayer->z <= z + 5)) return false; - } - return true; -} +#include "NetherReactor.hpp" +#include "world/entity/player/Player.hpp" +#include "world/level/Level.hpp" +#include "entity/NetherReactorTileEntity.hpp" +#include "NetherReactorPattern.hpp" +NetherReactor::NetherReactor( int id, int tex, const Material* material ) : super(id, tex, material) { } + +bool NetherReactor::use( Level* level, int x, int y, int z, Player* player ) { + if(level->getLevelData()->getGameType() != GameType::Survival) + return false; + + // Level, X, Z + NetherReactorPattern pattern; + for(int checkLevel = 0; checkLevel <= 2; ++checkLevel) { + for(int checkX = -1; checkX <= 1; ++checkX) { + for(int checkZ = -1; checkZ <= 1; ++checkZ) { + if(level->getTile(x + checkX, y + checkLevel - 1, z + checkZ) != pattern.getTileAt(checkLevel, checkX + 1, checkZ + 1)) { + player->displayClientMessage("Not the correct pattern!"); + return false; + } + } + } + } + if(!canSpawnStartNetherReactor(level, x, y, z, player)) return false; + player->displayClientMessage("Active!"); + NetherReactorTileEntity* reactor = static_cast(level->getTileEntity(x, y, z)); + if (reactor != NULL) { + reactor->lightItUp(x, y, z); + } + return true; +} + +TileEntity* NetherReactor::newTileEntity() { + return TileEntityFactory::createTileEntity(TileEntityType::NetherReactor); +} + +void NetherReactor::setPhase(Level* level, int x, int y, int z, int phase) { + int curPhase = level->getData(x, y, z); + if(curPhase != phase) { + level->setData(x, y, z, phase); + } +} + +int NetherReactor::getTexture( int face, int data ) { + switch(data) { + case 1: return tex-1; + case 2: return tex-2; + default: return tex; + } +} + +bool NetherReactor::canSpawnStartNetherReactor( Level* level, int x, int y, int z, Player* player ) { + if(!allPlayersCloseToReactor(level, x, y, z)) { + player->displayClientMessage("All players need to be close to the reactor."); + return false; + } else if(y > LEVEL_HEIGHT - 28) { + player->displayClientMessage("The nether reactor needs to be built lower down."); + return false; + } else if(y < 2) { + player->displayClientMessage("The nether reactor needs to be built higher up."); + return false; + } + return true; +} + +bool NetherReactor::allPlayersCloseToReactor( Level* level, int x, int y, int z ) { + for(PlayerList::const_iterator i = level->players.begin(); i != level->players.end(); ++i) { + Player* currentPlayer = (*i); + if(!(currentPlayer->x >= x - 5 && currentPlayer->x <= x + 5)) return false; + if(!(currentPlayer->y - currentPlayer->heightOffset >= y -1 && currentPlayer->y - currentPlayer->heightOffset <= y + 1)) return false; + if(!(currentPlayer->z >= z - 5 && currentPlayer->z <= z + 5)) return false; + } + return true; +} diff --git a/src/world/level/tile/NetherReactor.h b/src/world/level/tile/NetherReactor.hpp similarity index 95% rename from src/world/level/tile/NetherReactor.h rename to src/world/level/tile/NetherReactor.hpp index 654330c..6b74d3a 100755 --- a/src/world/level/tile/NetherReactor.h +++ b/src/world/level/tile/NetherReactor.hpp @@ -1,6 +1,6 @@ #pragma once -#include "EntityTile.h" +#include "EntityTile.hpp" class Material; class NetherReactor : public EntityTile { diff --git a/src/world/level/tile/NetherReactorPattern.cpp b/src/world/level/tile/NetherReactorPattern.cpp index 8181e41..0c9d077 100755 --- a/src/world/level/tile/NetherReactorPattern.cpp +++ b/src/world/level/tile/NetherReactorPattern.cpp @@ -1,43 +1,43 @@ -#include "NetherReactorPattern.h" -#include "Tile.h" -NetherReactorPattern::NetherReactorPattern( ) { - const int goldId = Tile::goldBlock->id; - const int stoneId = Tile::stoneBrick->id; - const int netherCoreId = Tile::netherReactor->id; - const unsigned int types[3][3][3] = - { - // Level 0 - { - {goldId, stoneId, goldId}, - {stoneId, stoneId, stoneId}, - {goldId, stoneId, goldId} - }, - // Level 1 - { - {stoneId, 0, stoneId}, - {0, netherCoreId, 0}, - {stoneId, 0, stoneId} - }, - // Level 2 - { - {0, stoneId, 0}, - {stoneId, stoneId, stoneId}, - {0, stoneId, 0} - } - }; - for(int setLevel = 0; setLevel <= 2; ++setLevel) { - for(int setX = 0; setX <= 2; ++setX) { - for(int setZ = 0; setZ <= 2; ++setZ) { - setTileAt(setLevel, setX, setZ, types[setLevel][setX][setZ]); - } - } - } -} - -void NetherReactorPattern::setTileAt( int level, int x, int z, int tile) { - pattern[level][x][z] = tile; -} - -unsigned int NetherReactorPattern::getTileAt( int level, int x, int z ) { - return pattern[level][x][z]; -} +#include "NetherReactorPattern.hpp" +#include "Tile.hpp" +NetherReactorPattern::NetherReactorPattern( ) { + const int goldId = Tile::goldBlock->id; + const int stoneId = Tile::stoneBrick->id; + const int netherCoreId = Tile::netherReactor->id; + const unsigned int types[3][3][3] = + { + // Level 0 + { + {goldId, stoneId, goldId}, + {stoneId, stoneId, stoneId}, + {goldId, stoneId, goldId} + }, + // Level 1 + { + {stoneId, 0, stoneId}, + {0, netherCoreId, 0}, + {stoneId, 0, stoneId} + }, + // Level 2 + { + {0, stoneId, 0}, + {stoneId, stoneId, stoneId}, + {0, stoneId, 0} + } + }; + for(int setLevel = 0; setLevel <= 2; ++setLevel) { + for(int setX = 0; setX <= 2; ++setX) { + for(int setZ = 0; setZ <= 2; ++setZ) { + setTileAt(setLevel, setX, setZ, types[setLevel][setX][setZ]); + } + } + } +} + +void NetherReactorPattern::setTileAt( int level, int x, int z, int tile) { + pattern[level][x][z] = tile; +} + +unsigned int NetherReactorPattern::getTileAt( int level, int x, int z ) { + return pattern[level][x][z]; +} diff --git a/src/world/level/tile/NetherReactorPattern.h b/src/world/level/tile/NetherReactorPattern.hpp similarity index 100% rename from src/world/level/tile/NetherReactorPattern.h rename to src/world/level/tile/NetherReactorPattern.hpp diff --git a/src/world/level/tile/ObsidianTile.h b/src/world/level/tile/ObsidianTile.hpp similarity index 97% rename from src/world/level/tile/ObsidianTile.h rename to src/world/level/tile/ObsidianTile.hpp index 3a77cdd..6e757e9 100755 --- a/src/world/level/tile/ObsidianTile.h +++ b/src/world/level/tile/ObsidianTile.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "StoneTile.h" +#include "util/Random.hpp" +#include "StoneTile.hpp" class ObsidianTile: public StoneTile diff --git a/src/world/level/tile/OreTile.h b/src/world/level/tile/OreTile.hpp similarity index 85% rename from src/world/level/tile/OreTile.h rename to src/world/level/tile/OreTile.hpp index 2ef31f6..517e077 100755 --- a/src/world/level/tile/OreTile.h +++ b/src/world/level/tile/OreTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" -#include "Tile.h" -#include "../../item/DyePowderItem.h" +#include "Tile.hpp" +#include "world/item/DyePowderItem.hpp" class OreTile: public Tile { diff --git a/src/world/level/tile/QuartzBlockTile.h b/src/world/level/tile/QuartzBlockTile.hpp similarity index 85% rename from src/world/level/tile/QuartzBlockTile.h rename to src/world/level/tile/QuartzBlockTile.hpp index 155617d..64cee2f 100755 --- a/src/world/level/tile/QuartzBlockTile.h +++ b/src/world/level/tile/QuartzBlockTile.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../../Facing.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/Facing.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" +#include "Tile.hpp" class QuartzBlockTile: public Tile { diff --git a/src/world/level/tile/RedStoneOreTile.h b/src/world/level/tile/RedStoneOreTile.hpp similarity index 96% rename from src/world/level/tile/RedStoneOreTile.h rename to src/world/level/tile/RedStoneOreTile.hpp index 71a73ef..8dae67e 100755 --- a/src/world/level/tile/RedStoneOreTile.h +++ b/src/world/level/tile/RedStoneOreTile.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" class Player; diff --git a/src/world/level/tile/ReedTile.h b/src/world/level/tile/ReedTile.hpp similarity index 95% rename from src/world/level/tile/ReedTile.h rename to src/world/level/tile/ReedTile.hpp index 30b4a7c..ffe60d3 100755 --- a/src/world/level/tile/ReedTile.h +++ b/src/world/level/tile/ReedTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" +#include "Tile.hpp" class ReedTile: public Tile { diff --git a/src/world/level/tile/SandStoneTile.h b/src/world/level/tile/SandStoneTile.hpp similarity index 77% rename from src/world/level/tile/SandStoneTile.h rename to src/world/level/tile/SandStoneTile.hpp index 861100d..86cff7a 100755 --- a/src/world/level/tile/SandStoneTile.h +++ b/src/world/level/tile/SandStoneTile.hpp @@ -2,13 +2,13 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../../Facing.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/Facing.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" -#include "MultiTextureTile.h" +#include "Tile.hpp" +#include "MultiTextureTile.hpp" class SandStoneTile: public MultiTextureTile { diff --git a/src/world/level/tile/SandTile.cpp b/src/world/level/tile/SandTile.cpp index 429f117..3158855 100755 --- a/src/world/level/tile/SandTile.cpp +++ b/src/world/level/tile/SandTile.cpp @@ -1,26 +1,26 @@ -#include "SandTile.h" -#include "../../entity/item/FallingTile.h" - -bool SandTile::instaFall = false; - -/*private*/ -void SandTile::checkSlide(Level* level, int x, int y, int z) -{ - int x2 = x; - int y2 = y; - int z2 = z; - if (isFree(level, x2, y2 - 1, z2) && y2 >= 0) { - int r = 32; - if (instaFall || !level->hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { - level->setTile(x, y, z, 0); - while (isFree(level, x, y - 1, z) && y > 0) - y--; - if (y > 0) { - level->setTile(x, y, z, id); - } - } else { - FallingTile* e = new FallingTile(level, x + 0.5f, y + 0.5f, z + 0.5f, id); - level->addEntity(e); - } - } -} +#include "SandTile.hpp" +#include "world/entity/item/FallingTile.hpp" + +bool SandTile::instaFall = false; + +/*private*/ +void SandTile::checkSlide(Level* level, int x, int y, int z) +{ + int x2 = x; + int y2 = y; + int z2 = z; + if (isFree(level, x2, y2 - 1, z2) && y2 >= 0) { + int r = 32; + if (instaFall || !level->hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { + level->setTile(x, y, z, 0); + while (isFree(level, x, y - 1, z) && y > 0) + y--; + if (y > 0) { + level->setTile(x, y, z, id); + } + } else { + FallingTile* e = new FallingTile(level, x + 0.5f, y + 0.5f, z + 0.5f, id); + level->addEntity(e); + } + } +} diff --git a/src/world/level/tile/SandTile.h b/src/world/level/tile/SandTile.hpp similarity index 90% rename from src/world/level/tile/SandTile.h rename to src/world/level/tile/SandTile.hpp index 1c10123..a981bcd 100755 --- a/src/world/level/tile/SandTile.h +++ b/src/world/level/tile/SandTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" +#include "Tile.hpp" class Level; diff --git a/src/world/level/tile/Sapling.h b/src/world/level/tile/Sapling.hpp similarity index 95% rename from src/world/level/tile/Sapling.h rename to src/world/level/tile/Sapling.hpp index fe95990..970716e 100755 --- a/src/world/level/tile/Sapling.h +++ b/src/world/level/tile/Sapling.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level->tile; -#include "Bush.h" -#include "../Level.h" -#include "../levelgen/feature/SpruceFeature.h" -#include "../levelgen/feature/BirchFeature.h" -#include "../levelgen/feature/TreeFeature.h" +#include "Bush.hpp" +#include "world/level/Level.hpp" +#include "world/level/levelgen/feature/SpruceFeature.hpp" +#include "world/level/levelgen/feature/BirchFeature.hpp" +#include "world/level/levelgen/feature/TreeFeature.hpp" class Sapling: public Bush { diff --git a/src/world/level/tile/SignTile.h b/src/world/level/tile/SignTile.hpp similarity index 94% rename from src/world/level/tile/SignTile.h rename to src/world/level/tile/SignTile.hpp index 02d9a60..5fea663 100755 --- a/src/world/level/tile/SignTile.h +++ b/src/world/level/tile/SignTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "EntityTile.h" -#include "../../item/Item.h" -#include "../material/Material.h" -#include "entity/TileEntity.h" -#include "../../phys/AABB.h" +#include "EntityTile.hpp" +#include "world/item/Item.hpp" +#include "world/level/material/Material.hpp" +#include "entity/TileEntity.hpp" +#include "world/phys/AABB.hpp" class SignTile: public EntityTile { diff --git a/src/world/level/tile/SnowTile.h b/src/world/level/tile/SnowTile.hpp similarity index 84% rename from src/world/level/tile/SnowTile.h rename to src/world/level/tile/SnowTile.hpp index 4609cb6..83f901c 100755 --- a/src/world/level/tile/SnowTile.h +++ b/src/world/level/tile/SnowTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level->tile; -#include "Tile.h" +#include "Tile.hpp" -#include "../material/Material.h" -#include "../../item/Item.h" -#include "../../../util/Random.h" +#include "world/level/material/Material.hpp" +#include "world/item/Item.hpp" +#include "util/Random.hpp" class SnowTile: public Tile { diff --git a/src/world/level/tile/StairTile.cpp b/src/world/level/tile/StairTile.cpp index e6969e4..ac159fd 100755 --- a/src/world/level/tile/StairTile.cpp +++ b/src/world/level/tile/StairTile.cpp @@ -1,237 +1,237 @@ -#include "../Level.h" -#include "../../phys/HitResult.h" -#include "../../phys/Vec3.h" -#include "../../Facing.h" -#include "StairTile.h" - -const int StairTile::DEAD_SPACES[8][2] = { - {2, 6}, {3, 7}, {2, 3}, {6, 7}, - {0, 4}, {1, 5}, {0, 1}, {4, 5} -}; - -int StairTile::getPlacedOnFaceDataValue(Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) { - if (face == Facing::DOWN || (face != Facing::UP && clickY > 0.5)) { - return itemValue | UPSIDEDOWN_BIT; - } - return itemValue; -} - - -bool StairTile::setStepShape(LevelSource* level, int x, int y, int z) { - int data = level->getData(x, y, z); - int dir = data & 0x3; - - float bottom = 0.5f; - float top = 1.0f; - - if ((data & UPSIDEDOWN_BIT) != 0) { - bottom = 0; - top = .5f; - } - - float west = 0; - float east = 1; - float north = 0; - float south = .5f; - - bool checkInnerPiece = true; - - if (dir == DIR_EAST) { - west = .5f; - south = 1; - - int backTile = level->getTile(x + 1, y, z); - int backData = level->getData(x + 1, y, z); - if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { - int backDir = backData & 0x3; - if (backDir == DIR_NORTH && !isLockAttached(level, x, y, z + 1, data)) { - south = .5f; - checkInnerPiece = false; - } else if (backDir == DIR_SOUTH && !isLockAttached(level, x, y, z - 1, data)) { - north = .5f; - checkInnerPiece = false; - } - } - } else if (dir == DIR_WEST) { - east = .5f; - south = 1; - - int backTile = level->getTile(x - 1, y, z); - int backData = level->getData(x - 1, y, z); - if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { - int backDir = backData & 0x3; - if (backDir == DIR_NORTH && !isLockAttached(level, x, y, z + 1, data)) { - south = .5f; - checkInnerPiece = false; - } else if (backDir == DIR_SOUTH && !isLockAttached(level, x, y, z - 1, data)) { - north = .5f; - checkInnerPiece = false; - } - } - } else if (dir == DIR_SOUTH) { - north = .5f; - south = 1; - - int backTile = level->getTile(x, y, z + 1); - int backData = level->getData(x, y, z + 1); - if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { - int backDir = backData & 0x3; - if (backDir == DIR_WEST && !isLockAttached(level, x + 1, y, z, data)) { - east = .5f; - checkInnerPiece = false; - } else if (backDir == DIR_EAST && !isLockAttached(level, x - 1, y, z, data)) { - west = .5f; - checkInnerPiece = false; - } - } - } else if (dir == DIR_NORTH) { - int backTile = level->getTile(x, y, z - 1); - int backData = level->getData(x, y, z - 1); - if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { - int backDir = backData & 0x3; - if (backDir == DIR_WEST && !isLockAttached(level, x + 1, y, z, data)) { - east = .5f; - checkInnerPiece = false; - } else if (backDir == DIR_EAST && !isLockAttached(level, x - 1, y, z, data)) { - west = .5f; - checkInnerPiece = false; - } - } - } - - setShape(west, bottom, north, east, top, south); - return checkInnerPiece; -} - -/* - * This method adds an extra 1/8 block if the stairs can attach as an - * "inner corner." - */ -bool StairTile::setInnerPieceShape(LevelSource* level, int x, int y, int z) { - int data = level->getData(x, y, z); - int dir = data & 0x3; - - float bottom = 0.5f; - float top = 1.0f; - - if ((data & UPSIDEDOWN_BIT) != 0) { - bottom = 0; - top = .5f; - } - - float west = 0; - float east = .5f; - float north = .5f; - float south = 1.0f; - - bool hasInnerPiece = false; - - if (dir == DIR_EAST) { - int frontTile = level->getTile(x - 1, y, z); - int frontData = level->getData(x - 1, y, z); - if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { - int frontDir = frontData & 0x3; - if (frontDir == DIR_NORTH && !isLockAttached(level, x, y, z - 1, data)) { - north = 0; - south = .5f; - hasInnerPiece = true; - } else if (frontDir == DIR_SOUTH && !isLockAttached(level, x, y, z + 1, data)) { - north = .5f; - south = 1; - hasInnerPiece = true; - } - } - } else if (dir == DIR_WEST) { - int frontTile = level->getTile(x + 1, y, z); - int frontData = level->getData(x + 1, y, z); - if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { - west = .5f; - east = 1.0f; - int frontDir = frontData & 0x3; - if (frontDir == DIR_NORTH && !isLockAttached(level, x, y, z - 1, data)) { - north = 0; - south = .5f; - hasInnerPiece = true; - } else if (frontDir == DIR_SOUTH && !isLockAttached(level, x, y, z + 1, data)) { - north = .5f; - south = 1; - hasInnerPiece = true; - } - } - } else if (dir == DIR_SOUTH) { - int frontTile = level->getTile(x, y, z - 1); - int frontData = level->getData(x, y, z - 1); - if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { - north = 0; - south = .5f; - - int frontDir = frontData & 0x3; - if (frontDir == DIR_WEST && !isLockAttached(level, x - 1, y, z, data)) { - hasInnerPiece = true; - } else if (frontDir == DIR_EAST && !isLockAttached(level, x + 1, y, z, data)) { - west = .5f; - east = 1.0f; - hasInnerPiece = true; - } - } - } else if (dir == DIR_NORTH) { - int frontTile = level->getTile(x, y, z + 1); - int frontData = level->getData(x, y, z + 1); - if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { - int frontDir = frontData & 0x3; - if (frontDir == DIR_WEST && !isLockAttached(level, x - 1, y, z, data)) { - hasInnerPiece = true; - } else if (frontDir == DIR_EAST && !isLockAttached(level, x + 1, y, z, data)) { - west = .5f; - east = 1.0f; - hasInnerPiece = true; - } - } - } - - if (hasInnerPiece) { - setShape(west, bottom, north, east, top, south); - } - return hasInnerPiece; -} - -HitResult StairTile::clip(Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b) -{ - HitResult results[8]; - - int data = level->getData(xt, yt, zt); - int dir = data & 0x3; - bool upsideDown = (data & UPSIDEDOWN_BIT) == UPSIDEDOWN_BIT; - const int* deadSpaces = (const int*)&DEAD_SPACES[dir + (upsideDown ? 4 : 0)]; - - isClipping = true; - for (int i = 0; i < 8; i++) { - clipStep = i; - results[i] = super::clip(level, xt, yt, zt, a, b); - } - isClipping = false; - - results[deadSpaces[0]] = HitResult(); - results[deadSpaces[1]] = HitResult(); - - HitResult* closest = NULL; - double closestDist = 0; - - for (int r = 0; r < 8; r++) { - HitResult& result = results[r]; - if (result.isHit()) { - double dist = result.pos.distanceToSqr(b); - - if (dist > closestDist) { - closest = &result; - closestDist = dist; - } - } - } - if (closest == NULL) - { - return HitResult(); - } - - return *closest; -} +#include "world/level/Level.hpp" +#include "world/phys/HitResult.hpp" +#include "world/phys/Vec3.hpp" +#include "world/Facing.hpp" +#include "StairTile.hpp" + +const int StairTile::DEAD_SPACES[8][2] = { + {2, 6}, {3, 7}, {2, 3}, {6, 7}, + {0, 4}, {1, 5}, {0, 1}, {4, 5} +}; + +int StairTile::getPlacedOnFaceDataValue(Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) { + if (face == Facing::DOWN || (face != Facing::UP && clickY > 0.5)) { + return itemValue | UPSIDEDOWN_BIT; + } + return itemValue; +} + + +bool StairTile::setStepShape(LevelSource* level, int x, int y, int z) { + int data = level->getData(x, y, z); + int dir = data & 0x3; + + float bottom = 0.5f; + float top = 1.0f; + + if ((data & UPSIDEDOWN_BIT) != 0) { + bottom = 0; + top = .5f; + } + + float west = 0; + float east = 1; + float north = 0; + float south = .5f; + + bool checkInnerPiece = true; + + if (dir == DIR_EAST) { + west = .5f; + south = 1; + + int backTile = level->getTile(x + 1, y, z); + int backData = level->getData(x + 1, y, z); + if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { + int backDir = backData & 0x3; + if (backDir == DIR_NORTH && !isLockAttached(level, x, y, z + 1, data)) { + south = .5f; + checkInnerPiece = false; + } else if (backDir == DIR_SOUTH && !isLockAttached(level, x, y, z - 1, data)) { + north = .5f; + checkInnerPiece = false; + } + } + } else if (dir == DIR_WEST) { + east = .5f; + south = 1; + + int backTile = level->getTile(x - 1, y, z); + int backData = level->getData(x - 1, y, z); + if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { + int backDir = backData & 0x3; + if (backDir == DIR_NORTH && !isLockAttached(level, x, y, z + 1, data)) { + south = .5f; + checkInnerPiece = false; + } else if (backDir == DIR_SOUTH && !isLockAttached(level, x, y, z - 1, data)) { + north = .5f; + checkInnerPiece = false; + } + } + } else if (dir == DIR_SOUTH) { + north = .5f; + south = 1; + + int backTile = level->getTile(x, y, z + 1); + int backData = level->getData(x, y, z + 1); + if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { + int backDir = backData & 0x3; + if (backDir == DIR_WEST && !isLockAttached(level, x + 1, y, z, data)) { + east = .5f; + checkInnerPiece = false; + } else if (backDir == DIR_EAST && !isLockAttached(level, x - 1, y, z, data)) { + west = .5f; + checkInnerPiece = false; + } + } + } else if (dir == DIR_NORTH) { + int backTile = level->getTile(x, y, z - 1); + int backData = level->getData(x, y, z - 1); + if (isStairs(backTile) && ((data & UPSIDEDOWN_BIT) == (backData & UPSIDEDOWN_BIT))) { + int backDir = backData & 0x3; + if (backDir == DIR_WEST && !isLockAttached(level, x + 1, y, z, data)) { + east = .5f; + checkInnerPiece = false; + } else if (backDir == DIR_EAST && !isLockAttached(level, x - 1, y, z, data)) { + west = .5f; + checkInnerPiece = false; + } + } + } + + setShape(west, bottom, north, east, top, south); + return checkInnerPiece; +} + +/* + * This method adds an extra 1/8 block if the stairs can attach as an + * "inner corner." + */ +bool StairTile::setInnerPieceShape(LevelSource* level, int x, int y, int z) { + int data = level->getData(x, y, z); + int dir = data & 0x3; + + float bottom = 0.5f; + float top = 1.0f; + + if ((data & UPSIDEDOWN_BIT) != 0) { + bottom = 0; + top = .5f; + } + + float west = 0; + float east = .5f; + float north = .5f; + float south = 1.0f; + + bool hasInnerPiece = false; + + if (dir == DIR_EAST) { + int frontTile = level->getTile(x - 1, y, z); + int frontData = level->getData(x - 1, y, z); + if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { + int frontDir = frontData & 0x3; + if (frontDir == DIR_NORTH && !isLockAttached(level, x, y, z - 1, data)) { + north = 0; + south = .5f; + hasInnerPiece = true; + } else if (frontDir == DIR_SOUTH && !isLockAttached(level, x, y, z + 1, data)) { + north = .5f; + south = 1; + hasInnerPiece = true; + } + } + } else if (dir == DIR_WEST) { + int frontTile = level->getTile(x + 1, y, z); + int frontData = level->getData(x + 1, y, z); + if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { + west = .5f; + east = 1.0f; + int frontDir = frontData & 0x3; + if (frontDir == DIR_NORTH && !isLockAttached(level, x, y, z - 1, data)) { + north = 0; + south = .5f; + hasInnerPiece = true; + } else if (frontDir == DIR_SOUTH && !isLockAttached(level, x, y, z + 1, data)) { + north = .5f; + south = 1; + hasInnerPiece = true; + } + } + } else if (dir == DIR_SOUTH) { + int frontTile = level->getTile(x, y, z - 1); + int frontData = level->getData(x, y, z - 1); + if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { + north = 0; + south = .5f; + + int frontDir = frontData & 0x3; + if (frontDir == DIR_WEST && !isLockAttached(level, x - 1, y, z, data)) { + hasInnerPiece = true; + } else if (frontDir == DIR_EAST && !isLockAttached(level, x + 1, y, z, data)) { + west = .5f; + east = 1.0f; + hasInnerPiece = true; + } + } + } else if (dir == DIR_NORTH) { + int frontTile = level->getTile(x, y, z + 1); + int frontData = level->getData(x, y, z + 1); + if (isStairs(frontTile) && ((data & UPSIDEDOWN_BIT) == (frontData & UPSIDEDOWN_BIT))) { + int frontDir = frontData & 0x3; + if (frontDir == DIR_WEST && !isLockAttached(level, x - 1, y, z, data)) { + hasInnerPiece = true; + } else if (frontDir == DIR_EAST && !isLockAttached(level, x + 1, y, z, data)) { + west = .5f; + east = 1.0f; + hasInnerPiece = true; + } + } + } + + if (hasInnerPiece) { + setShape(west, bottom, north, east, top, south); + } + return hasInnerPiece; +} + +HitResult StairTile::clip(Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b) +{ + HitResult results[8]; + + int data = level->getData(xt, yt, zt); + int dir = data & 0x3; + bool upsideDown = (data & UPSIDEDOWN_BIT) == UPSIDEDOWN_BIT; + const int* deadSpaces = (const int*)&DEAD_SPACES[dir + (upsideDown ? 4 : 0)]; + + isClipping = true; + for (int i = 0; i < 8; i++) { + clipStep = i; + results[i] = super::clip(level, xt, yt, zt, a, b); + } + isClipping = false; + + results[deadSpaces[0]] = HitResult(); + results[deadSpaces[1]] = HitResult(); + + HitResult* closest = NULL; + double closestDist = 0; + + for (int r = 0; r < 8; r++) { + HitResult& result = results[r]; + if (result.isHit()) { + double dist = result.pos.distanceToSqr(b); + + if (dist > closestDist) { + closest = &result; + closestDist = dist; + } + } + } + if (closest == NULL) + { + return HitResult(); + } + + return *closest; +} diff --git a/src/world/level/tile/StairTile.h b/src/world/level/tile/StairTile.hpp similarity index 98% rename from src/world/level/tile/StairTile.h rename to src/world/level/tile/StairTile.hpp index f5ed554..58b09fb 100755 --- a/src/world/level/tile/StairTile.h +++ b/src/world/level/tile/StairTile.hpp @@ -4,10 +4,10 @@ #include -#include "Tile.h" -#include "../../../util/Mth.h" -#include "../../../util/Random.h" -#include "../../entity/Mob.h" +#include "Tile.hpp" +#include "util/Mth.hpp" +#include "util/Random.hpp" +#include "world/entity/Mob.hpp" class StairTile: public Tile { diff --git a/src/world/level/tile/StemTile.cpp b/src/world/level/tile/StemTile.cpp index 57faee5..a7232c7 100755 --- a/src/world/level/tile/StemTile.cpp +++ b/src/world/level/tile/StemTile.cpp @@ -1,153 +1,153 @@ -#include "StemTile.h" -StemTile::StemTile( int id, Tile* fruit ) -: super(id, 15 + 6 * 16), - fruit(fruit) { - setTicking(true); - float ss = 0.125f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); -} - -bool StemTile::mayPlaceOn( int tile ) { - return tile == Tile::farmland->id; -} - -void StemTile::tick( Level* level, int x, int y, int z, Random* random ) { - super::tick(level, x, y, z, random); - if (level->getRawBrightness(x, y + 1, z) >= Level::MAX_BRIGHTNESS - 6) { - - float growthSpeed = getGrowthSpeed(level, x, y, z); - - if (random->nextInt((int) (25 / growthSpeed) + 1) == 0) { - int age = level->getData(x, y, z); - if (age < 7) { - age++; - level->setData(x, y, z, age); - } else { - if (level->getTile(x - 1, y, z) == fruit->id) return; - if (level->getTile(x + 1, y, z) == fruit->id) return; - if (level->getTile(x, y, z - 1) == fruit->id) return; - if (level->getTile(x, y, z + 1) == fruit->id) return; - for(int a = 0; a < 4; ++a) { - int dir = a; //random->nextInt(4); - int xx = x; - int zz = z; - if (dir == 0) xx--; - if (dir == 1) xx++; - if (dir == 2) zz--; - if (dir == 3) zz++; - int below = level->getTile(xx, y - 1, zz); - if (level->getTile(xx, y, zz) == 0 && (below == Tile::farmland->id || below == Tile::dirt->id || below == Tile::grass->id)) { - level->setTile(xx, y, zz, fruit->id); - break; - } - } - } - } - } -} - -void StemTile::growCropsToMax( Level* level, int x, int y, int z ) { - level->setData(x, y, z, 7); -} - -float StemTile::getGrowthSpeed( Level* level, int x, int y, int z ) { - float speed = 1; - - int n = level->getTile(x, y, z - 1); - int s = level->getTile(x, y, z + 1); - int w = level->getTile(x - 1, y, z); - int e = level->getTile(x + 1, y, z); - - int d0 = level->getTile(x - 1, y, z - 1); - int d1 = level->getTile(x + 1, y, z - 1); - int d2 = level->getTile(x + 1, y, z + 1); - int d3 = level->getTile(x - 1, y, z + 1); - - bool horizontal = w == this->id || e == this->id; - bool vertical = n == this->id || s == this->id; - bool diagonal = d0 == this->id || d1 == this->id || d2 == this->id || d3 == this->id; - - for (int xx = x - 1; xx <= x + 1; xx++) - for (int zz = z - 1; zz <= z + 1; zz++) { - int t = level->getTile(xx, y - 1, zz); - - float tileSpeed = 0; - if (t == Tile::farmland->id) { - tileSpeed = 1; - if (level->getData(xx, y - 1, zz) > 0) tileSpeed = 3; - } - - if (xx != x || zz != z) tileSpeed /= 4; - - speed += tileSpeed; - } - - if (diagonal || (horizontal && vertical)) speed /= 2; - - return speed; -} - -int StemTile::getColor( int data ) { - int r = data * 32; - int g = 255 - data * 8; - int b = data * 4; - return r << 16 | g << 8 | b; -} - -int StemTile::getColor( LevelSource* level, int x, int y, int z ) { - return getColor(level->getData(x, y, z)); -} - -int StemTile::getTexture( int face, int data ) { - return tex; -} - -void StemTile::updateDefaultShape() { - float ss = 0.125f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); -} - -void StemTile::updateShape( LevelSource* level, int x, int y, int z ) { - yy1 = (level->getData(x, y, z) * 2 + 2) / 16.0f; - float ss = 0.125f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, (float) yy1, 0.5f + ss); -} - -int StemTile::getRenderShape() { - return Tile::SHAPE_STEM; -} - -int StemTile::getConnectDir( LevelSource* level, int x, int y, int z ) { - int d = level->getData(x, y, z); - if (d < 7) return -1; - if (level->getTile(x - 1, y, z) == fruit->id) return 0; - if (level->getTile(x + 1, y, z) == fruit->id) return 1; - if (level->getTile(x, y, z - 1) == fruit->id) return 2; - if (level->getTile(x, y, z + 1) == fruit->id) return 3; - return -1; -} - -void StemTile::spawnResources( Level* level, int x, int y, int z, int data, float odds ) { - super::spawnResources(level, x, y, z, data, odds); - - if (level->isClientSide) { - return; - } - - Item* seed = NULL; - //if (fruit == Tile::pumpkin) seed = Item::seeds_pumpkin; - if (fruit == Tile::melon) seed = Item::seeds_melon; - for (int i = 0; i < 3; i++) { - if (level->random.nextInt(5 * 3) > data) continue; - popResource(level, x, y, z, ItemInstance(seed)); - } -} - -int StemTile::getResource( int data, Random* random ) { - return -1; -} - -int StemTile::getResourceCount( Random* random ) { - return 1; -} - +#include "StemTile.hpp" +StemTile::StemTile( int id, Tile* fruit ) +: super(id, 15 + 6 * 16), + fruit(fruit) { + setTicking(true); + float ss = 0.125f; + this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); +} + +bool StemTile::mayPlaceOn( int tile ) { + return tile == Tile::farmland->id; +} + +void StemTile::tick( Level* level, int x, int y, int z, Random* random ) { + super::tick(level, x, y, z, random); + if (level->getRawBrightness(x, y + 1, z) >= Level::MAX_BRIGHTNESS - 6) { + + float growthSpeed = getGrowthSpeed(level, x, y, z); + + if (random->nextInt((int) (25 / growthSpeed) + 1) == 0) { + int age = level->getData(x, y, z); + if (age < 7) { + age++; + level->setData(x, y, z, age); + } else { + if (level->getTile(x - 1, y, z) == fruit->id) return; + if (level->getTile(x + 1, y, z) == fruit->id) return; + if (level->getTile(x, y, z - 1) == fruit->id) return; + if (level->getTile(x, y, z + 1) == fruit->id) return; + for(int a = 0; a < 4; ++a) { + int dir = a; //random->nextInt(4); + int xx = x; + int zz = z; + if (dir == 0) xx--; + if (dir == 1) xx++; + if (dir == 2) zz--; + if (dir == 3) zz++; + int below = level->getTile(xx, y - 1, zz); + if (level->getTile(xx, y, zz) == 0 && (below == Tile::farmland->id || below == Tile::dirt->id || below == Tile::grass->id)) { + level->setTile(xx, y, zz, fruit->id); + break; + } + } + } + } + } +} + +void StemTile::growCropsToMax( Level* level, int x, int y, int z ) { + level->setData(x, y, z, 7); +} + +float StemTile::getGrowthSpeed( Level* level, int x, int y, int z ) { + float speed = 1; + + int n = level->getTile(x, y, z - 1); + int s = level->getTile(x, y, z + 1); + int w = level->getTile(x - 1, y, z); + int e = level->getTile(x + 1, y, z); + + int d0 = level->getTile(x - 1, y, z - 1); + int d1 = level->getTile(x + 1, y, z - 1); + int d2 = level->getTile(x + 1, y, z + 1); + int d3 = level->getTile(x - 1, y, z + 1); + + bool horizontal = w == this->id || e == this->id; + bool vertical = n == this->id || s == this->id; + bool diagonal = d0 == this->id || d1 == this->id || d2 == this->id || d3 == this->id; + + for (int xx = x - 1; xx <= x + 1; xx++) + for (int zz = z - 1; zz <= z + 1; zz++) { + int t = level->getTile(xx, y - 1, zz); + + float tileSpeed = 0; + if (t == Tile::farmland->id) { + tileSpeed = 1; + if (level->getData(xx, y - 1, zz) > 0) tileSpeed = 3; + } + + if (xx != x || zz != z) tileSpeed /= 4; + + speed += tileSpeed; + } + + if (diagonal || (horizontal && vertical)) speed /= 2; + + return speed; +} + +int StemTile::getColor( int data ) { + int r = data * 32; + int g = 255 - data * 8; + int b = data * 4; + return r << 16 | g << 8 | b; +} + +int StemTile::getColor( LevelSource* level, int x, int y, int z ) { + return getColor(level->getData(x, y, z)); +} + +int StemTile::getTexture( int face, int data ) { + return tex; +} + +void StemTile::updateDefaultShape() { + float ss = 0.125f; + this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); +} + +void StemTile::updateShape( LevelSource* level, int x, int y, int z ) { + yy1 = (level->getData(x, y, z) * 2 + 2) / 16.0f; + float ss = 0.125f; + this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, (float) yy1, 0.5f + ss); +} + +int StemTile::getRenderShape() { + return Tile::SHAPE_STEM; +} + +int StemTile::getConnectDir( LevelSource* level, int x, int y, int z ) { + int d = level->getData(x, y, z); + if (d < 7) return -1; + if (level->getTile(x - 1, y, z) == fruit->id) return 0; + if (level->getTile(x + 1, y, z) == fruit->id) return 1; + if (level->getTile(x, y, z - 1) == fruit->id) return 2; + if (level->getTile(x, y, z + 1) == fruit->id) return 3; + return -1; +} + +void StemTile::spawnResources( Level* level, int x, int y, int z, int data, float odds ) { + super::spawnResources(level, x, y, z, data, odds); + + if (level->isClientSide) { + return; + } + + Item* seed = NULL; + //if (fruit == Tile::pumpkin) seed = Item::seeds_pumpkin; + if (fruit == Tile::melon) seed = Item::seeds_melon; + for (int i = 0; i < 3; i++) { + if (level->random.nextInt(5 * 3) > data) continue; + popResource(level, x, y, z, ItemInstance(seed)); + } +} + +int StemTile::getResource( int data, Random* random ) { + return -1; +} + +int StemTile::getResourceCount( Random* random ) { + return 1; +} + diff --git a/src/world/level/tile/StemTile.h b/src/world/level/tile/StemTile.hpp similarity index 97% rename from src/world/level/tile/StemTile.h rename to src/world/level/tile/StemTile.hpp index c94129b..166cdac 100755 --- a/src/world/level/tile/StemTile.h +++ b/src/world/level/tile/StemTile.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Bush.h" +#include "Bush.hpp" class StemTile : public Bush { typedef Bush super; public: diff --git a/src/world/level/tile/StoneSlabTile.cpp b/src/world/level/tile/StoneSlabTile.cpp index 938f83d..1674e07 100755 --- a/src/world/level/tile/StoneSlabTile.cpp +++ b/src/world/level/tile/StoneSlabTile.cpp @@ -1,155 +1,155 @@ -#include "StoneSlabTile.h" -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" -#include "../../Facing.h" - -const std::string StoneSlabTile::SLAB_NAMES[] = { - "stone", "sand", "wood", "cobble", "brick", "smoothStoneBrick" -}; -const int StoneSlabTile::SLAB_NAMES_COUNT = sizeof(SLAB_NAMES) / sizeof(std::string); - -StoneSlabTile::StoneSlabTile(int id, bool fullSize) -: Tile(id, 6, Material::stone) -{ - this->fullSize = fullSize; - - if (!fullSize) { - setShape(0, 0, 0, 1, 0.5f, 1); - } - setLightBlock(255); -} - -void StoneSlabTile::updateShape(LevelSource* level, int x, int y, int z) -{ - if (fullSize) { - setShape(0, 0, 0, 1, 1, 1); - } else { - bool upper = (level->getData(x, y, z) & TOP_SLOT_BIT) != 0; - if (upper) { - setShape(0, 0.5f, 0, 1, 1, 1); - } else { - setShape(0, 0, 0, 1, 0.5f, 1); - } - } -} - -void StoneSlabTile::updateDefaultShape() -{ - if (fullSize) { - setShape(0, 0, 0, 1, 1, 1); - } else { - setShape(0, 0, 0, 1, 0.5f, 1); - } -} - -int StoneSlabTile::getTexture(int face, int data) { - data = data & TYPE_MASK; - if (data == STONE_SLAB) { - if (face <= 1) return 6; - return 5; - } else if (data == SAND_SLAB) { - if (face == Facing::DOWN) return 13 * 16; - if (face == Facing::UP) return 11 * 16; - return 12 * 16; - } else if (data == WOOD_SLAB) { - return 4; - } else if (data == COBBLESTONE_SLAB) { - return 16; - } else if (data == BRICK_SLAB) { - return Tile::redBrick->tex; - } else if (data == SMOOTHBRICK_SLAB) { - return Tile::stoneBrickSmooth->tex; - } - return 6; -} - -int StoneSlabTile::getTexture(int face) { - return getTexture(face, 0); -} - -bool StoneSlabTile::isSolidRender() { - return fullSize; -} - -int StoneSlabTile::getPlacedOnFaceDataValue(Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) -{ - if (fullSize) return itemValue; - - if (face == Facing::DOWN || (face != Facing::UP && clickY > 0.5)) { - return itemValue | TOP_SLOT_BIT; - } - return itemValue; -} - -/* -void StoneSlabTile::onPlace(Level* level, int x, int y, int z) { - if (this != Tile::stoneSlabHalf) Tile::onPlace(level, x, y, z); - int below = level->getTile(x, y - 1, z); - - int myData = level->getData(x, y, z); - int belowData = level->getData(x, y - 1, z); - - if (myData != belowData) { - return; - } - - if (below == Tile::stoneSlabHalf->id) { - level->setTile(x, y, z, 0); - level->setTileAndData(x, y - 1, z, Tile::stoneSlab->id, myData); - } -} -*/ - -int StoneSlabTile::getResource(int data, Random* random) { - return Tile::stoneSlabHalf->id; -} - -int StoneSlabTile::getResourceCount(Random* random) { - if (fullSize) { - return 2; - } - return 1; -} - -bool StoneSlabTile::isCubeShaped() { - return fullSize; -} - -void StoneSlabTile::addAABBs( Level* level, int x, int y, int z, const AABB* box, std::vector& boxes ) { - updateShape(level, x, y, z); - super::addAABBs(level, x, y, z, box, boxes); -} - -static bool isHalfSlab(int tileId) { - return tileId == Tile::stoneSlabHalf->id;// || tileId == Tile::woodSlabHalf->id; -} - -bool StoneSlabTile::shouldRenderFace(LevelSource* level, int x, int y, int z, int face) { - - if (fullSize) return super::shouldRenderFace(level, x, y, z, face); - - if (face != Facing::UP && face != Facing::DOWN && !super::shouldRenderFace(level, x, y, z, face)) { - return false; - } - - int ox = x, oy = y, oz = z; - ox += Facing::STEP_X[Facing::OPPOSITE_FACING[face]]; - oy += Facing::STEP_Y[Facing::OPPOSITE_FACING[face]]; - oz += Facing::STEP_Z[Facing::OPPOSITE_FACING[face]]; - - bool isUpper = (level->getData(ox, oy, oz) & TOP_SLOT_BIT) != 0; - if (isUpper) { - if (face == Facing::DOWN) return true; - if (face == Facing::UP && super::shouldRenderFace(level, x, y, z, face)) return true; - return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) != 0); - } else { - if (face == Facing::UP) return true; - if (face == Facing::DOWN && super::shouldRenderFace(level, x, y, z, face)) return true; - return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) == 0); - } -} - -int StoneSlabTile::getSpawnResourcesAuxValue(int data) { - return data & TYPE_MASK; -} +#include "StoneSlabTile.hpp" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" +#include "world/Facing.hpp" + +const std::string StoneSlabTile::SLAB_NAMES[] = { + "stone", "sand", "wood", "cobble", "brick", "smoothStoneBrick" +}; +const int StoneSlabTile::SLAB_NAMES_COUNT = sizeof(SLAB_NAMES) / sizeof(std::string); + +StoneSlabTile::StoneSlabTile(int id, bool fullSize) +: Tile(id, 6, Material::stone) +{ + this->fullSize = fullSize; + + if (!fullSize) { + setShape(0, 0, 0, 1, 0.5f, 1); + } + setLightBlock(255); +} + +void StoneSlabTile::updateShape(LevelSource* level, int x, int y, int z) +{ + if (fullSize) { + setShape(0, 0, 0, 1, 1, 1); + } else { + bool upper = (level->getData(x, y, z) & TOP_SLOT_BIT) != 0; + if (upper) { + setShape(0, 0.5f, 0, 1, 1, 1); + } else { + setShape(0, 0, 0, 1, 0.5f, 1); + } + } +} + +void StoneSlabTile::updateDefaultShape() +{ + if (fullSize) { + setShape(0, 0, 0, 1, 1, 1); + } else { + setShape(0, 0, 0, 1, 0.5f, 1); + } +} + +int StoneSlabTile::getTexture(int face, int data) { + data = data & TYPE_MASK; + if (data == STONE_SLAB) { + if (face <= 1) return 6; + return 5; + } else if (data == SAND_SLAB) { + if (face == Facing::DOWN) return 13 * 16; + if (face == Facing::UP) return 11 * 16; + return 12 * 16; + } else if (data == WOOD_SLAB) { + return 4; + } else if (data == COBBLESTONE_SLAB) { + return 16; + } else if (data == BRICK_SLAB) { + return Tile::redBrick->tex; + } else if (data == SMOOTHBRICK_SLAB) { + return Tile::stoneBrickSmooth->tex; + } + return 6; +} + +int StoneSlabTile::getTexture(int face) { + return getTexture(face, 0); +} + +bool StoneSlabTile::isSolidRender() { + return fullSize; +} + +int StoneSlabTile::getPlacedOnFaceDataValue(Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) +{ + if (fullSize) return itemValue; + + if (face == Facing::DOWN || (face != Facing::UP && clickY > 0.5)) { + return itemValue | TOP_SLOT_BIT; + } + return itemValue; +} + +/* +void StoneSlabTile::onPlace(Level* level, int x, int y, int z) { + if (this != Tile::stoneSlabHalf) Tile::onPlace(level, x, y, z); + int below = level->getTile(x, y - 1, z); + + int myData = level->getData(x, y, z); + int belowData = level->getData(x, y - 1, z); + + if (myData != belowData) { + return; + } + + if (below == Tile::stoneSlabHalf->id) { + level->setTile(x, y, z, 0); + level->setTileAndData(x, y - 1, z, Tile::stoneSlab->id, myData); + } +} +*/ + +int StoneSlabTile::getResource(int data, Random* random) { + return Tile::stoneSlabHalf->id; +} + +int StoneSlabTile::getResourceCount(Random* random) { + if (fullSize) { + return 2; + } + return 1; +} + +bool StoneSlabTile::isCubeShaped() { + return fullSize; +} + +void StoneSlabTile::addAABBs( Level* level, int x, int y, int z, const AABB* box, std::vector& boxes ) { + updateShape(level, x, y, z); + super::addAABBs(level, x, y, z, box, boxes); +} + +static bool isHalfSlab(int tileId) { + return tileId == Tile::stoneSlabHalf->id;// || tileId == Tile::woodSlabHalf->id; +} + +bool StoneSlabTile::shouldRenderFace(LevelSource* level, int x, int y, int z, int face) { + + if (fullSize) return super::shouldRenderFace(level, x, y, z, face); + + if (face != Facing::UP && face != Facing::DOWN && !super::shouldRenderFace(level, x, y, z, face)) { + return false; + } + + int ox = x, oy = y, oz = z; + ox += Facing::STEP_X[Facing::OPPOSITE_FACING[face]]; + oy += Facing::STEP_Y[Facing::OPPOSITE_FACING[face]]; + oz += Facing::STEP_Z[Facing::OPPOSITE_FACING[face]]; + + bool isUpper = (level->getData(ox, oy, oz) & TOP_SLOT_BIT) != 0; + if (isUpper) { + if (face == Facing::DOWN) return true; + if (face == Facing::UP && super::shouldRenderFace(level, x, y, z, face)) return true; + return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) != 0); + } else { + if (face == Facing::UP) return true; + if (face == Facing::DOWN && super::shouldRenderFace(level, x, y, z, face)) return true; + return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) == 0); + } +} + +int StoneSlabTile::getSpawnResourcesAuxValue(int data) { + return data & TYPE_MASK; +} diff --git a/src/world/level/tile/StoneSlabTile.h b/src/world/level/tile/StoneSlabTile.hpp similarity index 98% rename from src/world/level/tile/StoneSlabTile.h rename to src/world/level/tile/StoneSlabTile.hpp index eca1e17..5023189 100755 --- a/src/world/level/tile/StoneSlabTile.h +++ b/src/world/level/tile/StoneSlabTile.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.level.tile; -#include "Tile.h" +#include "Tile.hpp" class Level; class LevelSource; diff --git a/src/world/level/tile/StoneTile.h b/src/world/level/tile/StoneTile.hpp similarity index 74% rename from src/world/level/tile/StoneTile.h rename to src/world/level/tile/StoneTile.hpp index 608446c..374ee5e 100755 --- a/src/world/level/tile/StoneTile.h +++ b/src/world/level/tile/StoneTile.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" -#include "Tile.h" +#include "Tile.hpp" class StoneTile: public Tile { diff --git a/src/world/level/tile/StonecutterTile.h b/src/world/level/tile/StonecutterTile.hpp similarity index 79% rename from src/world/level/tile/StonecutterTile.h rename to src/world/level/tile/StonecutterTile.hpp index ea3c4cf..a52b994 100755 --- a/src/world/level/tile/StonecutterTile.h +++ b/src/world/level/tile/StonecutterTile.hpp @@ -1,9 +1,9 @@ #pragma once -#include "Tile.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../entity/player/Player.h" +#include "Tile.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/entity/player/Player.hpp" class StonecutterTile: public Tile { diff --git a/src/world/level/tile/TallGrass.cpp b/src/world/level/tile/TallGrass.cpp index 7a0350c..5b34bd9 100755 --- a/src/world/level/tile/TallGrass.cpp +++ b/src/world/level/tile/TallGrass.cpp @@ -1,55 +1,55 @@ -#include "TallGrass.h" -#include "../FoliageColor.h" -#include "../../entity/player/Player.h" -#include "../../item/Item.h" -#include "../../item/ShearsItem.h" - -TallGrass::TallGrass( int id, int tex ) : super(id, tex, Material::replaceable_plant) { - float ss = 0.4f; - setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.8f, 0.5f + ss); -} - -int TallGrass::getTexture( int face, int data ) { - if(data == TALL_GRASS) return tex; - if(data == FERN) return tex + 16 + 1; - if(data == DEAD_SHRUB) return tex + 16; - return tex; -} - -int TallGrass::getColor() { - /*double temp = 0.5; - double rain = 1.0; - return GrassColor.get(temp, rain);*/ - return 0x339933; -} - -int TallGrass::getColor( int auxData ) { - if(auxData == DEAD_SHRUB) return 0xffffffff; - return FoliageColor::getDefaultColor(); -} - -int TallGrass::getColor( LevelSource* level, int x, int y, int z ) { - int d = level->getData(x, y, z); - if (d == DEAD_SHRUB) return 0xffffff; - - return 0x339933;//level->getBiome(x, z)->getGrassColor(); -} - -int TallGrass::getResource( int data, Random* random ) { - if (random->nextInt(8) == 0) { - return Item::seeds_wheat->id; - } - return -1; -} - -void TallGrass::playerDestroy( Level* level, Player* player, int x, int y, int z, int data ) { - if (!level->isClientSide && player->getSelectedItem() != NULL && player->getSelectedItem()->id == Item::shears->id) { - //player->awardStat(Stats.blockMined[id], 1); - - // drop leaf block instead of sapling - ItemInstance itemInstance(Tile::tallgrass, 1, data); - popResource(level, x, y, z, itemInstance); - } else { - super::playerDestroy(level, player, x, y, z, data); - } -} +#include "TallGrass.hpp" +#include "world/level/FoliageColor.hpp" +#include "world/entity/player/Player.hpp" +#include "world/item/Item.hpp" +#include "world/item/ShearsItem.hpp" + +TallGrass::TallGrass( int id, int tex ) : super(id, tex, Material::replaceable_plant) { + float ss = 0.4f; + setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.8f, 0.5f + ss); +} + +int TallGrass::getTexture( int face, int data ) { + if(data == TALL_GRASS) return tex; + if(data == FERN) return tex + 16 + 1; + if(data == DEAD_SHRUB) return tex + 16; + return tex; +} + +int TallGrass::getColor() { + /*double temp = 0.5; + double rain = 1.0; + return GrassColor.get(temp, rain);*/ + return 0x339933; +} + +int TallGrass::getColor( int auxData ) { + if(auxData == DEAD_SHRUB) return 0xffffffff; + return FoliageColor::getDefaultColor(); +} + +int TallGrass::getColor( LevelSource* level, int x, int y, int z ) { + int d = level->getData(x, y, z); + if (d == DEAD_SHRUB) return 0xffffff; + + return 0x339933;//level->getBiome(x, z)->getGrassColor(); +} + +int TallGrass::getResource( int data, Random* random ) { + if (random->nextInt(8) == 0) { + return Item::seeds_wheat->id; + } + return -1; +} + +void TallGrass::playerDestroy( Level* level, Player* player, int x, int y, int z, int data ) { + if (!level->isClientSide && player->getSelectedItem() != NULL && player->getSelectedItem()->id == Item::shears->id) { + //player->awardStat(Stats.blockMined[id], 1); + + // drop leaf block instead of sapling + ItemInstance itemInstance(Tile::tallgrass, 1, data); + popResource(level, x, y, z, itemInstance); + } else { + super::playerDestroy(level, player, x, y, z, data); + } +} diff --git a/src/world/level/tile/TallGrass.h b/src/world/level/tile/TallGrass.hpp similarity index 96% rename from src/world/level/tile/TallGrass.h rename to src/world/level/tile/TallGrass.hpp index edb26a2..9b890f8 100755 --- a/src/world/level/tile/TallGrass.h +++ b/src/world/level/tile/TallGrass.hpp @@ -1,5 +1,5 @@ #pragma once -#include "Bush.h" +#include "Bush.hpp" class Pos; class TallGrass : public Bush { public: diff --git a/src/world/level/tile/ThinFenceTile.h b/src/world/level/tile/ThinFenceTile.hpp similarity index 97% rename from src/world/level/tile/ThinFenceTile.h rename to src/world/level/tile/ThinFenceTile.hpp index ccbeecf..e1f54e2 100755 --- a/src/world/level/tile/ThinFenceTile.h +++ b/src/world/level/tile/ThinFenceTile.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level.tile; -#include "Tile.h" -#include "../material/Material.h" -#include "../../phys/AABB.h" +#include "Tile.hpp" +#include "world/level/material/Material.hpp" +#include "world/phys/AABB.hpp" class ThinFenceTile: public Tile { diff --git a/src/world/level/tile/Tile.cpp b/src/world/level/tile/Tile.cpp index a5acf7a..2d35b65 100755 --- a/src/world/level/tile/Tile.cpp +++ b/src/world/level/tile/Tile.cpp @@ -1,747 +1,747 @@ -#include "TileInclude.h" -#include "../Level.h" -#include "../../entity/player/Player.h" -#include "../../entity/item/ItemEntity.h" -#include "../../item/Item.h" -#include "../../item/TileItem.h" - -#include "../../../util/Random.h" -//#include "locale/Descriptive.h" -//#include "stats/Stats.h" -#include "../../entity/Entity.h" -#include "../LevelSource.h" -#include "../material/Material.h" -#include "../../phys/AABB.h" -#include "../../phys/HitResult.h" -#include "../../phys/Vec3.h" -#include "../../../locale/I18n.h" -#include "../../item/ClothTileItem.h" - -#include "../../item/AuxDataTileItem.h" -#include "../../item/LeafTileItem.h" -#include "../../item/StoneSlabTileItem.h" -#include "../../item/SaplingTileItem.h" -#include "../../item/ItemCategory.h" - -const int Tile::RENDERLAYER_OPAQUE = 0; -const int Tile::RENDERLAYER_ALPHATEST = 1; -const int Tile::RENDERLAYER_BLEND = 2; - -const std::string Tile::TILE_DESCRIPTION_PREFIX("tile."); - -const Tile::SoundType Tile::SOUND_NORMAL("stone", 1, 1); -const Tile::SoundType Tile::SOUND_WOOD("wood", 1, 1); -const Tile::SoundType Tile::SOUND_GRAVEL("gravel", 1, 1); -const Tile::SoundType Tile::SOUND_GRASS("grass", 0.5f, 1); -const Tile::SoundType Tile::SOUND_STONE("stone", 1, 1); -const Tile::SoundType Tile::SOUND_METAL("stone", 1, 1.5f); -const Tile::SoundType Tile::SOUND_GLASS("stone", "random.glass", 1, 1); -const Tile::SoundType Tile::SOUND_CLOTH("cloth", 1, 1); - -#ifdef PRE_ANDROID23 - const Tile::SoundType Tile::SOUND_SAND("sand", 0.45f, 1); -#else - const Tile::SoundType Tile::SOUND_SAND("sand", "step.gravel", 1, 1); -#endif - -const Tile::SoundType Tile::SOUND_SILENT("", 0, 0); - -Tile* Tile::tiles[] = {NULL}; -int Tile::lightBlock[] = {0}; -int Tile::lightEmission[] = {0}; -bool Tile::solid[] = {false}; -bool Tile::isEntityTile[] = {false}; -bool Tile::translucent[] = {true, false}; // @trans: translucent, @trans "asbMax", some more like "*conditon" -bool Tile::shouldTick[] = {false}; -bool Tile::sendTileData[] = {false}; - -Tile* Tile::sand = NULL; -Tile* Tile::sandStone = NULL; -const int SANDSTONE_TEXTURES[] = { 0 + 16 * 12, 5 + 16 * 14, 6 + 16 * 14 }; -const int SANDSTONE_TEXTURE_COUNT = 3; - -Tile* Tile::stoneBrick = NULL; -Tile* Tile::redBrick = NULL; -Tile* Tile::wood = NULL; -Tile* Tile::sapling = NULL; -Tile* Tile::glass = NULL; -Tile* Tile::web = NULL; -Tile* Tile::thinGlass = NULL; -Tile* Tile::calmWater = NULL; -Tile* Tile::calmLava = NULL; -Tile* Tile::gravel = NULL; -Tile* Tile::rock = NULL; -Tile* Tile::unbreakable = NULL; -Tile* Tile::dirt = NULL; -Tile* Tile::grass = NULL; -Tile* Tile::ice = NULL; -Tile* Tile::clay = NULL; -Tile* Tile::farmland = NULL; -Tile* Tile::stoneSlab = NULL; -Tile* Tile::stoneSlabHalf=NULL; -Tile* Tile::cloth = NULL; -Tile* Tile::flower = NULL; -Tile* Tile::rose = NULL; -Tile* Tile::mushroom1 = NULL; -Tile* Tile::mushroom2 = NULL; -Tile* Tile::topSnow = NULL; -Tile* Tile::treeTrunk = NULL; -Tile* Tile::snow = NULL; -LeafTile* Tile::leaves = NULL; -Tile* Tile::emeraldOre = NULL; -Tile* Tile::redStoneOre = NULL; -Tile* Tile::redStoneOre_lit = NULL; -Tile* Tile::goldOre = NULL; -Tile* Tile::ironOre = NULL; -Tile* Tile::coalOre = NULL; -Tile* Tile::lapisOre = NULL; -Tile* Tile::lapisBlock = NULL; -Tile* Tile::reeds = NULL; -Tile* Tile::ladder = NULL; -Tile* Tile::obsidian = NULL; -Tile* Tile::tnt = NULL; -Tile* Tile::bookshelf = NULL; -Tile* Tile::sign = NULL; -Tile* Tile::wallSign = NULL; -Tile* Tile::mossStone = NULL; -Tile* Tile::torch = NULL; -Tile* Tile::water = NULL; -Tile* Tile::lava = NULL; -FireTile* Tile::fire = NULL; -Tile* Tile::invisible_bedrock = NULL; -Tile* Tile::goldBlock = NULL; -Tile* Tile::ironBlock = NULL; -Tile* Tile::emeraldBlock= NULL; -Tile* Tile::workBench = NULL; -Tile* Tile::stonecutterBench = NULL; -Tile* Tile::crops = NULL; -Tile* Tile::furnace = NULL; -Tile* Tile::furnace_lit = NULL; -Tile* Tile::chest = NULL; -Tile* Tile::lightGem = NULL; -Tile* Tile::stairs_wood = NULL; -Tile* Tile::stairs_stone= NULL; -Tile* Tile::stairs_brick= NULL; -Tile* Tile::door_wood = NULL; -Tile* Tile::door_iron = NULL; -Tile* Tile::cactus = NULL; - -Tile* Tile::melon = NULL; -Tile* Tile::melonStem = NULL; - -Tile* Tile::bed = NULL; -Tile* Tile::tallgrass = NULL; -Tile* Tile::trapdoor = NULL; -Tile* Tile::stoneBrickSmooth = NULL; -const int STONE_BRICK_TEXTURES[] = { 6 + 16 * 3, 4 + 16 * 6, 5 + 16 * 6 }; -const int STONE_BRICK_TEXTURE_COUNT = 3; - -Tile* Tile::fence = NULL; -Tile* Tile::fenceGate = NULL; - -Tile* Tile::info_updateGame1 = NULL; -Tile* Tile::info_updateGame2 = NULL; -Tile* Tile::info_reserved6 = NULL; -Tile* Tile::grass_carried = NULL; -LeafTile* Tile::leaves_carried = NULL; - -Tile* Tile::netherReactor = NULL; -Tile* Tile::glowingObsidian = NULL; - -Tile* Tile::stairs_stoneBrickSmooth = NULL; -Tile* Tile::netherBrick = NULL; -Tile* Tile::netherrack = NULL; -Tile* Tile::stairs_netherBricks = NULL; -Tile* Tile::stairs_sandStone = NULL; -Tile* Tile::quartzBlock = NULL; -Tile* Tile::stairs_quartz = NULL; - -/*static*/ -void Tile::initTiles() { - rock = (new StoneTile(1, 1))->init()->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stone"); - grass = (GrassTile*) (new GrassTile(2))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("grass"); - dirt = (new DirtTile(3, 2))->init()->setDestroyTime(0.5f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("dirt"); - stoneBrick = (new Tile(4, 16, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stonebrick"); - wood = (new Tile(5, 4, Material::wood))->init()->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("wood"); - sapling = (new Sapling(6, 15))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("sapling");//->sendTileData(); - unbreakable = (new Tile(7, 17, Material::stone))->init()->setDestroyTime(-1)->setExplodeable(6000000)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("bedrock"); - water = (new LiquidTileDynamic(8, Material::water))->init()->setDestroyTime(100.0f)->setLightBlock(3)->setCategory(ItemCategory::Structures)->setDescriptionId("water"); - calmWater = (new LiquidTileStatic(9, Material::water))->init()->setDestroyTime(100.0f)->setLightBlock(3)->setCategory(ItemCategory::Structures)->setDescriptionId("water"); - lava = (new LiquidTileDynamic(10, Material::lava))->init()->setDestroyTime(00.0f)->setLightEmission(1.0f)->setLightBlock(255)->setCategory(ItemCategory::Structures)->setDescriptionId("lava"); // 00.0? - calmLava = (new LiquidTileStatic(11, Material::lava))->init()->setDestroyTime(100.0f)->setLightEmission(1.0f)->setLightBlock(255)->setCategory(ItemCategory::Structures)->setDescriptionId("lava"); - sand = (new HeavyTile(12, 18))->init()->setDestroyTime(0.5f)->setSoundType(SOUND_SAND)->setCategory(ItemCategory::Structures)->setDescriptionId("sand"); - gravel = (new GravelTile(13, 19))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("gravel"); - goldOre = (new OreTile(14, 32))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("oreGold"); - ironOre = (new OreTile(15, 33))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("oreIron"); - coalOre = (new OreTile(16, 34))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("oreCoal"); - treeTrunk = (new TreeTile(17))->init()->setDestroyTime(2.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("log"); - leaves = (LeafTile*) (new LeafTile(18, 4 + 3 * 16))->init()->setDestroyTime(0.2f)->setLightBlock(1)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("leaves"); - - glass = (new GlassTile(20, 49, Material::glass, false))->init()->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setCategory(ItemCategory::Structures)->setDescriptionId("glass"); - lapisOre = (new OreTile(21, 10 * 16))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("oreLapis"); - lapisBlock = (new Tile(22, 9 * 16, Material::stone))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockLapis"); - sandStone = (new SandStoneTile(24, (const int*)&SANDSTONE_TEXTURES, SANDSTONE_TEXTURE_COUNT))->init()->setSoundType(SOUND_STONE)->setDestroyTime(0.8f)->setCategory(ItemCategory::Structures)->setDescriptionId("sandStone"); - bed = (new BedTile(26))->init()->setDestroyTime(0.2f)->setCategory(ItemCategory::Structures)->setDescriptionId("bed"); - web = (new WebTile(30, 11))->init()->setLightBlock(1)->setDestroyTime(4.0f)->setCategory(ItemCategory::Decorations)->setDescriptionId("web"); - tallgrass = (new TallGrass(31, 2 * 16 + 7))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("tallgrass"); - cloth = (new ClothTile(35))->init()->setDestroyTime(0.8f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("cloth"); - - flower = (new Bush(37, 13))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("flower"); - rose = (new Bush(38, 12))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("rose"); - mushroom1 = (new Mushroom(39, 13 + 16))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setLightEmission(2 / 16.0f)->setCategory(ItemCategory::Decorations)->setDescriptionId("mushroom"); - mushroom2 = (new Mushroom(40, 12 + 16))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("mushroom"); - goldBlock = (new MetalTile(41, 39 - 16))->init()->setDestroyTime(3.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockGold"); - ironBlock = (new MetalTile(42, 38 - 16))->init()->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockIron"); - stoneSlab = (new StoneSlabTile(43, true))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stoneSlab"); - stoneSlabHalf=(new StoneSlabTile(44, false))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stoneSlab"); - redBrick = (new Tile(45, 7, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("brick"); - tnt = (new TntTile(46, 8))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Tools)->setDescriptionId("tnt"); - bookshelf = (new BookshelfTile(47, 35))->init()->setDestroyTime(1.5f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Decorations)->setDescriptionId("bookshelf"); - mossStone = (new Tile(48, 36, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stoneMoss"); - obsidian = (new ObsidianTile(49, 37, false))->init()->setDestroyTime(10.0f)->setExplodeable(2000)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("obsidian"); - torch = (new TorchTile(50, 5 * 16))->init()->setDestroyTime(0.0f)->setLightEmission(15 / 16.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Tools)->setDescriptionId("torch"); - - stairs_wood = (new StairTile(53, wood))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsWood"); - chest = (new ChestTile(54))->init()->setCategory(ItemCategory::Structures)->setDestroyTime(2.5f)->setSoundType(SOUND_WOOD)->setDescriptionId("chest");//->sendTileData(); - - emeraldOre = (new OreTile(56, 16 * 3 + 2))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("oreDiamond"); - emeraldBlock= (new MetalTile(57, 40 - 16))->init()->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockDiamond"); - workBench = (new WorkbenchTile(58))->init()->setDestroyTime(2.5f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("workbench"); - crops = (new CropTile(59, 8 + 5 * 16))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("crops");//->sendTileData(); - farmland = (new FarmTile(60))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("farmland"); - furnace = (new FurnaceTile(61, false))->init()->setDestroyTime(3.5f)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("furnace");//.sendTileData(); - furnace_lit = (new FurnaceTile(62, true))->init()->setDestroyTime(3.5f)->setSoundType(SOUND_STONE)->setLightEmission(14 / 16.0f)->setCategory(ItemCategory::Structures)->setDescriptionId("furnace");//.sendTileData(); - sign = (new SignTile(63, TileEntityType::Sign, true))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Decorations)->setDescriptionId("sign");//->sendTileData(); - door_wood = (new DoorTile(64, Material::wood))->init()->setDestroyTime(3.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("doorWood"); - ladder = (new LadderTile(65, 3 + 5 * 16))->init()->setDestroyTime(0.4f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("ladder"); - - stairs_stone= (new StairTile(67, stoneBrick))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsStone"); - wallSign = (new SignTile(68, TileEntityType::Sign, false))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Decorations)->setDescriptionId("sign");//->sendTileData(); - - door_iron = (new DoorTile(71, Material::metal))->init()->setDestroyTime(5.0f)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Structures)->setDescriptionId("doorIron"); - - redStoneOre = (new RedStoneOreTile(73, 16 * 3 + 3, false))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("oreRedstone"); - redStoneOre_lit = (new RedStoneOreTile(74, 16 * 3 + 3, true))->init()->setDestroyTime(3.0f)->setLightEmission(10 / 16.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("oreRedstone"); - - topSnow = (new TopSnowTile(78, 16 * 4 + 2))->init()->setDestroyTime(0.1f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("snow"); - ice = (new IceTile(79, 16 * 4 + 3))->init()->setDestroyTime(0.5f)->setLightBlock(3)->setSoundType(SOUND_GLASS)->setCategory(ItemCategory::Structures)->setDescriptionId("ice"); - snow = (new SnowTile(80, 16 * 4 + 2))->init()->setDestroyTime(0.2f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("snow"); - cactus = (new CactusTile(81, 16 * 4 + 6))->init()->setDestroyTime(0.4f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("cactus"); - clay = (new ClayTile(82, 16 * 4 + 8))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("clay"); - reeds = (new ReedTile(83, 16 * 4 + 9))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("reeds"); - - fence = (new FenceTile(85, 4))->init()->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("fence"); - - netherrack = (new Tile(87, 7 + 6 * 16, Material::stone))->init()->setDestroyTime(0.4f)->setSoundType(SOUND_STONE)->setDescriptionId("hellrock"); - //hellSand = (new HellSandTile(88, 8 + 6 * 16, Material::sand))->init()->setDestroyTime(0.5f)->setSoundType(SOUND_SAND)->setDescriptionId("hellsand"); - - lightGem = (new LightGemTile(89, 9 + 16 * 6, Material::glass))->init()->setDestroyTime(0.3f)->setCategory(ItemCategory::Structures)->setSoundType(SOUND_GLASS)->setLightEmission(1.0f)->setDescriptionId("lightgem"); - invisible_bedrock = (new InvisibleTile(95, 0, Material::stone))->init()->setDestroyTime(-1)->setExplodeable(6000000);//->setSoundType(SOUND_SILENT); - trapdoor = (new TrapDoorTile(96, Material::wood))->init()->setDestroyTime(3.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("trapdoor");//->sendTileData(); - - stoneBrickSmooth = (new MultiTextureTile(98, (const int*)&STONE_BRICK_TEXTURES, STONE_BRICK_TEXTURE_COUNT, Material::stone))->init()->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stonebricksmooth"); - - thinGlass = (new ThinFenceTile(102, 1 + 3 * 16, 4 + 9 * 16, Material::glass, false))->init()->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setCategory(ItemCategory::Structures)->setDescriptionId("thinGlass"); - melon = (new MelonTile(103))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("melon"); - melonStem = (new StemTile(105, Tile::melon))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("pumpkinStem");//->sendTileData(); - fenceGate = (new FenceGateTile(107, 4))->init()->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("fenceGate");//->sendTileData(); - stairs_brick = (new StairTile(108, Tile::redBrick))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsBrick");//->sendTileData(); - - stairs_stoneBrickSmooth = (new StairTile(109, Tile::stoneBrickSmooth))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsStoneBrickSmooth");//->sendTileData(); - netherBrick = (new Tile(112, 0 + 14 * 16, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("netherBrick"); - stairs_netherBricks = (new StairTile(114, Tile::netherBrick))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsNetherBrick");//->sendTileData(); - stairs_sandStone = (new StairTile(128, Tile::sandStone))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsSandStone");//->sendTileData(); - - quartzBlock = (new QuartzBlockTile(155))->init()->setSoundType(SOUND_STONE)->setDestroyTime(0.8f)->setCategory(ItemCategory::Structures)->setDescriptionId("quartzBlock"); - stairs_quartz = (new StairTile(156, Tile::quartzBlock))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsQuartz");//->sendTileData(); - - // - // Special tiles for Pocket Edition is placed at high IDs - // - stonecutterBench= (new StonecutterTile(245))->init()->setDestroyTime(2.5f)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stonecutter"); - glowingObsidian = (new ObsidianTile(246, 10 + 16 * 13, true))->init()->setDestroyTime(10.0f)->setLightEmission(14 / 16.0f)->setExplodeable(2000)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("glowingobsidian"); - netherReactor = (new NetherReactor(247, 10 + 14 * 16, Material::metal))->init()->setDestroyTime(3.0f)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Structures)->setDescriptionId("netherreactor"); - info_updateGame1= (new Tile(248, 252, Material::dirt))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("info_update"); - info_updateGame2= (new Tile(249, 253, Material::dirt))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("info_update"); - grass_carried = (new CarriedTile(253, 3, 12*16 + 12))->init()->setDescriptionId("grass"); - leaves_carried = (LeafTile*) (new LeafTile(254, 11 + 14 * 16))->init()->setDestroyTime(0.2f)->setLightBlock(1)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("leaves"); - info_reserved6 = (new Tile(255, Material::dirt))->init(); - - // - // Stuff that need to be inited in a specific order (i.e. after the other tiles have been created) - // - fire = (FireTile*) (new FireTile(51, 1 * 16 + 15))->init()->setDestroyTime(0.0f)->setLightEmission(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("fire"); - - // - // Special case for certain items since they can have different icons - // @note: Make sure those different items are handled in ItemInHandRenderer::renderItem - // - Item::items[cloth->id] = (new ClothTileItem(cloth->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("cloth"); - Item::items[treeTrunk->id] = (new AuxDataTileItem(treeTrunk->id - 256, treeTrunk))->setCategory(ItemCategory::Structures)->setDescriptionId("log"); - Item::items[stoneBrickSmooth->id] = (new AuxDataTileItem(stoneBrickSmooth->id - 256, stoneBrickSmooth))->setCategory(ItemCategory::Structures)->setDescriptionId("stonebricksmooth"); - Item::items[stoneSlabHalf->id] = (new StoneSlabTileItem(stoneSlabHalf->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("stoneSlab"); - Item::items[sapling->id] = (new SaplingTileItem(sapling->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("sapling"); - Item::items[leaves->id] = (new LeafTileItem(leaves->id - 256))->setCategory(ItemCategory::Decorations)->setDescriptionId("leaves"); - Item::items[sandStone->id] = (new AuxDataTileItem(sandStone->id - 256, sandStone))->setCategory(ItemCategory::Structures)->setDescriptionId("sandStone"); - - Item::items[quartzBlock->id] = (new AuxDataTileItem(quartzBlock->id - 256, quartzBlock))->setCategory(ItemCategory::Structures)->setDescriptionId("quartzBlock"); - - for (int i = 0; i < 256; i++) { - if (Tile::tiles[i] != NULL) { - if (Item::items[i] == NULL) { - Item::items[i] = new TileItem(i - 256); - Item::items[i]->category = Tile::tiles[i]->category; - } - // Check for missing category - if (Item::items[i]->category == -1) - LOGE("Error: Missing category for tile %d: %s\n", tiles[i]->id, tiles[i]->getDescriptionId().c_str()); - } - } -} - -/*static*/ -void Tile::teardownTiles() { - for (int i = 0; i < 256; ++i) - if (Tile::tiles[i]) { - delete Tile::tiles[i]; - Tile::tiles[i] = NULL; - } -} - -int Tile::transformToValidBlockId( int blockId ) { - return transformToValidBlockId(blockId, 0, 0, 0); -} - -int Tile::transformToValidBlockId( int blockId, int x, int y, int z ) { - if (blockId != 0 && Tile::tiles[blockId] == NULL) - return (((x + y + z)&1) == 1)? Tile::info_updateGame1->id : Tile::info_updateGame2->id; - return blockId; -} - - -Tile::Tile(int id, const Material* material) -: id(id), - material(material), - tex(1), - category(-1), - gravity(1.0f), - friction(0.6f), - soundType(&Tile::SOUND_NORMAL), - tmpBB(0,0,0,1,1,1), - xx0(0),yy0(0),zz0(0), - xx1(1),yy1(1),zz1(1) -{ - if (Tile::tiles[id]) { - printf("Slot %d is already occupied by %p when adding %p\n", id, &Tile::tiles[id], this); - } -} - -Tile::Tile( int id, int tex, const Material* material ) -: id(id), - tex(tex), - material(material), - category(-1), - gravity(1.0f), - friction(0.6f), - soundType(&Tile::SOUND_NORMAL), - tmpBB(0,0,0,1,1,1), - xx0(0),yy0(0),zz0(0), - xx1(1),yy1(1),zz1(1) -{ - if (Tile::tiles[id]) { - printf("Slot %d is already occupied by %p when adding %p\n", id, &Tile::tiles[id], this); - } -} - -//Tile* sendTileData() { -// Tile::sendTileData[id] = true; -// return this; -//} - -/*protected*/ -Tile* Tile::setLightEmission(float f) { - Tile::lightEmission[id] = (int) (Level::MAX_BRIGHTNESS * f); - return this; -} - -/*public static*/ -bool Tile::isFaceVisible(Level* level, int x, int y, int z, int f) { - switch (f) { - case Facing::DOWN : y--; break; - case Facing::UP : y++; break; - case Facing::NORTH: z--; break; - case Facing::SOUTH: z++; break; - case Facing::WEST : x--; break; - case Facing::EAST : x++; break; - } - return !level->isSolidRenderTile(x, y, z); -} - -/* private */ -Tile* Tile::init() { - Tile::tiles[id] = this; - setShape(xx0, yy0, zz0, xx1, yy1, zz1); // @attn - solid[id] = isSolidRender(); - lightBlock[id] = isSolidRender() ? 255 : 0; - translucent[id] = !material->blocksLight(); - return this; -} - -/*public virtual*/ -float Tile::getDestroyProgress(Player* player) { - if (destroySpeed < 0) return 0; - if (!player->canDestroy(this)) return 1 / destroySpeed / 100.0f; - return (player->getDestroySpeed(this) / destroySpeed) / 30.0f; -} - -/*public virtual*/ -HitResult Tile::clip(Level* level, int xt, int yt, int zt, const Vec3& A, const Vec3& B) { - updateShape(level, xt, yt, zt); - - //Stopwatch sw; - //sw.start(); - - Vec3 sub((float)xt, (float)yt, (float)zt); - Vec3 a = A - sub;//a.add((float)-xt, (float)-yt, (float)-zt); - Vec3 b = B - sub;//b.add((float)-xt, (float)-yt, (float)-zt); - - Vec3 xh0, xh1, yh0, yh1, zh0, zh1; - - bool bxh0 = a.clipX(b, xx0, xh0); - bool bxh1 = a.clipX(b, xx1, xh1); - - bool byh0 = a.clipY(b, yy0, yh0); - bool byh1 = a.clipY(b, yy1, yh1); - - bool bzh0 = a.clipZ(b, zz0, zh0); - bool bzh1 = a.clipZ(b, zz1, zh1); - - //if (!containsX(xh0)) xh0 = NULL; - if (!bxh0 || !containsX(xh0)) bxh0 = false; - if (!bxh1 || !containsX(xh1)) bxh1 = false; - if (!byh0 || !containsY(yh0)) byh0 = false; - if (!byh1 || !containsY(yh1)) byh1 = false; - if (!bzh0 || !containsZ(zh0)) bzh0 = false; - if (!bzh1 || !containsZ(zh1)) bzh1 = false; - Vec3* closest = NULL; - - //if (xh0 != NULL && (closest == NULL || a.distanceToSqr(xh0) < a.distanceToSqr(closest))) closest = xh0; - if (bxh0 && (closest == NULL || a.distanceToSqr(xh0) < a.distanceToSqr(*closest))) closest = &xh0; - if (bxh1 && (closest == NULL || a.distanceToSqr(xh1) < a.distanceToSqr(*closest))) closest = &xh1; - if (byh0 && (closest == NULL || a.distanceToSqr(yh0) < a.distanceToSqr(*closest))) closest = &yh0; - if (byh1 && (closest == NULL || a.distanceToSqr(yh1) < a.distanceToSqr(*closest))) closest = &yh1; - if (bzh0 && (closest == NULL || a.distanceToSqr(zh0) < a.distanceToSqr(*closest))) closest = &zh0; - if (bzh1 && (closest == NULL || a.distanceToSqr(zh1) < a.distanceToSqr(*closest))) closest = &zh1; - - if (closest == NULL) - return HitResult(); - - int face = -1; - - if (closest == &xh0) face = 4; - if (closest == &xh1) face = 5; - if (closest == &yh0) face = 0; - if (closest == &yh1) face = 1; - if (closest == &zh0) face = 2; - if (closest == &zh1) face = 3; - - //sw.stop(); - //sw.printEvery(5, ">>> "); - - return HitResult(xt, yt, zt, face, closest->add((float)xt, (float)yt, (float)zt)); -} - -/*virtual*/ -void Tile::spawnResources(Level* level, int x, int y, int z, int data, float odds) { - if (level->isClientSide) return; - - int count = getResourceCount(&level->random); - for (int i = 0; i < count; i++) { - if (level->random.nextFloat() > odds) continue; - int type = getResource(data, &level->random); - if (type <= 0) continue; - const float s = 0.7f; - float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; - float yo = level->random.nextFloat() * s + (1 - s) * 0.5f; - float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; - ItemEntity* item = new ItemEntity(level, x + xo, y + yo, z + zo, ItemInstance(type, 1, getSpawnResourcesAuxValue(data))); - item->throwTime = 10; - level->addEntity(item); - } -} - -void Tile::spawnResources( Level* level, int x, int y, int z, int data ) -{ - spawnResources(level, x, y, z, data, 1); -} - -void Tile::popResource(Level* level, int x, int y, int z, const ItemInstance& itemInstance) { - if (level->isClientSide || level->getLevelData()->getGameType() == GameType::Creative) return; - - float s = 0.7f; - float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; - float yo = level->random.nextFloat() * s + (1 - s) * 0.5f; - float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; - - ItemEntity* item = new ItemEntity(level, x + xo, y + yo, z + zo, itemInstance); - item->throwTime = 10; - level->addEntity(item); -} - - -void Tile::destroy( Level* level, int x, int y, int z, int data ) -{ -} - -bool Tile::isCubeShaped() -{ - return true; -} - -int Tile::getRenderShape() -{ - return SHAPE_BLOCK; -} - -float Tile::getBrightness( LevelSource* level, int x, int y, int z ) -{ - return level->getBrightness(x, y, z); -} - -bool Tile::shouldRenderFace( LevelSource* level, int x, int y, int z, int face ) -{ - if (face == 0 && y == -1) return false; - // For fixed size worlds //@todo: external constants rather than magic numbers - if (face == 2 && z == -1) return false; - if (face == 3 && z == 256) return false; - if (face == 4 && x == -1) return false; - if (face == 5 && x == 256) return false; - // Common - if (face == 0 && yy0 > 0) return true; - if (face == 1 && yy1 < 1) return true; - if (face == 2 && zz0 > 0) return true; - if (face == 3 && zz1 < 1) return true; - if (face == 4 && xx0 > 0) return true; - if (face == 5 && xx1 < 1) return true; - Tile* t = Tile::tiles[level->getTile(x, y, z)]; - if (!t) return true; - if (face == 1 && t->id == topSnow->id) return false; - return !t->isSolidRender(); - //return (!level->isSolidRenderTile(x, y, z)); -} - -int Tile::getTexture( LevelSource* level, int x, int y, int z, int face ) -{ - return getTexture(face, level->getData(x, y, z)); -} - -int Tile::getTexture( int face, int data ) -{ - return getTexture(face); -} - -int Tile::getTexture( int face ) -{ - return tex; -} - -void Tile::addAABBs( Level* level, int x, int y, int z, const AABB* box, std::vector& boxes ) -{ - AABB* aabb = getAABB(level, x, y, z); - if (aabb != NULL && box->intersects(*aabb)) { - boxes.push_back(*aabb); - } -} - -AABB* Tile::getAABB( Level* level, int x, int y, int z ) -{ - tmpBB.x0 = x + xx0; - tmpBB.y0 = y + yy0; - tmpBB.z0 = z + zz0; - tmpBB.x1 = x + xx1; - tmpBB.y1 = y + yy1; - tmpBB.z1 = z + zz1; - return &tmpBB; -} - -bool Tile::isSolidRender() -{ - return true; -} - -bool Tile::mayPick( int data, bool liquid ) -{ - return mayPick(); -} - -bool Tile::mayPick() -{ - return true; -} - -int Tile::getTickDelay() -{ - return 10; -} - -int Tile::getResourceCount( Random* random ) -{ - return 1; -} - -int Tile::getResource( int data, Random* random ) -{ - return id; -} - -float Tile::getExplosionResistance( Entity* source ) -{ - return explosionResistance / 5.0f; -} - -int Tile::getRenderLayer() -{ - return Tile::RENDERLAYER_OPAQUE; -} - -bool Tile::use( Level* level, int x, int y, int z, Player* player ) -{ - return false; -} - -bool Tile::spawnBurnResources( Level* level, float x, float y, float z ) -{ - return false; -} - -int Tile::getColor( LevelSource* level, int x, int y, int z ) -{ - return 0xffffff; -} - -bool Tile::getSignal( LevelSource* level, int x, int y, int z ) -{ - return false; -} - -bool Tile::getSignal( LevelSource* level, int x, int y, int z, int dir ) -{ - return false; -} - -bool Tile::isSignalSource() -{ - return false; -} - -bool Tile::getDirectSignal( Level* level, int x, int y, int z, int dir ) -{ - return false; -} - -void Tile::playerDestroy( Level* level, Player* player, int x, int y, int z, int data ) -{ - //player.awardStat(Stats.blockMined[id], 1); - spawnResources(level, x, y, z, data); -} - -bool Tile::canSurvive( Level* level, int x, int y, int z ) -{ - return true; -} - -Tile* Tile::setDescriptionId( const std::string& id ) -{ - descriptionId = TILE_DESCRIPTION_PREFIX + id; - return this; -} - -std::string Tile::getName() const -{ - return I18n::get(getDescriptionId() + ".name"); -} - -std::string Tile::getDescriptionId() const -{ - return descriptionId; -} - -Tile* Tile::setSoundType( const SoundType& soundType ) -{ - this->soundType = &soundType; - return this; -} - -Tile* Tile::setLightBlock( int i ) -{ - lightBlock[id] = i; - return this; -} - -Tile* Tile::setExplodeable( float explosionResistance ) -{ - this->explosionResistance = explosionResistance * 3; - return this; -} - -Tile* Tile::setDestroyTime( float destroySpeed ) -{ - this->destroySpeed = destroySpeed; - if (explosionResistance < destroySpeed * 5) explosionResistance = destroySpeed * 5; - return this; -} - -void Tile::setTicking( bool tick ) -{ - shouldTick[id] = tick; -} - -int Tile::getSpawnResourcesAuxValue( int data ) -{ - return 0; -} - -bool Tile::containsX( const Vec3& v ) -{ - return v.y >= yy0 && v.y <= yy1 && v.z >= zz0 && v.z <= zz1; -} - -bool Tile::containsY( const Vec3& v ) -{ - return v.x >= xx0 && v.x <= xx1 && v.z >= zz0 && v.z <= zz1; -} - -bool Tile::containsZ( const Vec3& v ) -{ - return v.x >= xx0 && v.x <= xx1 && v.y >= yy0 && v.y <= yy1; -} - -/*public*/ -AABB Tile::getTileAABB(Level* level, int x, int y, int z) { - return AABB(x + xx0, y + yy0, z + zz0, x + xx1, y + yy1, z + zz1); -} - -/*public*/ -void Tile::setShape(float x0, float y0, float z0, float x1, float y1, float z1) { - this->xx0 = x0; - this->yy0 = y0; - this->zz0 = z0; - this->xx1 = x1; - this->yy1 = y1; - this->zz1 = z1; -} - -/*public*/ -bool Tile::mayPlace(Level* level, int x, int y, int z, unsigned char face) { - return mayPlace(level, x, y, z); -} - -bool Tile::mayPlace( Level* level, int x, int y, int z ) { - int t = level->getTile(x, y, z); - return t == 0 || Tile::tiles[t]->material->isReplaceable(); -} - -Tile* Tile::setCategory(int category) { - this->category = category; - return this; -} +#include "TileInclude.hpp" +#include "world/level/Level.hpp" +#include "world/entity/player/Player.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/item/Item.hpp" +#include "world/item/TileItem.hpp" + +#include "util/Random.hpp" +//#include "locale/Descriptive.hpp" +//#include "stats/Stats.hpp" +#include "world/entity/Entity.hpp" +#include "world/level/LevelSource.hpp" +#include "world/level/material/Material.hpp" +#include "world/phys/AABB.hpp" +#include "world/phys/HitResult.hpp" +#include "world/phys/Vec3.hpp" +#include "locale/I18n.hpp" +#include "world/item/ClothTileItem.hpp" + +#include "world/item/AuxDataTileItem.hpp" +#include "world/item/LeafTileItem.hpp" +#include "world/item/StoneSlabTileItem.hpp" +#include "world/item/SaplingTileItem.hpp" +#include "world/item/ItemCategory.hpp" + +const int Tile::RENDERLAYER_OPAQUE = 0; +const int Tile::RENDERLAYER_ALPHATEST = 1; +const int Tile::RENDERLAYER_BLEND = 2; + +const std::string Tile::TILE_DESCRIPTION_PREFIX("tile."); + +const Tile::SoundType Tile::SOUND_NORMAL("stone", 1, 1); +const Tile::SoundType Tile::SOUND_WOOD("wood", 1, 1); +const Tile::SoundType Tile::SOUND_GRAVEL("gravel", 1, 1); +const Tile::SoundType Tile::SOUND_GRASS("grass", 0.5f, 1); +const Tile::SoundType Tile::SOUND_STONE("stone", 1, 1); +const Tile::SoundType Tile::SOUND_METAL("stone", 1, 1.5f); +const Tile::SoundType Tile::SOUND_GLASS("stone", "random.glass", 1, 1); +const Tile::SoundType Tile::SOUND_CLOTH("cloth", 1, 1); + +#ifdef PRE_ANDROID23 + const Tile::SoundType Tile::SOUND_SAND("sand", 0.45f, 1); +#else + const Tile::SoundType Tile::SOUND_SAND("sand", "step.gravel", 1, 1); +#endif + +const Tile::SoundType Tile::SOUND_SILENT("", 0, 0); + +Tile* Tile::tiles[] = {NULL}; +int Tile::lightBlock[] = {0}; +int Tile::lightEmission[] = {0}; +bool Tile::solid[] = {false}; +bool Tile::isEntityTile[] = {false}; +bool Tile::translucent[] = {true, false}; // @trans: translucent, @trans "asbMax", some more like "*conditon" +bool Tile::shouldTick[] = {false}; +bool Tile::sendTileData[] = {false}; + +Tile* Tile::sand = NULL; +Tile* Tile::sandStone = NULL; +const int SANDSTONE_TEXTURES[] = { 0 + 16 * 12, 5 + 16 * 14, 6 + 16 * 14 }; +const int SANDSTONE_TEXTURE_COUNT = 3; + +Tile* Tile::stoneBrick = NULL; +Tile* Tile::redBrick = NULL; +Tile* Tile::wood = NULL; +Tile* Tile::sapling = NULL; +Tile* Tile::glass = NULL; +Tile* Tile::web = NULL; +Tile* Tile::thinGlass = NULL; +Tile* Tile::calmWater = NULL; +Tile* Tile::calmLava = NULL; +Tile* Tile::gravel = NULL; +Tile* Tile::rock = NULL; +Tile* Tile::unbreakable = NULL; +Tile* Tile::dirt = NULL; +Tile* Tile::grass = NULL; +Tile* Tile::ice = NULL; +Tile* Tile::clay = NULL; +Tile* Tile::farmland = NULL; +Tile* Tile::stoneSlab = NULL; +Tile* Tile::stoneSlabHalf=NULL; +Tile* Tile::cloth = NULL; +Tile* Tile::flower = NULL; +Tile* Tile::rose = NULL; +Tile* Tile::mushroom1 = NULL; +Tile* Tile::mushroom2 = NULL; +Tile* Tile::topSnow = NULL; +Tile* Tile::treeTrunk = NULL; +Tile* Tile::snow = NULL; +LeafTile* Tile::leaves = NULL; +Tile* Tile::emeraldOre = NULL; +Tile* Tile::redStoneOre = NULL; +Tile* Tile::redStoneOre_lit = NULL; +Tile* Tile::goldOre = NULL; +Tile* Tile::ironOre = NULL; +Tile* Tile::coalOre = NULL; +Tile* Tile::lapisOre = NULL; +Tile* Tile::lapisBlock = NULL; +Tile* Tile::reeds = NULL; +Tile* Tile::ladder = NULL; +Tile* Tile::obsidian = NULL; +Tile* Tile::tnt = NULL; +Tile* Tile::bookshelf = NULL; +Tile* Tile::sign = NULL; +Tile* Tile::wallSign = NULL; +Tile* Tile::mossStone = NULL; +Tile* Tile::torch = NULL; +Tile* Tile::water = NULL; +Tile* Tile::lava = NULL; +FireTile* Tile::fire = NULL; +Tile* Tile::invisible_bedrock = NULL; +Tile* Tile::goldBlock = NULL; +Tile* Tile::ironBlock = NULL; +Tile* Tile::emeraldBlock= NULL; +Tile* Tile::workBench = NULL; +Tile* Tile::stonecutterBench = NULL; +Tile* Tile::crops = NULL; +Tile* Tile::furnace = NULL; +Tile* Tile::furnace_lit = NULL; +Tile* Tile::chest = NULL; +Tile* Tile::lightGem = NULL; +Tile* Tile::stairs_wood = NULL; +Tile* Tile::stairs_stone= NULL; +Tile* Tile::stairs_brick= NULL; +Tile* Tile::door_wood = NULL; +Tile* Tile::door_iron = NULL; +Tile* Tile::cactus = NULL; + +Tile* Tile::melon = NULL; +Tile* Tile::melonStem = NULL; + +Tile* Tile::bed = NULL; +Tile* Tile::tallgrass = NULL; +Tile* Tile::trapdoor = NULL; +Tile* Tile::stoneBrickSmooth = NULL; +const int STONE_BRICK_TEXTURES[] = { 6 + 16 * 3, 4 + 16 * 6, 5 + 16 * 6 }; +const int STONE_BRICK_TEXTURE_COUNT = 3; + +Tile* Tile::fence = NULL; +Tile* Tile::fenceGate = NULL; + +Tile* Tile::info_updateGame1 = NULL; +Tile* Tile::info_updateGame2 = NULL; +Tile* Tile::info_reserved6 = NULL; +Tile* Tile::grass_carried = NULL; +LeafTile* Tile::leaves_carried = NULL; + +Tile* Tile::netherReactor = NULL; +Tile* Tile::glowingObsidian = NULL; + +Tile* Tile::stairs_stoneBrickSmooth = NULL; +Tile* Tile::netherBrick = NULL; +Tile* Tile::netherrack = NULL; +Tile* Tile::stairs_netherBricks = NULL; +Tile* Tile::stairs_sandStone = NULL; +Tile* Tile::quartzBlock = NULL; +Tile* Tile::stairs_quartz = NULL; + +/*static*/ +void Tile::initTiles() { + rock = (new StoneTile(1, 1))->init()->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stone"); + grass = (GrassTile*) (new GrassTile(2))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("grass"); + dirt = (new DirtTile(3, 2))->init()->setDestroyTime(0.5f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("dirt"); + stoneBrick = (new Tile(4, 16, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stonebrick"); + wood = (new Tile(5, 4, Material::wood))->init()->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("wood"); + sapling = (new Sapling(6, 15))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("sapling");//->sendTileData(); + unbreakable = (new Tile(7, 17, Material::stone))->init()->setDestroyTime(-1)->setExplodeable(6000000)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("bedrock"); + water = (new LiquidTileDynamic(8, Material::water))->init()->setDestroyTime(100.0f)->setLightBlock(3)->setCategory(ItemCategory::Structures)->setDescriptionId("water"); + calmWater = (new LiquidTileStatic(9, Material::water))->init()->setDestroyTime(100.0f)->setLightBlock(3)->setCategory(ItemCategory::Structures)->setDescriptionId("water"); + lava = (new LiquidTileDynamic(10, Material::lava))->init()->setDestroyTime(00.0f)->setLightEmission(1.0f)->setLightBlock(255)->setCategory(ItemCategory::Structures)->setDescriptionId("lava"); // 00.0? + calmLava = (new LiquidTileStatic(11, Material::lava))->init()->setDestroyTime(100.0f)->setLightEmission(1.0f)->setLightBlock(255)->setCategory(ItemCategory::Structures)->setDescriptionId("lava"); + sand = (new HeavyTile(12, 18))->init()->setDestroyTime(0.5f)->setSoundType(SOUND_SAND)->setCategory(ItemCategory::Structures)->setDescriptionId("sand"); + gravel = (new GravelTile(13, 19))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("gravel"); + goldOre = (new OreTile(14, 32))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("oreGold"); + ironOre = (new OreTile(15, 33))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("oreIron"); + coalOre = (new OreTile(16, 34))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("oreCoal"); + treeTrunk = (new TreeTile(17))->init()->setDestroyTime(2.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("log"); + leaves = (LeafTile*) (new LeafTile(18, 4 + 3 * 16))->init()->setDestroyTime(0.2f)->setLightBlock(1)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("leaves"); + + glass = (new GlassTile(20, 49, Material::glass, false))->init()->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setCategory(ItemCategory::Structures)->setDescriptionId("glass"); + lapisOre = (new OreTile(21, 10 * 16))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("oreLapis"); + lapisBlock = (new Tile(22, 9 * 16, Material::stone))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockLapis"); + sandStone = (new SandStoneTile(24, (const int*)&SANDSTONE_TEXTURES, SANDSTONE_TEXTURE_COUNT))->init()->setSoundType(SOUND_STONE)->setDestroyTime(0.8f)->setCategory(ItemCategory::Structures)->setDescriptionId("sandStone"); + bed = (new BedTile(26))->init()->setDestroyTime(0.2f)->setCategory(ItemCategory::Structures)->setDescriptionId("bed"); + web = (new WebTile(30, 11))->init()->setLightBlock(1)->setDestroyTime(4.0f)->setCategory(ItemCategory::Decorations)->setDescriptionId("web"); + tallgrass = (new TallGrass(31, 2 * 16 + 7))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("tallgrass"); + cloth = (new ClothTile(35))->init()->setDestroyTime(0.8f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("cloth"); + + flower = (new Bush(37, 13))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("flower"); + rose = (new Bush(38, 12))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("rose"); + mushroom1 = (new Mushroom(39, 13 + 16))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setLightEmission(2 / 16.0f)->setCategory(ItemCategory::Decorations)->setDescriptionId("mushroom"); + mushroom2 = (new Mushroom(40, 12 + 16))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Decorations)->setDescriptionId("mushroom"); + goldBlock = (new MetalTile(41, 39 - 16))->init()->setDestroyTime(3.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockGold"); + ironBlock = (new MetalTile(42, 38 - 16))->init()->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockIron"); + stoneSlab = (new StoneSlabTile(43, true))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stoneSlab"); + stoneSlabHalf=(new StoneSlabTile(44, false))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stoneSlab"); + redBrick = (new Tile(45, 7, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("brick"); + tnt = (new TntTile(46, 8))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Tools)->setDescriptionId("tnt"); + bookshelf = (new BookshelfTile(47, 35))->init()->setDestroyTime(1.5f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Decorations)->setDescriptionId("bookshelf"); + mossStone = (new Tile(48, 36, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stoneMoss"); + obsidian = (new ObsidianTile(49, 37, false))->init()->setDestroyTime(10.0f)->setExplodeable(2000)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("obsidian"); + torch = (new TorchTile(50, 5 * 16))->init()->setDestroyTime(0.0f)->setLightEmission(15 / 16.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Tools)->setDescriptionId("torch"); + + stairs_wood = (new StairTile(53, wood))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsWood"); + chest = (new ChestTile(54))->init()->setCategory(ItemCategory::Structures)->setDestroyTime(2.5f)->setSoundType(SOUND_WOOD)->setDescriptionId("chest");//->sendTileData(); + + emeraldOre = (new OreTile(56, 16 * 3 + 2))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Decorations)->setDescriptionId("oreDiamond"); + emeraldBlock= (new MetalTile(57, 40 - 16))->init()->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Decorations)->setDescriptionId("blockDiamond"); + workBench = (new WorkbenchTile(58))->init()->setDestroyTime(2.5f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("workbench"); + crops = (new CropTile(59, 8 + 5 * 16))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("crops");//->sendTileData(); + farmland = (new FarmTile(60))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("farmland"); + furnace = (new FurnaceTile(61, false))->init()->setDestroyTime(3.5f)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("furnace");//.sendTileData(); + furnace_lit = (new FurnaceTile(62, true))->init()->setDestroyTime(3.5f)->setSoundType(SOUND_STONE)->setLightEmission(14 / 16.0f)->setCategory(ItemCategory::Structures)->setDescriptionId("furnace");//.sendTileData(); + sign = (new SignTile(63, TileEntityType::Sign, true))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Decorations)->setDescriptionId("sign");//->sendTileData(); + door_wood = (new DoorTile(64, Material::wood))->init()->setDestroyTime(3.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("doorWood"); + ladder = (new LadderTile(65, 3 + 5 * 16))->init()->setDestroyTime(0.4f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("ladder"); + + stairs_stone= (new StairTile(67, stoneBrick))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsStone"); + wallSign = (new SignTile(68, TileEntityType::Sign, false))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Decorations)->setDescriptionId("sign");//->sendTileData(); + + door_iron = (new DoorTile(71, Material::metal))->init()->setDestroyTime(5.0f)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Structures)->setDescriptionId("doorIron"); + + redStoneOre = (new RedStoneOreTile(73, 16 * 3 + 3, false))->init()->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("oreRedstone"); + redStoneOre_lit = (new RedStoneOreTile(74, 16 * 3 + 3, true))->init()->setDestroyTime(3.0f)->setLightEmission(10 / 16.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Mechanisms)->setDescriptionId("oreRedstone"); + + topSnow = (new TopSnowTile(78, 16 * 4 + 2))->init()->setDestroyTime(0.1f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("snow"); + ice = (new IceTile(79, 16 * 4 + 3))->init()->setDestroyTime(0.5f)->setLightBlock(3)->setSoundType(SOUND_GLASS)->setCategory(ItemCategory::Structures)->setDescriptionId("ice"); + snow = (new SnowTile(80, 16 * 4 + 2))->init()->setDestroyTime(0.2f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("snow"); + cactus = (new CactusTile(81, 16 * 4 + 6))->init()->setDestroyTime(0.4f)->setSoundType(SOUND_CLOTH)->setCategory(ItemCategory::Structures)->setDescriptionId("cactus"); + clay = (new ClayTile(82, 16 * 4 + 8))->init()->setDestroyTime(0.6f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("clay"); + reeds = (new ReedTile(83, 16 * 4 + 9))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("reeds"); + + fence = (new FenceTile(85, 4))->init()->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("fence"); + + netherrack = (new Tile(87, 7 + 6 * 16, Material::stone))->init()->setDestroyTime(0.4f)->setSoundType(SOUND_STONE)->setDescriptionId("hellrock"); + //hellSand = (new HellSandTile(88, 8 + 6 * 16, Material::sand))->init()->setDestroyTime(0.5f)->setSoundType(SOUND_SAND)->setDescriptionId("hellsand"); + + lightGem = (new LightGemTile(89, 9 + 16 * 6, Material::glass))->init()->setDestroyTime(0.3f)->setCategory(ItemCategory::Structures)->setSoundType(SOUND_GLASS)->setLightEmission(1.0f)->setDescriptionId("lightgem"); + invisible_bedrock = (new InvisibleTile(95, 0, Material::stone))->init()->setDestroyTime(-1)->setExplodeable(6000000);//->setSoundType(SOUND_SILENT); + trapdoor = (new TrapDoorTile(96, Material::wood))->init()->setDestroyTime(3.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("trapdoor");//->sendTileData(); + + stoneBrickSmooth = (new MultiTextureTile(98, (const int*)&STONE_BRICK_TEXTURES, STONE_BRICK_TEXTURE_COUNT, Material::stone))->init()->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stonebricksmooth"); + + thinGlass = (new ThinFenceTile(102, 1 + 3 * 16, 4 + 9 * 16, Material::glass, false))->init()->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setCategory(ItemCategory::Structures)->setDescriptionId("thinGlass"); + melon = (new MelonTile(103))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("melon"); + melonStem = (new StemTile(105, Tile::melon))->init()->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::FoodArmor)->setDescriptionId("pumpkinStem");//->sendTileData(); + fenceGate = (new FenceGateTile(107, 4))->init()->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("fenceGate");//->sendTileData(); + stairs_brick = (new StairTile(108, Tile::redBrick))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsBrick");//->sendTileData(); + + stairs_stoneBrickSmooth = (new StairTile(109, Tile::stoneBrickSmooth))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsStoneBrickSmooth");//->sendTileData(); + netherBrick = (new Tile(112, 0 + 14 * 16, Material::stone))->init()->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("netherBrick"); + stairs_netherBricks = (new StairTile(114, Tile::netherBrick))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsNetherBrick");//->sendTileData(); + stairs_sandStone = (new StairTile(128, Tile::sandStone))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsSandStone");//->sendTileData(); + + quartzBlock = (new QuartzBlockTile(155))->init()->setSoundType(SOUND_STONE)->setDestroyTime(0.8f)->setCategory(ItemCategory::Structures)->setDescriptionId("quartzBlock"); + stairs_quartz = (new StairTile(156, Tile::quartzBlock))->init()->setCategory(ItemCategory::Structures)->setDescriptionId("stairsQuartz");//->sendTileData(); + + // + // Special tiles for Pocket Edition is placed at high IDs + // + stonecutterBench= (new StonecutterTile(245))->init()->setDestroyTime(2.5f)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("stonecutter"); + glowingObsidian = (new ObsidianTile(246, 10 + 16 * 13, true))->init()->setDestroyTime(10.0f)->setLightEmission(14 / 16.0f)->setExplodeable(2000)->setSoundType(SOUND_STONE)->setCategory(ItemCategory::Structures)->setDescriptionId("glowingobsidian"); + netherReactor = (new NetherReactor(247, 10 + 14 * 16, Material::metal))->init()->setDestroyTime(3.0f)->setSoundType(SOUND_METAL)->setCategory(ItemCategory::Structures)->setDescriptionId("netherreactor"); + info_updateGame1= (new Tile(248, 252, Material::dirt))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("info_update"); + info_updateGame2= (new Tile(249, 253, Material::dirt))->init()->setDestroyTime(1.0f)->setSoundType(SOUND_GRAVEL)->setCategory(ItemCategory::Structures)->setDescriptionId("info_update"); + grass_carried = (new CarriedTile(253, 3, 12*16 + 12))->init()->setDescriptionId("grass"); + leaves_carried = (LeafTile*) (new LeafTile(254, 11 + 14 * 16))->init()->setDestroyTime(0.2f)->setLightBlock(1)->setSoundType(SOUND_GRASS)->setCategory(ItemCategory::Structures)->setDescriptionId("leaves"); + info_reserved6 = (new Tile(255, Material::dirt))->init(); + + // + // Stuff that need to be inited in a specific order (i.e. after the other tiles have been created) + // + fire = (FireTile*) (new FireTile(51, 1 * 16 + 15))->init()->setDestroyTime(0.0f)->setLightEmission(1.0f)->setSoundType(SOUND_WOOD)->setCategory(ItemCategory::Structures)->setDescriptionId("fire"); + + // + // Special case for certain items since they can have different icons + // @note: Make sure those different items are handled in ItemInHandRenderer::renderItem + // + Item::items[cloth->id] = (new ClothTileItem(cloth->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("cloth"); + Item::items[treeTrunk->id] = (new AuxDataTileItem(treeTrunk->id - 256, treeTrunk))->setCategory(ItemCategory::Structures)->setDescriptionId("log"); + Item::items[stoneBrickSmooth->id] = (new AuxDataTileItem(stoneBrickSmooth->id - 256, stoneBrickSmooth))->setCategory(ItemCategory::Structures)->setDescriptionId("stonebricksmooth"); + Item::items[stoneSlabHalf->id] = (new StoneSlabTileItem(stoneSlabHalf->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("stoneSlab"); + Item::items[sapling->id] = (new SaplingTileItem(sapling->id - 256))->setCategory(ItemCategory::Structures)->setDescriptionId("sapling"); + Item::items[leaves->id] = (new LeafTileItem(leaves->id - 256))->setCategory(ItemCategory::Decorations)->setDescriptionId("leaves"); + Item::items[sandStone->id] = (new AuxDataTileItem(sandStone->id - 256, sandStone))->setCategory(ItemCategory::Structures)->setDescriptionId("sandStone"); + + Item::items[quartzBlock->id] = (new AuxDataTileItem(quartzBlock->id - 256, quartzBlock))->setCategory(ItemCategory::Structures)->setDescriptionId("quartzBlock"); + + for (int i = 0; i < 256; i++) { + if (Tile::tiles[i] != NULL) { + if (Item::items[i] == NULL) { + Item::items[i] = new TileItem(i - 256); + Item::items[i]->category = Tile::tiles[i]->category; + } + // Check for missing category + if (Item::items[i]->category == -1) + LOGE("Error: Missing category for tile %d: %s\n", tiles[i]->id, tiles[i]->getDescriptionId().c_str()); + } + } +} + +/*static*/ +void Tile::teardownTiles() { + for (int i = 0; i < 256; ++i) + if (Tile::tiles[i]) { + delete Tile::tiles[i]; + Tile::tiles[i] = NULL; + } +} + +int Tile::transformToValidBlockId( int blockId ) { + return transformToValidBlockId(blockId, 0, 0, 0); +} + +int Tile::transformToValidBlockId( int blockId, int x, int y, int z ) { + if (blockId != 0 && Tile::tiles[blockId] == NULL) + return (((x + y + z)&1) == 1)? Tile::info_updateGame1->id : Tile::info_updateGame2->id; + return blockId; +} + + +Tile::Tile(int id, const Material* material) +: id(id), + material(material), + tex(1), + category(-1), + gravity(1.0f), + friction(0.6f), + soundType(&Tile::SOUND_NORMAL), + tmpBB(0,0,0,1,1,1), + xx0(0),yy0(0),zz0(0), + xx1(1),yy1(1),zz1(1) +{ + if (Tile::tiles[id]) { + printf("Slot %d is already occupied by %p when adding %p\n", id, &Tile::tiles[id], this); + } +} + +Tile::Tile( int id, int tex, const Material* material ) +: id(id), + tex(tex), + material(material), + category(-1), + gravity(1.0f), + friction(0.6f), + soundType(&Tile::SOUND_NORMAL), + tmpBB(0,0,0,1,1,1), + xx0(0),yy0(0),zz0(0), + xx1(1),yy1(1),zz1(1) +{ + if (Tile::tiles[id]) { + printf("Slot %d is already occupied by %p when adding %p\n", id, &Tile::tiles[id], this); + } +} + +//Tile* sendTileData() { +// Tile::sendTileData[id] = true; +// return this; +//} + +/*protected*/ +Tile* Tile::setLightEmission(float f) { + Tile::lightEmission[id] = (int) (Level::MAX_BRIGHTNESS * f); + return this; +} + +/*public static*/ +bool Tile::isFaceVisible(Level* level, int x, int y, int z, int f) { + switch (f) { + case Facing::DOWN : y--; break; + case Facing::UP : y++; break; + case Facing::NORTH: z--; break; + case Facing::SOUTH: z++; break; + case Facing::WEST : x--; break; + case Facing::EAST : x++; break; + } + return !level->isSolidRenderTile(x, y, z); +} + +/* private */ +Tile* Tile::init() { + Tile::tiles[id] = this; + setShape(xx0, yy0, zz0, xx1, yy1, zz1); // @attn + solid[id] = isSolidRender(); + lightBlock[id] = isSolidRender() ? 255 : 0; + translucent[id] = !material->blocksLight(); + return this; +} + +/*public virtual*/ +float Tile::getDestroyProgress(Player* player) { + if (destroySpeed < 0) return 0; + if (!player->canDestroy(this)) return 1 / destroySpeed / 100.0f; + return (player->getDestroySpeed(this) / destroySpeed) / 30.0f; +} + +/*public virtual*/ +HitResult Tile::clip(Level* level, int xt, int yt, int zt, const Vec3& A, const Vec3& B) { + updateShape(level, xt, yt, zt); + + //Stopwatch sw; + //sw.start(); + + Vec3 sub((float)xt, (float)yt, (float)zt); + Vec3 a = A - sub;//a.add((float)-xt, (float)-yt, (float)-zt); + Vec3 b = B - sub;//b.add((float)-xt, (float)-yt, (float)-zt); + + Vec3 xh0, xh1, yh0, yh1, zh0, zh1; + + bool bxh0 = a.clipX(b, xx0, xh0); + bool bxh1 = a.clipX(b, xx1, xh1); + + bool byh0 = a.clipY(b, yy0, yh0); + bool byh1 = a.clipY(b, yy1, yh1); + + bool bzh0 = a.clipZ(b, zz0, zh0); + bool bzh1 = a.clipZ(b, zz1, zh1); + + //if (!containsX(xh0)) xh0 = NULL; + if (!bxh0 || !containsX(xh0)) bxh0 = false; + if (!bxh1 || !containsX(xh1)) bxh1 = false; + if (!byh0 || !containsY(yh0)) byh0 = false; + if (!byh1 || !containsY(yh1)) byh1 = false; + if (!bzh0 || !containsZ(zh0)) bzh0 = false; + if (!bzh1 || !containsZ(zh1)) bzh1 = false; + Vec3* closest = NULL; + + //if (xh0 != NULL && (closest == NULL || a.distanceToSqr(xh0) < a.distanceToSqr(closest))) closest = xh0; + if (bxh0 && (closest == NULL || a.distanceToSqr(xh0) < a.distanceToSqr(*closest))) closest = &xh0; + if (bxh1 && (closest == NULL || a.distanceToSqr(xh1) < a.distanceToSqr(*closest))) closest = &xh1; + if (byh0 && (closest == NULL || a.distanceToSqr(yh0) < a.distanceToSqr(*closest))) closest = &yh0; + if (byh1 && (closest == NULL || a.distanceToSqr(yh1) < a.distanceToSqr(*closest))) closest = &yh1; + if (bzh0 && (closest == NULL || a.distanceToSqr(zh0) < a.distanceToSqr(*closest))) closest = &zh0; + if (bzh1 && (closest == NULL || a.distanceToSqr(zh1) < a.distanceToSqr(*closest))) closest = &zh1; + + if (closest == NULL) + return HitResult(); + + int face = -1; + + if (closest == &xh0) face = 4; + if (closest == &xh1) face = 5; + if (closest == &yh0) face = 0; + if (closest == &yh1) face = 1; + if (closest == &zh0) face = 2; + if (closest == &zh1) face = 3; + + //sw.stop(); + //sw.printEvery(5, ">>> "); + + return HitResult(xt, yt, zt, face, closest->add((float)xt, (float)yt, (float)zt)); +} + +/*virtual*/ +void Tile::spawnResources(Level* level, int x, int y, int z, int data, float odds) { + if (level->isClientSide) return; + + int count = getResourceCount(&level->random); + for (int i = 0; i < count; i++) { + if (level->random.nextFloat() > odds) continue; + int type = getResource(data, &level->random); + if (type <= 0) continue; + const float s = 0.7f; + float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; + float yo = level->random.nextFloat() * s + (1 - s) * 0.5f; + float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; + ItemEntity* item = new ItemEntity(level, x + xo, y + yo, z + zo, ItemInstance(type, 1, getSpawnResourcesAuxValue(data))); + item->throwTime = 10; + level->addEntity(item); + } +} + +void Tile::spawnResources( Level* level, int x, int y, int z, int data ) +{ + spawnResources(level, x, y, z, data, 1); +} + +void Tile::popResource(Level* level, int x, int y, int z, const ItemInstance& itemInstance) { + if (level->isClientSide || level->getLevelData()->getGameType() == GameType::Creative) return; + + float s = 0.7f; + float xo = level->random.nextFloat() * s + (1 - s) * 0.5f; + float yo = level->random.nextFloat() * s + (1 - s) * 0.5f; + float zo = level->random.nextFloat() * s + (1 - s) * 0.5f; + + ItemEntity* item = new ItemEntity(level, x + xo, y + yo, z + zo, itemInstance); + item->throwTime = 10; + level->addEntity(item); +} + + +void Tile::destroy( Level* level, int x, int y, int z, int data ) +{ +} + +bool Tile::isCubeShaped() +{ + return true; +} + +int Tile::getRenderShape() +{ + return SHAPE_BLOCK; +} + +float Tile::getBrightness( LevelSource* level, int x, int y, int z ) +{ + return level->getBrightness(x, y, z); +} + +bool Tile::shouldRenderFace( LevelSource* level, int x, int y, int z, int face ) +{ + if (face == 0 && y == -1) return false; + // For fixed size worlds //@todo: external constants rather than magic numbers + if (face == 2 && z == -1) return false; + if (face == 3 && z == 256) return false; + if (face == 4 && x == -1) return false; + if (face == 5 && x == 256) return false; + // Common + if (face == 0 && yy0 > 0) return true; + if (face == 1 && yy1 < 1) return true; + if (face == 2 && zz0 > 0) return true; + if (face == 3 && zz1 < 1) return true; + if (face == 4 && xx0 > 0) return true; + if (face == 5 && xx1 < 1) return true; + Tile* t = Tile::tiles[level->getTile(x, y, z)]; + if (!t) return true; + if (face == 1 && t->id == topSnow->id) return false; + return !t->isSolidRender(); + //return (!level->isSolidRenderTile(x, y, z)); +} + +int Tile::getTexture( LevelSource* level, int x, int y, int z, int face ) +{ + return getTexture(face, level->getData(x, y, z)); +} + +int Tile::getTexture( int face, int data ) +{ + return getTexture(face); +} + +int Tile::getTexture( int face ) +{ + return tex; +} + +void Tile::addAABBs( Level* level, int x, int y, int z, const AABB* box, std::vector& boxes ) +{ + AABB* aabb = getAABB(level, x, y, z); + if (aabb != NULL && box->intersects(*aabb)) { + boxes.push_back(*aabb); + } +} + +AABB* Tile::getAABB( Level* level, int x, int y, int z ) +{ + tmpBB.x0 = x + xx0; + tmpBB.y0 = y + yy0; + tmpBB.z0 = z + zz0; + tmpBB.x1 = x + xx1; + tmpBB.y1 = y + yy1; + tmpBB.z1 = z + zz1; + return &tmpBB; +} + +bool Tile::isSolidRender() +{ + return true; +} + +bool Tile::mayPick( int data, bool liquid ) +{ + return mayPick(); +} + +bool Tile::mayPick() +{ + return true; +} + +int Tile::getTickDelay() +{ + return 10; +} + +int Tile::getResourceCount( Random* random ) +{ + return 1; +} + +int Tile::getResource( int data, Random* random ) +{ + return id; +} + +float Tile::getExplosionResistance( Entity* source ) +{ + return explosionResistance / 5.0f; +} + +int Tile::getRenderLayer() +{ + return Tile::RENDERLAYER_OPAQUE; +} + +bool Tile::use( Level* level, int x, int y, int z, Player* player ) +{ + return false; +} + +bool Tile::spawnBurnResources( Level* level, float x, float y, float z ) +{ + return false; +} + +int Tile::getColor( LevelSource* level, int x, int y, int z ) +{ + return 0xffffff; +} + +bool Tile::getSignal( LevelSource* level, int x, int y, int z ) +{ + return false; +} + +bool Tile::getSignal( LevelSource* level, int x, int y, int z, int dir ) +{ + return false; +} + +bool Tile::isSignalSource() +{ + return false; +} + +bool Tile::getDirectSignal( Level* level, int x, int y, int z, int dir ) +{ + return false; +} + +void Tile::playerDestroy( Level* level, Player* player, int x, int y, int z, int data ) +{ + //player.awardStat(Stats.blockMined[id], 1); + spawnResources(level, x, y, z, data); +} + +bool Tile::canSurvive( Level* level, int x, int y, int z ) +{ + return true; +} + +Tile* Tile::setDescriptionId( const std::string& id ) +{ + descriptionId = TILE_DESCRIPTION_PREFIX + id; + return this; +} + +std::string Tile::getName() const +{ + return I18n::get(getDescriptionId() + ".name"); +} + +std::string Tile::getDescriptionId() const +{ + return descriptionId; +} + +Tile* Tile::setSoundType( const SoundType& soundType ) +{ + this->soundType = &soundType; + return this; +} + +Tile* Tile::setLightBlock( int i ) +{ + lightBlock[id] = i; + return this; +} + +Tile* Tile::setExplodeable( float explosionResistance ) +{ + this->explosionResistance = explosionResistance * 3; + return this; +} + +Tile* Tile::setDestroyTime( float destroySpeed ) +{ + this->destroySpeed = destroySpeed; + if (explosionResistance < destroySpeed * 5) explosionResistance = destroySpeed * 5; + return this; +} + +void Tile::setTicking( bool tick ) +{ + shouldTick[id] = tick; +} + +int Tile::getSpawnResourcesAuxValue( int data ) +{ + return 0; +} + +bool Tile::containsX( const Vec3& v ) +{ + return v.y >= yy0 && v.y <= yy1 && v.z >= zz0 && v.z <= zz1; +} + +bool Tile::containsY( const Vec3& v ) +{ + return v.x >= xx0 && v.x <= xx1 && v.z >= zz0 && v.z <= zz1; +} + +bool Tile::containsZ( const Vec3& v ) +{ + return v.x >= xx0 && v.x <= xx1 && v.y >= yy0 && v.y <= yy1; +} + +/*public*/ +AABB Tile::getTileAABB(Level* level, int x, int y, int z) { + return AABB(x + xx0, y + yy0, z + zz0, x + xx1, y + yy1, z + zz1); +} + +/*public*/ +void Tile::setShape(float x0, float y0, float z0, float x1, float y1, float z1) { + this->xx0 = x0; + this->yy0 = y0; + this->zz0 = z0; + this->xx1 = x1; + this->yy1 = y1; + this->zz1 = z1; +} + +/*public*/ +bool Tile::mayPlace(Level* level, int x, int y, int z, unsigned char face) { + return mayPlace(level, x, y, z); +} + +bool Tile::mayPlace( Level* level, int x, int y, int z ) { + int t = level->getTile(x, y, z); + return t == 0 || Tile::tiles[t]->material->isReplaceable(); +} + +Tile* Tile::setCategory(int category) { + this->category = category; + return this; +} diff --git a/src/world/level/tile/Tile.h b/src/world/level/tile/Tile.hpp similarity index 99% rename from src/world/level/tile/Tile.h rename to src/world/level/tile/Tile.hpp index 7808153..9aad5b1 100755 --- a/src/world/level/tile/Tile.h +++ b/src/world/level/tile/Tile.hpp @@ -3,7 +3,7 @@ //package net.minecraft.world.level.tile; #include -#include "../../phys/AABB.h" +#include "world/phys/AABB.hpp" class Entity; class Mob; diff --git a/src/world/level/tile/TileInclude.h b/src/world/level/tile/TileInclude.h deleted file mode 100755 index 1016a73..0000000 --- a/src/world/level/tile/TileInclude.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include "Tile.h" - -#include "BedTile.h" -#include "BookshelfTile.h" -#include "Bush.h" -#include "CactusTile.h" -#include "CarriedTile.h" -#include "ClayTile.h" -#include "ChestTile.h" -#include "ClothTile.h" -#include "CropTile.h" -#include "DirtTile.h" -#include "DoorTile.h" -#include "FarmTile.h" -#include "FenceTile.h" -#include "FenceGateTile.h" -#include "FireTile.h" -#include "FurnaceTile.h" -#include "GlassTile.h" -#include "GrassTile.h" -#include "GravelTile.h" -#include "HeavyTile.h" -#include "IceTile.h" -#include "InvisibleTile.h" -#include "LadderTile.h" -#include "LeafTile.h" -#include "LightGemTile.h" -#include "LiquidTileDynamic.h" -#include "LiquidTileStatic.h" -#include "MelonTile.h" -#include "MultiTextureTile.h" -#include "Mushroom.h" -#include "ObsidianTile.h" -#include "OreTile.h" -#include "MetalTile.h" -#include "NetherReactor.h" -#include "QuartzBlockTile.h" -#include "RedStoneOreTile.h" -#include "ReedTile.h" -#include "SandStoneTile.h" -#include "Sapling.h" -#include "SignTile.h" -#include "SnowTile.h" -#include "StairTile.h" -#include "StemTile.h" -#include "StonecutterTile.h" -#include "StoneTile.h" -#include "StoneSlabTile.h" -#include "TallGrass.h" -#include "ThinFenceTile.h" -#include "TopSnowTile.h" -#include "TorchTile.h" -#include "TrapDoorTile.h" -#include "TreeTile.h" -#include "TntTile.h" -#include "WebTile.h" -#include "WorkbenchTile.h" - diff --git a/src/world/level/tile/TileInclude.hpp b/src/world/level/tile/TileInclude.hpp new file mode 100755 index 0000000..25f8631 --- /dev/null +++ b/src/world/level/tile/TileInclude.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "Tile.hpp" + +#include "BedTile.hpp" +#include "BookshelfTile.hpp" +#include "Bush.hpp" +#include "CactusTile.hpp" +#include "CarriedTile.hpp" +#include "ClayTile.hpp" +#include "ChestTile.hpp" +#include "ClothTile.hpp" +#include "CropTile.hpp" +#include "DirtTile.hpp" +#include "DoorTile.hpp" +#include "FarmTile.hpp" +#include "FenceTile.hpp" +#include "FenceGateTile.hpp" +#include "FireTile.hpp" +#include "FurnaceTile.hpp" +#include "GlassTile.hpp" +#include "GrassTile.hpp" +#include "GravelTile.hpp" +#include "HeavyTile.hpp" +#include "IceTile.hpp" +#include "InvisibleTile.hpp" +#include "LadderTile.hpp" +#include "LeafTile.hpp" +#include "LightGemTile.hpp" +#include "LiquidTileDynamic.hpp" +#include "LiquidTileStatic.hpp" +#include "MelonTile.hpp" +#include "MultiTextureTile.hpp" +#include "Mushroom.hpp" +#include "ObsidianTile.hpp" +#include "OreTile.hpp" +#include "MetalTile.hpp" +#include "NetherReactor.hpp" +#include "QuartzBlockTile.hpp" +#include "RedStoneOreTile.hpp" +#include "ReedTile.hpp" +#include "SandStoneTile.hpp" +#include "Sapling.hpp" +#include "SignTile.hpp" +#include "SnowTile.hpp" +#include "StairTile.hpp" +#include "StemTile.hpp" +#include "StonecutterTile.hpp" +#include "StoneTile.hpp" +#include "StoneSlabTile.hpp" +#include "TallGrass.hpp" +#include "ThinFenceTile.hpp" +#include "TopSnowTile.hpp" +#include "TorchTile.hpp" +#include "TrapDoorTile.hpp" +#include "TreeTile.hpp" +#include "TntTile.hpp" +#include "WebTile.hpp" +#include "WorkbenchTile.hpp" + diff --git a/src/world/level/tile/TntTile.h b/src/world/level/tile/TntTile.hpp similarity index 91% rename from src/world/level/tile/TntTile.h rename to src/world/level/tile/TntTile.hpp index 8d7a83d..747d1b7 100755 --- a/src/world/level/tile/TntTile.h +++ b/src/world/level/tile/TntTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" +#include "util/Random.hpp" -#include "../../entity/item/PrimedTnt.h" -#include "../Level.h" -#include "../material/Material.h" +#include "world/entity/item/PrimedTnt.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" class TntTile: public Tile { diff --git a/src/world/level/tile/TopSnowTile.h b/src/world/level/tile/TopSnowTile.hpp similarity index 92% rename from src/world/level/tile/TopSnowTile.h rename to src/world/level/tile/TopSnowTile.hpp index 82facd4..c17bfae 100755 --- a/src/world/level/tile/TopSnowTile.h +++ b/src/world/level/tile/TopSnowTile.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level->tile; -#include "Tile.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../entity/item/ItemEntity.h" -#include "../../item/ItemInstance.h" -#include "../../../util/Random.h" +#include "Tile.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/entity/item/ItemEntity.hpp" +#include "world/item/ItemInstance.hpp" +#include "util/Random.hpp" class TopSnowTile: public Tile { diff --git a/src/world/level/tile/TorchTile.h b/src/world/level/tile/TorchTile.hpp similarity index 97% rename from src/world/level/tile/TorchTile.h rename to src/world/level/tile/TorchTile.hpp index 5e21307..84a8e7d 100755 --- a/src/world/level/tile/TorchTile.h +++ b/src/world/level/tile/TorchTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level->tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" +#include "Tile.hpp" class TorchTile: public Tile { diff --git a/src/world/level/tile/TransparentTile.h b/src/world/level/tile/TransparentTile.hpp similarity index 92% rename from src/world/level/tile/TransparentTile.h rename to src/world/level/tile/TransparentTile.hpp index c4c794d..e954143 100755 --- a/src/world/level/tile/TransparentTile.h +++ b/src/world/level/tile/TransparentTile.hpp @@ -2,8 +2,8 @@ //package net.minecraft.world.level.tile; -#include "Tile.h" -#include "../LevelSource.h" +#include "Tile.hpp" +#include "world/level/LevelSource.hpp" class Material; class TransparentTile: public Tile diff --git a/src/world/level/tile/TrapDoorTile.cpp b/src/world/level/tile/TrapDoorTile.cpp index fa834e0..53c2c8f 100755 --- a/src/world/level/tile/TrapDoorTile.cpp +++ b/src/world/level/tile/TrapDoorTile.cpp @@ -1,154 +1,154 @@ -#include "TrapDoorTile.h" -#include "../material/Material.h" -#include "../Level.h" -#include "LevelEvent.h" -TrapDoorTile::TrapDoorTile( int id, const Material* material ) : super(id, material) { - tex = 4 + 5 * 16; - if(material == Material::metal) tex++; - float r = 0.5f; - float h = 1.0f; - super::setShape(0.5f - r, 0, 0.5f - r, 0.5f + r, h, 0.5f + r); -} - -bool TrapDoorTile::blocksLight() { - return false; -} - -bool TrapDoorTile::isSolidRender() { - return false; -} - -bool TrapDoorTile::isCubeShaped() { - return false; -} - -int TrapDoorTile::getRenderShape() { - return Tile::SHAPE_BLOCK; -} - -int TrapDoorTile::getRenderLayer() { - return Tile::RENDERLAYER_ALPHATEST; -} - -AABB TrapDoorTile::getTileAABB( Level* level, int x, int y, int z ) { - updateShape(level, x, y, z); - return super::getTileAABB(level, x, y, z); -} - -AABB* TrapDoorTile::getAABB( Level* level, int x, int y, int z ) { - updateShape(level, x, y, z); - return super::getAABB(level, x, y, z); -} - -void TrapDoorTile::updateShape( LevelSource* level, int x, int y, int z ) { - setShape(level->getData(x, y, z)); -} - -void TrapDoorTile::updateDefaultShape() { - float r = 3 / 16.0f; - super::setShape(0, 0.5f - r / 2, 0, 1, 0.5f + r / 2, 1); -} - -void TrapDoorTile::setShape( int data ) { - float r = 3 / 16.0f; - super::setShape(0, 0, 0, 1, r, 1); - if (isOpen(data)) { - if ((data & 3) == 0) super::setShape(0, 0, 1 - r, 1, 1, 1); - if ((data & 3) == 1) super::setShape(0, 0, 0, 1, 1, r); - if ((data & 3) == 2) super::setShape(1 - r, 0, 0, 1, 1, 1); - if ((data & 3) == 3) super::setShape(0, 0, 0, r, 1, 1); - } -} - -void TrapDoorTile::attack( Level* level, int x, int y, int z, Player* player ) { - use(level, x, y, z, player); -} - -bool TrapDoorTile::use( Level* level, int x, int y, int z, Player* player ) { - if (material == Material::metal) return true; - - int dir = level->getData(x, y, z); - level->setData(x, y, z, dir ^ 4); - - level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); - return true; -} - -void TrapDoorTile::setOpen( Level* level, int x, int y, int z, bool shouldOpen ) { - int dir = level->getData(x, y, z); - - bool wasOpen = (dir & 4) > 0; - if (wasOpen == shouldOpen) return; - - level->setData(x, y, z, dir ^ 4); - - level->levelEvent(NULL, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); -} - -void TrapDoorTile::neighborChanged( Level* level, int x, int y, int z, int type ) { - if (level->isClientSide) return; - - int data = level->getData(x, y, z); - int xt = x; - int zt = z; - if ((data & 3) == 0) zt++; - if ((data & 3) == 1) zt--; - if ((data & 3) == 2) xt++; - if ((data & 3) == 3) xt--; - - if (!attachesTo(level->getTile(xt, y, zt))) { - level->setTile(x, y, z, 0); - popResource(level, x, y, z, ItemInstance(Tile::trapdoor)); - } - - bool signal = level->hasNeighborSignal(x, y, z); - if (signal || ((type > 0 && Tile::tiles[type]->isSignalSource()) || type == 0)) { - setOpen(level, x, y, z, signal); - } -} - -HitResult TrapDoorTile::clip( Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b ) { - updateShape(level, xt, yt, zt); - return super::clip(level, xt, yt, zt, a, b); -} - -int TrapDoorTile::getDir( int dir ) { - if ((dir & 4) == 0) { - return ((dir - 1) & 3); - } else { - return (dir & 3); - } -} - -int TrapDoorTile::getPlacedOnFaceDataValue(Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) { - int dir = 0; - if (face == 2) dir = 0; - if (face == 3) dir = 1; - if (face == 4) dir = 2; - if (face == 5) dir = 3; - return dir; -} - -bool TrapDoorTile::mayPlace( Level* level, int x, int y, int z, unsigned char face) { - if (face == 0) return false; - if (face == 1) return false; - if (face == 2) z++; - if (face == 3) z--; - if (face == 4) x++; - if (face == 5) x--; - - return attachesTo(level->getTile(x, y, z)); -} - -bool TrapDoorTile::isOpen( int data ) { - return (data & 4) != 0; -} - -bool TrapDoorTile::attachesTo( int id ) { - if (id <= 0) { - return false; - } - Tile* tile = Tile::tiles[id]; - bool isStair = tile != NULL && tile->getRenderShape() == Tile::SHAPE_STAIRS; - return tile != NULL && (tile->material->isSolidBlocking() && tile->isCubeShaped()) || tile == Tile::lightGem || tile == Tile::stoneSlabHalf || isStair; -} +#include "TrapDoorTile.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" +#include "LevelEvent.hpp" +TrapDoorTile::TrapDoorTile( int id, const Material* material ) : super(id, material) { + tex = 4 + 5 * 16; + if(material == Material::metal) tex++; + float r = 0.5f; + float h = 1.0f; + super::setShape(0.5f - r, 0, 0.5f - r, 0.5f + r, h, 0.5f + r); +} + +bool TrapDoorTile::blocksLight() { + return false; +} + +bool TrapDoorTile::isSolidRender() { + return false; +} + +bool TrapDoorTile::isCubeShaped() { + return false; +} + +int TrapDoorTile::getRenderShape() { + return Tile::SHAPE_BLOCK; +} + +int TrapDoorTile::getRenderLayer() { + return Tile::RENDERLAYER_ALPHATEST; +} + +AABB TrapDoorTile::getTileAABB( Level* level, int x, int y, int z ) { + updateShape(level, x, y, z); + return super::getTileAABB(level, x, y, z); +} + +AABB* TrapDoorTile::getAABB( Level* level, int x, int y, int z ) { + updateShape(level, x, y, z); + return super::getAABB(level, x, y, z); +} + +void TrapDoorTile::updateShape( LevelSource* level, int x, int y, int z ) { + setShape(level->getData(x, y, z)); +} + +void TrapDoorTile::updateDefaultShape() { + float r = 3 / 16.0f; + super::setShape(0, 0.5f - r / 2, 0, 1, 0.5f + r / 2, 1); +} + +void TrapDoorTile::setShape( int data ) { + float r = 3 / 16.0f; + super::setShape(0, 0, 0, 1, r, 1); + if (isOpen(data)) { + if ((data & 3) == 0) super::setShape(0, 0, 1 - r, 1, 1, 1); + if ((data & 3) == 1) super::setShape(0, 0, 0, 1, 1, r); + if ((data & 3) == 2) super::setShape(1 - r, 0, 0, 1, 1, 1); + if ((data & 3) == 3) super::setShape(0, 0, 0, r, 1, 1); + } +} + +void TrapDoorTile::attack( Level* level, int x, int y, int z, Player* player ) { + use(level, x, y, z, player); +} + +bool TrapDoorTile::use( Level* level, int x, int y, int z, Player* player ) { + if (material == Material::metal) return true; + + int dir = level->getData(x, y, z); + level->setData(x, y, z, dir ^ 4); + + level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); + return true; +} + +void TrapDoorTile::setOpen( Level* level, int x, int y, int z, bool shouldOpen ) { + int dir = level->getData(x, y, z); + + bool wasOpen = (dir & 4) > 0; + if (wasOpen == shouldOpen) return; + + level->setData(x, y, z, dir ^ 4); + + level->levelEvent(NULL, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); +} + +void TrapDoorTile::neighborChanged( Level* level, int x, int y, int z, int type ) { + if (level->isClientSide) return; + + int data = level->getData(x, y, z); + int xt = x; + int zt = z; + if ((data & 3) == 0) zt++; + if ((data & 3) == 1) zt--; + if ((data & 3) == 2) xt++; + if ((data & 3) == 3) xt--; + + if (!attachesTo(level->getTile(xt, y, zt))) { + level->setTile(x, y, z, 0); + popResource(level, x, y, z, ItemInstance(Tile::trapdoor)); + } + + bool signal = level->hasNeighborSignal(x, y, z); + if (signal || ((type > 0 && Tile::tiles[type]->isSignalSource()) || type == 0)) { + setOpen(level, x, y, z, signal); + } +} + +HitResult TrapDoorTile::clip( Level* level, int xt, int yt, int zt, const Vec3& a, const Vec3& b ) { + updateShape(level, xt, yt, zt); + return super::clip(level, xt, yt, zt, a, b); +} + +int TrapDoorTile::getDir( int dir ) { + if ((dir & 4) == 0) { + return ((dir - 1) & 3); + } else { + return (dir & 3); + } +} + +int TrapDoorTile::getPlacedOnFaceDataValue(Level* level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) { + int dir = 0; + if (face == 2) dir = 0; + if (face == 3) dir = 1; + if (face == 4) dir = 2; + if (face == 5) dir = 3; + return dir; +} + +bool TrapDoorTile::mayPlace( Level* level, int x, int y, int z, unsigned char face) { + if (face == 0) return false; + if (face == 1) return false; + if (face == 2) z++; + if (face == 3) z--; + if (face == 4) x++; + if (face == 5) x--; + + return attachesTo(level->getTile(x, y, z)); +} + +bool TrapDoorTile::isOpen( int data ) { + return (data & 4) != 0; +} + +bool TrapDoorTile::attachesTo( int id ) { + if (id <= 0) { + return false; + } + Tile* tile = Tile::tiles[id]; + bool isStair = tile != NULL && tile->getRenderShape() == Tile::SHAPE_STAIRS; + return tile != NULL && (tile->material->isSolidBlocking() && tile->isCubeShaped()) || tile == Tile::lightGem || tile == Tile::stoneSlabHalf || isStair; +} diff --git a/src/world/level/tile/TrapDoorTile.h b/src/world/level/tile/TrapDoorTile.hpp similarity index 98% rename from src/world/level/tile/TrapDoorTile.h rename to src/world/level/tile/TrapDoorTile.hpp index d92d0e2..13c2252 100755 --- a/src/world/level/tile/TrapDoorTile.h +++ b/src/world/level/tile/TrapDoorTile.hpp @@ -1,6 +1,6 @@ #pragma once -#include "Tile.h" +#include "Tile.hpp" class TrapDoorTile : public Tile { typedef Tile super; diff --git a/src/world/level/tile/TreeTile.h b/src/world/level/tile/TreeTile.hpp similarity index 91% rename from src/world/level/tile/TreeTile.h rename to src/world/level/tile/TreeTile.hpp index 9a0a1c4..07571f8 100755 --- a/src/world/level/tile/TreeTile.h +++ b/src/world/level/tile/TreeTile.hpp @@ -2,12 +2,12 @@ //package net.minecraft.world.level.tile; -#include "../../../util/Random.h" -#include "../material/Material.h" -#include "../Level.h" +#include "util/Random.hpp" +#include "world/level/material/Material.hpp" +#include "world/level/Level.hpp" -#include "Tile.h" -#include "LeafTile.h" +#include "Tile.hpp" +#include "LeafTile.hpp" class TreeTile: public Tile { diff --git a/src/world/level/tile/WebTile.h b/src/world/level/tile/WebTile.hpp similarity index 83% rename from src/world/level/tile/WebTile.h rename to src/world/level/tile/WebTile.hpp index 4f188f5..7f88e9c 100755 --- a/src/world/level/tile/WebTile.h +++ b/src/world/level/tile/WebTile.hpp @@ -2,11 +2,11 @@ //package net.minecraft.world.level.tile; -#include "../../entity/Entity.h" -#include "../../item/Item.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../phys/AABB.h" +#include "world/entity/Entity.hpp" +#include "world/item/Item.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/phys/AABB.hpp" class WebTile: public Tile { diff --git a/src/world/level/tile/WorkbenchTile.h b/src/world/level/tile/WorkbenchTile.hpp similarity index 80% rename from src/world/level/tile/WorkbenchTile.h rename to src/world/level/tile/WorkbenchTile.hpp index f4d6f7e..d4c0997 100755 --- a/src/world/level/tile/WorkbenchTile.h +++ b/src/world/level/tile/WorkbenchTile.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level.tile; -#include "Tile.h" -#include "../Level.h" -#include "../material/Material.h" -#include "../../entity/player/Player.h" +#include "Tile.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/entity/player/Player.hpp" class WorkbenchTile: public Tile { diff --git a/src/world/level/tile/entity/ChestTileEntity.cpp b/src/world/level/tile/entity/ChestTileEntity.cpp index faf777b..bf9bdd7 100755 --- a/src/world/level/tile/entity/ChestTileEntity.cpp +++ b/src/world/level/tile/entity/ChestTileEntity.cpp @@ -1,239 +1,239 @@ -#include "ChestTileEntity.h" -#include "../ChestTile.h" -#include "../../Level.h" -#include "../../../entity/player/Player.h" -#include "../../../../nbt/NbtIo.h" - -ChestTileEntity::ChestTileEntity() -: super(TileEntityType::Chest), - FillingContainer(ItemsSize, 0, ContainerType::CONTAINER, false), - tickInterval(0), - openCount(0), - openness(0), oOpenness(0), - hasCheckedNeighbors(false), - n(NULL), s(NULL), w(NULL), e(NULL) -{ - //rendererId = TR_CHEST_RENDERER; -} - -int ChestTileEntity::getContainerSize() const -{ - return ItemsSize; -} - -ItemInstance* ChestTileEntity::getItem( int slot ) -{ - return items[slot]; -} - -/* -ItemInstance ChestTileEntity::removeItem( int slot, int count ) -{ - if (!items[slot].isNull()) { - if (items[slot].count <= count) { - ItemInstance item = items[slot]; - items[slot].setNull(); - this->setChanged(); - return item; - } else { - ItemInstance i = items[slot].remove(count); - if (items[slot].count == 0) items[slot].setNull(); - this->setChanged(); - return i; - } - } - return ItemInstance(); -} - -ItemInstance ChestTileEntity::removeItemNoUpdate( int slot ) -{ - if (!items[slot].isNull()) { - ItemInstance item = items[slot]; - items[slot].setNull(); - return item; - } - return ItemInstance(); -} - -void ChestTileEntity::setItem( int slot, ItemInstance* item ) -{ - items[slot] = item? *item : ItemInstance(); - if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); - this->setChanged(); -} -*/ - -std::string ChestTileEntity::getName() const -{ - return "container.chest"; -} - -bool ChestTileEntity::shouldSave() { - for (int i = 0; i < ItemsSize; ++i) - if (items[i] && !items[i]->isNull()) return true; - return false; -} - -void ChestTileEntity::load( CompoundTag* base ) -{ - super::load(base); - - if (!base->contains("Items"))//, Tag::TAG_List) - return; - - ListTag* inventoryList = base->getList("Items"); - for (int i = 0; i < inventoryList->size(); i++) { - Tag* ttag = inventoryList->get(i); - if (ttag->getId() != Tag::TAG_Compound) - continue; - - CompoundTag* tag = (CompoundTag*) ttag; - int slot = tag->getByte("Slot") & 0xff; - if (slot >= 0 && slot < ItemsSize) { - if (!items[slot]) items[slot] = new ItemInstance(); //@chestodo - items[slot]->load(tag); - } - } -} - -bool ChestTileEntity::save( CompoundTag* base ) -{ - if (!super::save(base)) - return false; - - ListTag* listTag = new ListTag(); - - for (int i = 0; i < ItemsSize; i++) { - if (items[i] && !items[i]->isNull()) { - CompoundTag* tag = new CompoundTag(); - tag->putByte("Slot", (char) i); - items[i]->save(tag); - listTag->add(tag); - } - } - base->put("Items", listTag); - return true; -} - -int ChestTileEntity::getMaxStackSize() const -{ - return Container::LARGE_MAX_STACK_SIZE; -} - -bool ChestTileEntity::stillValid( Player* player ) -{ - if (level->getTileEntity(x, y, z) != this) return false; - if (player->distanceToSqr(x + 0.5f, y + 0.5f, z + 0.5f) > 8 * 8) return false; - return true; -} - -void ChestTileEntity::clearCache() -{ - super::clearCache(); - hasCheckedNeighbors = false; -} - -void ChestTileEntity::checkNeighbors() -{ - if (hasCheckedNeighbors) - return; - - hasCheckedNeighbors = true; - n = NULL; - e = NULL; - w = NULL; - s = NULL; - - // if (getTile() != NULL) { - if (level->getTile(x - 1, y, z) == Tile::chest->id) { - w = (ChestTileEntity*) level->getTileEntity(x - 1, y, z); - } - if (level->getTile(x + 1, y, z) == Tile::chest->id) { - e = (ChestTileEntity*) level->getTileEntity(x + 1, y, z); - } - if (level->getTile(x, y, z - 1) == Tile::chest->id) { - n = (ChestTileEntity*) level->getTileEntity(x, y, z - 1); - } - if (level->getTile(x, y, z + 1) == Tile::chest->id) { - s = (ChestTileEntity*) level->getTileEntity(x, y, z + 1); - } - - if (n != NULL) n->clearCache(); - if (s != NULL) s->clearCache(); - if (e != NULL) e->clearCache(); - if (w != NULL) w->clearCache(); - // } -} - -void ChestTileEntity::tick() -{ - super::tick(); - checkNeighbors(); - - if (++tickInterval >= 4 * SharedConstants::TicksPerSecond) { - level->tileEvent(x, y, z, ChestTile::EVENT_SET_OPEN_COUNT, openCount); - tickInterval = 0; - } - - oOpenness = openness; - - float speed = 0.10f; - if (openCount > 0 && openness == 0) { - if (n == NULL && w == NULL) { - float xc = x + 0.5f; - float zc = z + 0.5f; - if (s != NULL) zc += 0.5f; - if (e != NULL) xc += 0.5f; - - level->playSound(xc, y + 0.5f, zc, "random.chestopen", 0.5f, level->random.nextFloat() * 0.1f + 0.9f); - } - } - if ((openCount == 0 && openness > 0) || (openCount > 0 && openness < 1)) { - float oldOpen = openness; - if (openCount > 0) openness += speed; - else openness -= speed; - if (openness > 1) { - openness = 1; - } - float lim = 0.5f; - if (openness < lim && oldOpen >= lim) { - if (n == NULL && w == NULL) { - float xc = x + 0.5f; - float zc = z + 0.5f; - if (s != NULL) zc += 0.5f; - if (e != NULL) xc += 0.5f; - - level->playSound(xc, y + 0.5f, zc, "random.chestclosed", 0.5f, level->random.nextFloat() * 0.1f + 0.9f); - } - } - if (openness < 0) { - openness = 0; - } - } -} - -void ChestTileEntity::triggerEvent( int b0, int b1 ) -{ - if (b0 == ChestTile::EVENT_SET_OPEN_COUNT) { - openCount = b1; - } -} - -void ChestTileEntity::startOpen() -{ - openCount++; - level->tileEvent(x, y, z, ChestTile::EVENT_SET_OPEN_COUNT, openCount); -} - -void ChestTileEntity::stopOpen() -{ - openCount--; - level->tileEvent(x, y, z, ChestTile::EVENT_SET_OPEN_COUNT, openCount); -} - -void ChestTileEntity::setRemoved() -{ - clearCache(); - checkNeighbors(); - super::setRemoved(); -} +#include "ChestTileEntity.hpp" +#include "world/level/tile/ChestTile.hpp" +#include "world/level/Level.hpp" +#include "world/entity/player/Player.hpp" +#include "nbt/NbtIo.hpp" + +ChestTileEntity::ChestTileEntity() +: super(TileEntityType::Chest), + FillingContainer(ItemsSize, 0, ContainerType::CONTAINER, false), + tickInterval(0), + openCount(0), + openness(0), oOpenness(0), + hasCheckedNeighbors(false), + n(NULL), s(NULL), w(NULL), e(NULL) +{ + //rendererId = TR_CHEST_RENDERER; +} + +int ChestTileEntity::getContainerSize() const +{ + return ItemsSize; +} + +ItemInstance* ChestTileEntity::getItem( int slot ) +{ + return items[slot]; +} + +/* +ItemInstance ChestTileEntity::removeItem( int slot, int count ) +{ + if (!items[slot].isNull()) { + if (items[slot].count <= count) { + ItemInstance item = items[slot]; + items[slot].setNull(); + this->setChanged(); + return item; + } else { + ItemInstance i = items[slot].remove(count); + if (items[slot].count == 0) items[slot].setNull(); + this->setChanged(); + return i; + } + } + return ItemInstance(); +} + +ItemInstance ChestTileEntity::removeItemNoUpdate( int slot ) +{ + if (!items[slot].isNull()) { + ItemInstance item = items[slot]; + items[slot].setNull(); + return item; + } + return ItemInstance(); +} + +void ChestTileEntity::setItem( int slot, ItemInstance* item ) +{ + items[slot] = item? *item : ItemInstance(); + if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); + this->setChanged(); +} +*/ + +std::string ChestTileEntity::getName() const +{ + return "container.chest"; +} + +bool ChestTileEntity::shouldSave() { + for (int i = 0; i < ItemsSize; ++i) + if (items[i] && !items[i]->isNull()) return true; + return false; +} + +void ChestTileEntity::load( CompoundTag* base ) +{ + super::load(base); + + if (!base->contains("Items"))//, Tag::TAG_List) + return; + + ListTag* inventoryList = base->getList("Items"); + for (int i = 0; i < inventoryList->size(); i++) { + Tag* ttag = inventoryList->get(i); + if (ttag->getId() != Tag::TAG_Compound) + continue; + + CompoundTag* tag = (CompoundTag*) ttag; + int slot = tag->getByte("Slot") & 0xff; + if (slot >= 0 && slot < ItemsSize) { + if (!items[slot]) items[slot] = new ItemInstance(); //@chestodo + items[slot]->load(tag); + } + } +} + +bool ChestTileEntity::save( CompoundTag* base ) +{ + if (!super::save(base)) + return false; + + ListTag* listTag = new ListTag(); + + for (int i = 0; i < ItemsSize; i++) { + if (items[i] && !items[i]->isNull()) { + CompoundTag* tag = new CompoundTag(); + tag->putByte("Slot", (char) i); + items[i]->save(tag); + listTag->add(tag); + } + } + base->put("Items", listTag); + return true; +} + +int ChestTileEntity::getMaxStackSize() const +{ + return Container::LARGE_MAX_STACK_SIZE; +} + +bool ChestTileEntity::stillValid( Player* player ) +{ + if (level->getTileEntity(x, y, z) != this) return false; + if (player->distanceToSqr(x + 0.5f, y + 0.5f, z + 0.5f) > 8 * 8) return false; + return true; +} + +void ChestTileEntity::clearCache() +{ + super::clearCache(); + hasCheckedNeighbors = false; +} + +void ChestTileEntity::checkNeighbors() +{ + if (hasCheckedNeighbors) + return; + + hasCheckedNeighbors = true; + n = NULL; + e = NULL; + w = NULL; + s = NULL; + + // if (getTile() != NULL) { + if (level->getTile(x - 1, y, z) == Tile::chest->id) { + w = (ChestTileEntity*) level->getTileEntity(x - 1, y, z); + } + if (level->getTile(x + 1, y, z) == Tile::chest->id) { + e = (ChestTileEntity*) level->getTileEntity(x + 1, y, z); + } + if (level->getTile(x, y, z - 1) == Tile::chest->id) { + n = (ChestTileEntity*) level->getTileEntity(x, y, z - 1); + } + if (level->getTile(x, y, z + 1) == Tile::chest->id) { + s = (ChestTileEntity*) level->getTileEntity(x, y, z + 1); + } + + if (n != NULL) n->clearCache(); + if (s != NULL) s->clearCache(); + if (e != NULL) e->clearCache(); + if (w != NULL) w->clearCache(); + // } +} + +void ChestTileEntity::tick() +{ + super::tick(); + checkNeighbors(); + + if (++tickInterval >= 4 * SharedConstants::TicksPerSecond) { + level->tileEvent(x, y, z, ChestTile::EVENT_SET_OPEN_COUNT, openCount); + tickInterval = 0; + } + + oOpenness = openness; + + float speed = 0.10f; + if (openCount > 0 && openness == 0) { + if (n == NULL && w == NULL) { + float xc = x + 0.5f; + float zc = z + 0.5f; + if (s != NULL) zc += 0.5f; + if (e != NULL) xc += 0.5f; + + level->playSound(xc, y + 0.5f, zc, "random.chestopen", 0.5f, level->random.nextFloat() * 0.1f + 0.9f); + } + } + if ((openCount == 0 && openness > 0) || (openCount > 0 && openness < 1)) { + float oldOpen = openness; + if (openCount > 0) openness += speed; + else openness -= speed; + if (openness > 1) { + openness = 1; + } + float lim = 0.5f; + if (openness < lim && oldOpen >= lim) { + if (n == NULL && w == NULL) { + float xc = x + 0.5f; + float zc = z + 0.5f; + if (s != NULL) zc += 0.5f; + if (e != NULL) xc += 0.5f; + + level->playSound(xc, y + 0.5f, zc, "random.chestclosed", 0.5f, level->random.nextFloat() * 0.1f + 0.9f); + } + } + if (openness < 0) { + openness = 0; + } + } +} + +void ChestTileEntity::triggerEvent( int b0, int b1 ) +{ + if (b0 == ChestTile::EVENT_SET_OPEN_COUNT) { + openCount = b1; + } +} + +void ChestTileEntity::startOpen() +{ + openCount++; + level->tileEvent(x, y, z, ChestTile::EVENT_SET_OPEN_COUNT, openCount); +} + +void ChestTileEntity::stopOpen() +{ + openCount--; + level->tileEvent(x, y, z, ChestTile::EVENT_SET_OPEN_COUNT, openCount); +} + +void ChestTileEntity::setRemoved() +{ + clearCache(); + checkNeighbors(); + super::setRemoved(); +} diff --git a/src/world/level/tile/entity/ChestTileEntity.h b/src/world/level/tile/entity/ChestTileEntity.hpp similarity index 90% rename from src/world/level/tile/entity/ChestTileEntity.h rename to src/world/level/tile/entity/ChestTileEntity.hpp index 6bb0172..b05a605 100755 --- a/src/world/level/tile/entity/ChestTileEntity.h +++ b/src/world/level/tile/entity/ChestTileEntity.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level->tile.entity; -#include "TileEntity.h" -#include "../../../inventory/FillingContainer.h" -#include "../../../item/ItemInstance.h" +#include "TileEntity.hpp" +#include "world/inventory/FillingContainer.hpp" +#include "world/item/ItemInstance.hpp" #include class CompoundTag; diff --git a/src/world/level/tile/entity/FurnaceTileEntity.cpp b/src/world/level/tile/entity/FurnaceTileEntity.cpp index e3e4a38..b5d0beb 100755 --- a/src/world/level/tile/entity/FurnaceTileEntity.cpp +++ b/src/world/level/tile/entity/FurnaceTileEntity.cpp @@ -1,251 +1,251 @@ -#include "FurnaceTileEntity.h" - -#include "../FurnaceTile.h" -#include "../../Level.h" -#include "../../material/Material.h" -#include "../../../Container.h" -#include "../../../entity/player/Player.h" -//#include "../../../item/crafting/FurnaceRecipes.h" -#include "../../../item/ItemInstance.h" -#include "../../../../nbt/ListTag.h" -#include "../../../item/crafting/FurnaceRecipes.h" - -FurnaceTileEntity::FurnaceTileEntity() -: super(TileEntityType::Furnace), - Container(ContainerType::FURNACE), - litTime(0), - litDuration(0), - tickCount(0), - finished(false), - _canBeFinished(false) -{ - //LOGI("CREATING FurnaceTileEntity! %p\n", this); -} - -FurnaceTileEntity::~FurnaceTileEntity() { - //LOGI("DELETING FurnaceTileEntity! %p @ %d, %d, %d\n", this, x, y, z); -} - -ItemInstance* FurnaceTileEntity::getItem(int slot) {// @todo @container @fix - return &items[slot]; -} - -ItemInstance FurnaceTileEntity::removeItem(int slot, int count) { - if (!items[slot].isNull()) { - if (items[slot].count <= count) { - ItemInstance item = items[slot]; - items[slot].setNull(); - return item; - } else { - ItemInstance i = items[slot].remove(count); - if (items[slot].count == 0) items[slot].setNull(); - return i; - } - } - return ItemInstance(); -} - -void FurnaceTileEntity::setItem(int slot, ItemInstance* item) { - items[slot] = *item; - if (item != NULL && item->count > getMaxStackSize()) - items[slot].count = getMaxStackSize(); - //LOGI("Furnace: Setting slot %d : %s\n", slot, item->getDescriptionId().c_str()); -} - -std::string FurnaceTileEntity::getName() const { - return "Furnace"; -} - -bool FurnaceTileEntity::shouldSave() { - if (litTime > 0) return true; - for (int i = 0; i < NumItems; ++i) - if (!items[i].isNull()) return true; - return false; -} - -void FurnaceTileEntity::load(CompoundTag* base) { - super::load(base); - ListTag* inventoryList = base->getList("Items"); - for (int i = 0; i < 3; ++i) - items[i].setNull(); - for (int i = 0; i < inventoryList->size(); i++) { - Tag* tt = inventoryList->get(i); - if (tt->getId() == Tag::TAG_Compound) { - CompoundTag* tag = (CompoundTag*)tt; - int slot = tag->getByte("Slot"); - if (slot >= 0 && slot < NumItems) { - ItemInstance* loaded = ItemInstance::fromTag(tag); - if (loaded) { - items[slot] = *loaded; - delete loaded; - } else - items[slot].setNull(); - } - } else { - LOGE("load @ FurnaceTileEntity failed. item's not a compoundTag!\n"); - } - } - - litTime = base->getShort("BurnTime"); - tickCount = base->getShort("CookTime"); - litDuration = getBurnDuration(items[SLOT_FUEL]); -} - -bool FurnaceTileEntity::save(CompoundTag* base) { - if (!super::save(base)) - return false; - - base->putShort("BurnTime", (short) (litTime)); - base->putShort("CookTime", (short) (tickCount)); - ListTag* listTag = new ListTag(); - - for (int i = 0; i < NumItems; i++) { - if (!items[i].isNull()) { - CompoundTag* tag = new CompoundTag(); - tag->putByte("Slot", (char) i); - items[i].save(tag); - listTag->add(tag); - } - } - base->put("Items", listTag); - return true; -} - -int FurnaceTileEntity::getMaxStackSize() const { - return Container::LARGE_MAX_STACK_SIZE; -} - -int FurnaceTileEntity::getContainerSize() const { - return NumItems; -} - -int FurnaceTileEntity::getBurnProgress(int max) { - return tickCount * max / BURN_INTERVAL; -} - -int FurnaceTileEntity::getLitProgress(int max) { - if (litDuration == 0) litDuration = BURN_INTERVAL; - return litTime * max / litDuration; -} - -bool FurnaceTileEntity::isLit() { - return litTime > 0; -} - -void FurnaceTileEntity::tick() -{ - //LOGI("lit|time, tick, dur: %d, %d, %d\n", litTime, tickCount, litDuration); - - bool wasLit = litTime > 0; - bool changed = false; - if (litTime > 0) { - --litTime; - } - - //LOGI("Ticking FurnaceTileEntity: %d\n", litTime); - - if (!level->isClientSide) { - if (litTime == 0 && canBurn()) { - litDuration = litTime = getBurnDuration(items[SLOT_FUEL]); - if (litTime > 0) { - changed = true; - if (!items[SLOT_FUEL].isNull()) { - if (--items[SLOT_FUEL].count == 0) items[SLOT_FUEL].setNull(); - } - } - } - - if (isLit() && canBurn()) { - if (++tickCount == BURN_INTERVAL) { - tickCount = 0; - burn(); - changed = true; - } - } else { - tickCount = 0; - } - - if (wasLit != (litTime > 0)) { - changed = true; - FurnaceTile::setLit(litTime > 0, level, x, y, z); - } - } - - if (changed) setChanged(); - else { - if (!wasLit) { - finished = true; - } - } -} - -bool FurnaceTileEntity::isFinished() -{ - return _canBeFinished && finished; -} - - -void FurnaceTileEntity::burn() { - if (!canBurn()) return; - - ItemInstance result = FurnaceRecipes::getInstance()->getResult(items[0].getItem()->id); - if (items[2].isNull()) items[2] = result; - else if (items[2].id == result.id) items[2].count++; - - if (--items[0].count <= 0) items[0].setNull(); -} - -bool FurnaceTileEntity::stillValid(Player* player) { - if (level->getTileEntity(x, y, z) != this) return false; - if (player->distanceToSqr(x + 0.5f, y + 0.5f, z + 0.5f) > 8 * 8) return false; - return true; -} - -void FurnaceTileEntity::startOpen() { - //_canBeFinished = false; - // TODO Auto-generated method stub -} - -void FurnaceTileEntity::stopOpen() { - //_canBeFinished = true; - // TODO Auto-generated method stub -} - -bool FurnaceTileEntity::canBurn() { - if (items[SLOT_INGREDIENT].isNull()) return false; - ItemInstance burnResult = FurnaceRecipes::getInstance()->getResult(items[SLOT_INGREDIENT].getItem()->id); - if (burnResult.isNull()) return false; - if (items[SLOT_RESULT].isNull()) return true; - if (!items[SLOT_RESULT].sameItem(&burnResult)) return false; - if (items[SLOT_RESULT].count < getMaxStackSize() && items[SLOT_RESULT].count < items[SLOT_RESULT].getMaxStackSize()) return true; - if (items[SLOT_RESULT].count < burnResult.getMaxStackSize()) return true; - return false; -} - -/*static*/ -int FurnaceTileEntity::getBurnDuration(const ItemInstance& itemInstance) { - //if (itemInstance == NULL) return 0; - if (itemInstance.isNull()) return 0; - int id = itemInstance.getItem()->id; - - if (id < 256 && Tile::tiles[id]->material == Material::wood) - return BURN_INTERVAL * 3 / 2; - - if (id == Item::stick->id) return BURN_INTERVAL / 2; - if (id == Item::coal->id) return BURN_INTERVAL * 8; - //case Item::bucket_lava->id: return BURN_INTERVAL * 100; - //case Tile::sapling->id: return BURN_INTERVAL / 2; - //case Item::blazeRod->id: return BURN_INTERVAL * 12; - - return 0; -} - -bool FurnaceTileEntity::isFuel( const ItemInstance& itemInstance ) -{ - return getBurnDuration(itemInstance) > 0; -} - -bool FurnaceTileEntity::isSlotEmpty( int slot ) -{ - return items[slot].isNull(); -} +#include "FurnaceTileEntity.hpp" + +#include "world/level/tile/FurnaceTile.hpp" +#include "world/level/Level.hpp" +#include "world/level/material/Material.hpp" +#include "world/Container.hpp" +#include "world/entity/player/Player.hpp" +//#include "world/item/crafting/FurnaceRecipes.hpp" +#include "world/item/ItemInstance.hpp" +#include "nbt/ListTag.hpp" +#include "world/item/crafting/FurnaceRecipes.hpp" + +FurnaceTileEntity::FurnaceTileEntity() +: super(TileEntityType::Furnace), + Container(ContainerType::FURNACE), + litTime(0), + litDuration(0), + tickCount(0), + finished(false), + _canBeFinished(false) +{ + //LOGI("CREATING FurnaceTileEntity! %p\n", this); +} + +FurnaceTileEntity::~FurnaceTileEntity() { + //LOGI("DELETING FurnaceTileEntity! %p @ %d, %d, %d\n", this, x, y, z); +} + +ItemInstance* FurnaceTileEntity::getItem(int slot) {// @todo @container @fix + return &items[slot]; +} + +ItemInstance FurnaceTileEntity::removeItem(int slot, int count) { + if (!items[slot].isNull()) { + if (items[slot].count <= count) { + ItemInstance item = items[slot]; + items[slot].setNull(); + return item; + } else { + ItemInstance i = items[slot].remove(count); + if (items[slot].count == 0) items[slot].setNull(); + return i; + } + } + return ItemInstance(); +} + +void FurnaceTileEntity::setItem(int slot, ItemInstance* item) { + items[slot] = *item; + if (item != NULL && item->count > getMaxStackSize()) + items[slot].count = getMaxStackSize(); + //LOGI("Furnace: Setting slot %d : %s\n", slot, item->getDescriptionId().c_str()); +} + +std::string FurnaceTileEntity::getName() const { + return "Furnace"; +} + +bool FurnaceTileEntity::shouldSave() { + if (litTime > 0) return true; + for (int i = 0; i < NumItems; ++i) + if (!items[i].isNull()) return true; + return false; +} + +void FurnaceTileEntity::load(CompoundTag* base) { + super::load(base); + ListTag* inventoryList = base->getList("Items"); + for (int i = 0; i < 3; ++i) + items[i].setNull(); + for (int i = 0; i < inventoryList->size(); i++) { + Tag* tt = inventoryList->get(i); + if (tt->getId() == Tag::TAG_Compound) { + CompoundTag* tag = (CompoundTag*)tt; + int slot = tag->getByte("Slot"); + if (slot >= 0 && slot < NumItems) { + ItemInstance* loaded = ItemInstance::fromTag(tag); + if (loaded) { + items[slot] = *loaded; + delete loaded; + } else + items[slot].setNull(); + } + } else { + LOGE("load @ FurnaceTileEntity failed. item's not a compoundTag!\n"); + } + } + + litTime = base->getShort("BurnTime"); + tickCount = base->getShort("CookTime"); + litDuration = getBurnDuration(items[SLOT_FUEL]); +} + +bool FurnaceTileEntity::save(CompoundTag* base) { + if (!super::save(base)) + return false; + + base->putShort("BurnTime", (short) (litTime)); + base->putShort("CookTime", (short) (tickCount)); + ListTag* listTag = new ListTag(); + + for (int i = 0; i < NumItems; i++) { + if (!items[i].isNull()) { + CompoundTag* tag = new CompoundTag(); + tag->putByte("Slot", (char) i); + items[i].save(tag); + listTag->add(tag); + } + } + base->put("Items", listTag); + return true; +} + +int FurnaceTileEntity::getMaxStackSize() const { + return Container::LARGE_MAX_STACK_SIZE; +} + +int FurnaceTileEntity::getContainerSize() const { + return NumItems; +} + +int FurnaceTileEntity::getBurnProgress(int max) { + return tickCount * max / BURN_INTERVAL; +} + +int FurnaceTileEntity::getLitProgress(int max) { + if (litDuration == 0) litDuration = BURN_INTERVAL; + return litTime * max / litDuration; +} + +bool FurnaceTileEntity::isLit() { + return litTime > 0; +} + +void FurnaceTileEntity::tick() +{ + //LOGI("lit|time, tick, dur: %d, %d, %d\n", litTime, tickCount, litDuration); + + bool wasLit = litTime > 0; + bool changed = false; + if (litTime > 0) { + --litTime; + } + + //LOGI("Ticking FurnaceTileEntity: %d\n", litTime); + + if (!level->isClientSide) { + if (litTime == 0 && canBurn()) { + litDuration = litTime = getBurnDuration(items[SLOT_FUEL]); + if (litTime > 0) { + changed = true; + if (!items[SLOT_FUEL].isNull()) { + if (--items[SLOT_FUEL].count == 0) items[SLOT_FUEL].setNull(); + } + } + } + + if (isLit() && canBurn()) { + if (++tickCount == BURN_INTERVAL) { + tickCount = 0; + burn(); + changed = true; + } + } else { + tickCount = 0; + } + + if (wasLit != (litTime > 0)) { + changed = true; + FurnaceTile::setLit(litTime > 0, level, x, y, z); + } + } + + if (changed) setChanged(); + else { + if (!wasLit) { + finished = true; + } + } +} + +bool FurnaceTileEntity::isFinished() +{ + return _canBeFinished && finished; +} + + +void FurnaceTileEntity::burn() { + if (!canBurn()) return; + + ItemInstance result = FurnaceRecipes::getInstance()->getResult(items[0].getItem()->id); + if (items[2].isNull()) items[2] = result; + else if (items[2].id == result.id) items[2].count++; + + if (--items[0].count <= 0) items[0].setNull(); +} + +bool FurnaceTileEntity::stillValid(Player* player) { + if (level->getTileEntity(x, y, z) != this) return false; + if (player->distanceToSqr(x + 0.5f, y + 0.5f, z + 0.5f) > 8 * 8) return false; + return true; +} + +void FurnaceTileEntity::startOpen() { + //_canBeFinished = false; + // TODO Auto-generated method stub +} + +void FurnaceTileEntity::stopOpen() { + //_canBeFinished = true; + // TODO Auto-generated method stub +} + +bool FurnaceTileEntity::canBurn() { + if (items[SLOT_INGREDIENT].isNull()) return false; + ItemInstance burnResult = FurnaceRecipes::getInstance()->getResult(items[SLOT_INGREDIENT].getItem()->id); + if (burnResult.isNull()) return false; + if (items[SLOT_RESULT].isNull()) return true; + if (!items[SLOT_RESULT].sameItem(&burnResult)) return false; + if (items[SLOT_RESULT].count < getMaxStackSize() && items[SLOT_RESULT].count < items[SLOT_RESULT].getMaxStackSize()) return true; + if (items[SLOT_RESULT].count < burnResult.getMaxStackSize()) return true; + return false; +} + +/*static*/ +int FurnaceTileEntity::getBurnDuration(const ItemInstance& itemInstance) { + //if (itemInstance == NULL) return 0; + if (itemInstance.isNull()) return 0; + int id = itemInstance.getItem()->id; + + if (id < 256 && Tile::tiles[id]->material == Material::wood) + return BURN_INTERVAL * 3 / 2; + + if (id == Item::stick->id) return BURN_INTERVAL / 2; + if (id == Item::coal->id) return BURN_INTERVAL * 8; + //case Item::bucket_lava->id: return BURN_INTERVAL * 100; + //case Tile::sapling->id: return BURN_INTERVAL / 2; + //case Item::blazeRod->id: return BURN_INTERVAL * 12; + + return 0; +} + +bool FurnaceTileEntity::isFuel( const ItemInstance& itemInstance ) +{ + return getBurnDuration(itemInstance) > 0; +} + +bool FurnaceTileEntity::isSlotEmpty( int slot ) +{ + return items[slot].isNull(); +} diff --git a/src/world/level/tile/entity/FurnaceTileEntity.h b/src/world/level/tile/entity/FurnaceTileEntity.hpp similarity index 93% rename from src/world/level/tile/entity/FurnaceTileEntity.h rename to src/world/level/tile/entity/FurnaceTileEntity.hpp index e97f89c..5b8dc93 100755 --- a/src/world/level/tile/entity/FurnaceTileEntity.h +++ b/src/world/level/tile/entity/FurnaceTileEntity.hpp @@ -2,9 +2,9 @@ //package net.minecraft.world.level->tile.entity; -#include "TileEntity.h" -#include "../../../Container.h" -#include "../../../item/ItemInstance.h" +#include "TileEntity.hpp" +#include "world/Container.hpp" +#include "world/item/ItemInstance.hpp" class CompoundTag; class Player; diff --git a/src/world/level/tile/entity/NetherReactorTileEntity.cpp b/src/world/level/tile/entity/NetherReactorTileEntity.cpp index f55c12d..29bed9f 100755 --- a/src/world/level/tile/entity/NetherReactorTileEntity.cpp +++ b/src/world/level/tile/entity/NetherReactorTileEntity.cpp @@ -1,402 +1,402 @@ -#include "NetherReactorTileEntity.h" -#include "../../../../nbt/CompoundTag.h" -#include "../../../../SharedConstants.h" -#include "../../../phys/Vec3.h" -#include "../../../level/Level.h" -#include "../../../level/MobSpawner.h" -#include "../../../entity/MobFactory.h" -#include "../NetherReactor.h" -#include "../../../entity/Entity.h" -#include "../../../Difficulty.h" -#include "../../../phys/AABB.h" -#include "../NetherReactorPattern.h" -NetherReactorTileEntity::NetherReactorTileEntity() - : super(TileEntityType::NetherReactor) - , isInitialized(false) - , progress(0) - , curLevel(0) - , hasFinished(false) -{ } - -bool NetherReactorTileEntity::shouldSave() { - return true; -} - -void NetherReactorTileEntity::lightItUp( int x, int y, int z ) { - //if(!isInitilized && !hasFinished) { - curLevel = 0; - NetherReactor::setPhase(level, x, y, z, 1); - isInitialized = true; - //clearDomeSpace(x, y, z); - buildDome(x, y, z); - - level->setNightMode(true); - //} -} - -void NetherReactorTileEntity::tick() { - if(level->isClientSide) - return; - if(progress < 0) { - remove = true; - } - if(isInitialized && !hasFinished) { - progress++; - if(progress % SharedConstants::TicksPerSecond == 0) { - int currentTime = progress / SharedConstants::TicksPerSecond; - if(currentTime < 10) { - tickGlowingRedstoneTransformation(currentTime); - } - if(currentTime > 42 && currentTime <= 45) { - // start with the top layer and move down - int currentLayer = 45 - currentTime; - turnGlowingObsidianLayerToObsidian(currentLayer); - } - if(checkLevelChange(progress / SharedConstants::TicksPerSecond)) { - curLevel++; - spawnItems(getNumItemsPerLevel(curLevel)); - trySpawnPigZombies(NUM_PIG_ZOMBIE_SLOTS, getNumEnemiesPerLevel(curLevel)); - } - } - if(progress > SharedConstants::TicksPerSecond * 46) { - finishReactorRun(); - } - } else if(hasFinished) { - if(progress % SharedConstants::TicksPerSecond * 60 == 0) { - if(playersAreCloseBy()) { - trySpawnPigZombies(2, 3); - } else { - killPigZombies(); - } - } - } -} - -void NetherReactorTileEntity::load( CompoundTag* tag ) { - super::load(tag); - isInitialized = tag->getBoolean("IsInitialized"); - if(isInitialized) { - progress = tag->getShort("Progress"); - hasFinished = tag->getBoolean("HasFinished"); - } -} - -bool NetherReactorTileEntity::save( CompoundTag* tag ) { - super::save(tag); - tag->putBoolean("IsInitialized", isInitialized); - tag->putShort("Progress", progress); - tag->putBoolean("HasFinished", hasFinished); - if(isInitialized && !hasFinished) - level->setNightMode(true); - return true; -} - -std::string NetherReactorTileEntity::getName() const { - return "NetherReactor"; -} - -int NetherReactorTileEntity::getNumEnemiesPerLevel( int curLevel ) { - if(curLevel == 0) - return 3; - else if(curLevel < 4) - return 2; - else if(curLevel < 6) - return Mth::Max(0, level->random.nextInt(2)); - else - return Mth::Max(0, level->random.nextInt(1)); -} - -int NetherReactorTileEntity::getNumItemsPerLevel( int curLevel ) { - if(curLevel == 0) - return 3 * 3; - else if(curLevel < 4) - return 5 * 3; - else if(curLevel < 8) - return Mth::Max(0, level->random.nextInt(14 * 3) - 4); - else - return Mth::Max(0, level->random.nextInt(9 * 3) - 2); -} - -void NetherReactorTileEntity::spawnItems( int numItems ) { - for (int ii = 0; ii < numItems ; ii++) { - spawnItem(); - } -} -Vec3 NetherReactorTileEntity::getSpawnPosition( float minDistance, float varibleDistance, float offset ) { - float distance = minDistance + level->random.nextFloat() * varibleDistance; - float rad = level->random.nextFloat() * Mth::TWO_PI; - return Vec3(sin(rad) * distance + x, offset + y, cos(rad) * distance + z); -} -void NetherReactorTileEntity::spawnEnemy() { - Mob* mob = MobFactory::CreateMob(MobTypes::PigZombie, level); - Vec3 enemyPosition = getSpawnPosition(3, 4, -1); - while(enemyPosition.x < 0 || enemyPosition.z < 0 || enemyPosition.x >= LEVEL_WIDTH || enemyPosition.z >= LEVEL_DEPTH) { - enemyPosition = getSpawnPosition(3, 4, -1); - } - MobSpawner::addMob(level, mob, enemyPosition.x, enemyPosition.y, enemyPosition.z, 0, 0, true); -} - - - -void NetherReactorTileEntity::spawnItem() { - Vec3 itemPosition= getSpawnPosition(3, 4, -1); - while(itemPosition.x < 0 || itemPosition.z < 0 || itemPosition.x >= LEVEL_WIDTH || itemPosition.z >= LEVEL_DEPTH) { - itemPosition = getSpawnPosition(3, 4, -1); - } - ItemEntity* item = new ItemEntity(level, itemPosition.x, itemPosition.y, itemPosition.z, getSpawnItem()); - - item->throwTime = 10; - item->age = item->getLifeTime() - SharedConstants::TicksPerSecond * 30; - level->addEntity(item); -} - -ItemInstance NetherReactorTileEntity::getSpawnItem() { - int itemType = level->random.nextInt(8); - switch(itemType) { - case 0: return ItemInstance(Item::yellowDust, 3); - case 1: return ItemInstance(Item::seeds_melon); - case 2: return ItemInstance(Tile::mushroom1); - case 3: return ItemInstance(Tile::mushroom2); - case 4: return ItemInstance(Item::reeds); - case 5: return ItemInstance(Tile::cactus); - case 6: return ItemInstance(Item::netherQuartz, 4); - default: return GetLowOddsSpawnItem(); - } -} - -ItemInstance NetherReactorTileEntity::GetLowOddsSpawnItem() { - if(level->random.nextInt(10) <= 9 ) { - static Item* items[] = { - Item::arrow, - Item::bed, - Item::bone, - Item::book, - Item::bow, - Item::bowl, - Item::feather, - Item::painting, - Item::door_wood - }; - int itemIndex = level->random.nextInt(sizeof(items) / sizeof(Item*)); - Item* itemToSpawn = items[itemIndex]; - return ItemInstance(itemToSpawn); - } else { - static Tile* tiles[] = { - Tile::bookshelf - }; - int tileIndex = level->random.nextInt(sizeof(tiles) / sizeof(Tile*)); - Tile* tileToSpawn = tiles[tileIndex]; - return ItemInstance(tileToSpawn); - } -} - -bool NetherReactorTileEntity::checkLevelChange( int progress ) { - static const int levelChangeTime[] = {10, 13, 20, 22, 25, 30, 34, 36, 38, 40}; - const int count = sizeof(levelChangeTime) / 4; - for(int a = 0; a < count; ++a) { - if(levelChangeTime[a] == progress) - return true; - } - return false; -} - -void NetherReactorTileEntity::clearDomeSpace( int x, int y, int z ) { - for(int curX = -12; curX <= 12; ++curX) { - for(int curY = -3; curY < 40; ++curY) { - for(int curZ = -12; curZ <= 12; ++curZ) { - if(curY > 2 || curX < -1 || curX > 1 || curZ < -1 || curZ > 1) - level->setTile(curX + x, curY + y, curZ + z, 0); - } - } - } -} - -void NetherReactorTileEntity::finishReactorRun() { - NetherReactor::setPhase(level, x, y, z, 2); - level->setNightMode(false); - hasFinished = true; - deterioateDome(x, y, z); - for(int curX = x - 1; curX <= x + 1; ++curX) { - for(int curY = y - 1; curY <= y + 1; ++curY) { - for(int curZ = z - 1; curZ <= z + 1; ++curZ) { - if(curX != x || curY != y || curZ != z) - level->setTile(curX, curY, curZ, Tile::obsidian->id); - } - } - } -} - -int NetherReactorTileEntity::numOfFreeEnemySlots() { - int numPigZombiesFound = 0; - AABB bb((float)x, (float)y, (float)z, x + 1.0f, y + 1.0f, z + 1.0f); - EntityList nearby = level->getEntities(NULL, bb.grow(7, 7, 7)); - for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { - if((*it)->isEntityType(MobTypes::PigZombie) && (*it)->isAlive()) { - numPigZombiesFound++; - } - } - return NUM_PIG_ZOMBIE_SLOTS - numPigZombiesFound; -} - -void NetherReactorTileEntity::trySpawnPigZombies( int maxNumOfEnemies, int maxToSpawn ) { - if(level->difficulty == Difficulty::PEACEFUL) - return; - int currentNumOfPigZombies = NUM_PIG_ZOMBIE_SLOTS - numOfFreeEnemySlots(); - if(currentNumOfPigZombies < maxNumOfEnemies) { - for(int a = 0; a < maxToSpawn && currentNumOfPigZombies < maxNumOfEnemies; ++a) { - spawnEnemy(); - currentNumOfPigZombies++; - } - } -} - -void NetherReactorTileEntity::tickGlowingRedstoneTransformation( int currentTime ) { - switch(currentTime) { - case 2: return turnLayerToGlowingObsidian(0, Tile::stoneBrick->id); - case 3: return turnLayerToGlowingObsidian(1, Tile::stoneBrick->id); - case 4: return turnLayerToGlowingObsidian(2, Tile::stoneBrick->id); - case 7: return turnLayerToGlowingObsidian(0, Tile::goldBlock->id); - case 8: return turnLayerToGlowingObsidian(1, Tile::goldBlock->id); - case 9: return turnLayerToGlowingObsidian(2, Tile::goldBlock->id); - } -} - -void NetherReactorTileEntity::turnLayerToGlowingObsidian( int layer, const int type ) { - NetherReactorPattern pattern; - for(int checkX = -1; checkX <= 1; ++checkX) { - for(int checkZ = -1; checkZ <= 1; ++checkZ) { - if(pattern.getTileAt(layer, checkX + 1, checkZ + 1) == type) { - level->setTile(x + checkX, y - 1 + layer, z + checkZ, Tile::glowingObsidian->id); - } - } - } -} - -void NetherReactorTileEntity::turnGlowingObsidianLayerToObsidian( int layer ) { - NetherReactorPattern pattern; - for(int checkX = -1; checkX <= 1; ++checkX) { - for(int checkZ = -1; checkZ <= 1; ++checkZ) { - if(level->getTile(x + checkX, y - 1 + layer, z + checkZ) != Tile::netherReactor->id) { - level->setTile(x + checkX, y - 1 + layer, z + checkZ, Tile::obsidian->id); - } - } - } -} - -void NetherReactorTileEntity::buildDome( int x, int y, int z ) { - buildFloorVolume(x, y - 3, z, 8, 2, Tile::netherrack->id); - buildHollowedVolume(x, y - 1, z, 8, 4, Tile::netherrack->id, 0); - buildFloorVolume(x, y - 1 + 4, z, 8, 1, Tile::netherrack->id); - buildCrockedRoofVolume(false, x, y - 1 + 5, z, 8, 1, Tile::netherrack->id); - buildCrockedRoofVolume(true, x, y - 1 + 6, z, 5, 8, Tile::netherrack->id); - buildCrockedRoofVolume(false, x, y + -1 + 12, z, 3, 14, Tile::netherrack->id); -} - -void NetherReactorTileEntity::buildHollowedVolume( int x, int y, int z, int expandWidth, int height, const int wallTileId, const int clearTileId ) { - for(int curY = 0; curY < height; ++curY) { - for(int curX = -expandWidth; curX <= expandWidth; ++curX) { - for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { - if((curX == -expandWidth || curX == expandWidth) - || (curZ == -expandWidth || curZ == expandWidth)) { - level->setTile(curX + x, curY + y, curZ + z, wallTileId); - } else if(curY > 2 || curX < -1 || curX > 1 || curZ < -1 || curZ > 1) { - level->setTile(curX + x, curY + y, curZ + z, clearTileId); - } - } - } - } -} - -void NetherReactorTileEntity::buildFloorVolume( int x, int y, int z, int expandWidth, int height, const int tileId ) { - for(int curY = 0; curY < height; ++curY) { - for(int curX = -expandWidth; curX <= expandWidth; ++curX) { - for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { - level->setTile(curX + x, curY + y, curZ + z, tileId); - } - } - } -} - -void NetherReactorTileEntity::buildCrockedRoofVolume( bool inverted, int x, int y, int z, int expandWidth, int height, const int tileId ) { - int fullHeight = height + expandWidth; - for(int curX = -expandWidth; curX <= expandWidth; ++curX) { - for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { - int offset = inverted ? ((-curX - curZ) / 2) : ((curX + curZ) / 2); - int acceptHeight = fullHeight + offset; - for(int curY = 0; curY < fullHeight + expandWidth; ++curY) { - if(acceptHeight >= curY - && (isEdge(curX, expandWidth, curZ) - || acceptHeight == curY )) { - level->setTile(curX + x, curY + y, curZ + z, tileId); - } - } - } - } -} - -bool NetherReactorTileEntity::isEdge( int curX, int expandWidth, int curZ ) { - return (curX == -expandWidth || curX == expandWidth) - || (curZ == -expandWidth || curZ == expandWidth); -} - -void NetherReactorTileEntity::deterioateDome( int x, int y, int z ) { - deterioateHollowedVolume(x, y - 1, z, 8, 5, 0); - deterioateCrockedRoofVolume(false, x, y - 1 + 5, z, 8, 1, 0); - deterioateCrockedRoofVolume(true, x, y - 1 + 6, z, 5, 8, 0); - deterioateCrockedRoofVolume(false, x, y + -1 + 12, z, 3, 14, 0); -} - -void NetherReactorTileEntity::deterioateCrockedRoofVolume( bool inverted, int x, int y, int z, int expandWidth, int height, int tileId ) { - int fullHeight = height + expandWidth; - for(int curX = -expandWidth; curX <= expandWidth; ++curX) { - for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { - int offset = inverted ? ((-curX - curZ) / 2) : ((curX + curZ) / 2); - int acceptHeight = fullHeight + offset; - for(int curY = 0; curY < fullHeight + expandWidth; ++curY) { - if(acceptHeight >= curY - && (isEdge(curX, expandWidth, curZ))) { - if(level->random.nextInt(4) == 0) { - level->setTile(curX + x, curY + y, curZ + z, tileId); - } - } - } - } - } -} - -void NetherReactorTileEntity::deterioateHollowedVolume( int x, int y, int z, int expandWidth, int height, int tileId ) { - for(int curY = 0; curY < height; ++curY) { - for(int curX = -expandWidth; curX <= expandWidth; ++curX) { - for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { - if((curX == -expandWidth || curX == expandWidth) - || (curZ == -expandWidth || curZ == expandWidth)) { - if(level->random.nextInt(3) == 0) - level->setTile(curX + x, curY + y, curZ + z, tileId); - } - } - } - } -} - -bool NetherReactorTileEntity::playersAreCloseBy() { - int numPlayers = 0; - AABB bb((float)x, (float)y, (float)z, x + 1.0f, y + 1.0f, z + 1.0f); - EntityList nearby = level->getEntities(NULL, bb.grow(40, 40, 40)); - for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { - if((*it)->isPlayer() && (*it)->isAlive() ) { - if((*it)->distanceTo((float)x, (float)y, (float)z) < 40) - numPlayers++; - } - } - return numPlayers != 0; -} - -void NetherReactorTileEntity::killPigZombies() { - AABB bb((float)x, (float)y, (float)z, x + 1.0f, y + 1.0f, z + 1.0f); - EntityList nearby = level->getEntities(NULL, bb.grow(40, 40, 40)); - for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { - if((*it)->isEntityType(MobTypes::PigZombie)) { - (*it)->remove(); - } - } -} +#include "NetherReactorTileEntity.hpp" +#include "nbt/CompoundTag.hpp" +#include "SharedConstants.hpp" +#include "world/phys/Vec3.hpp" +#include "world/level/Level.hpp" +#include "world/level/MobSpawner.hpp" +#include "world/entity/MobFactory.hpp" +#include "world/level/tile/NetherReactor.hpp" +#include "world/entity/Entity.hpp" +#include "world/Difficulty.hpp" +#include "world/phys/AABB.hpp" +#include "world/level/tile/NetherReactorPattern.hpp" +NetherReactorTileEntity::NetherReactorTileEntity() + : super(TileEntityType::NetherReactor) + , isInitialized(false) + , progress(0) + , curLevel(0) + , hasFinished(false) +{ } + +bool NetherReactorTileEntity::shouldSave() { + return true; +} + +void NetherReactorTileEntity::lightItUp( int x, int y, int z ) { + //if(!isInitilized && !hasFinished) { + curLevel = 0; + NetherReactor::setPhase(level, x, y, z, 1); + isInitialized = true; + //clearDomeSpace(x, y, z); + buildDome(x, y, z); + + level->setNightMode(true); + //} +} + +void NetherReactorTileEntity::tick() { + if(level->isClientSide) + return; + if(progress < 0) { + remove = true; + } + if(isInitialized && !hasFinished) { + progress++; + if(progress % SharedConstants::TicksPerSecond == 0) { + int currentTime = progress / SharedConstants::TicksPerSecond; + if(currentTime < 10) { + tickGlowingRedstoneTransformation(currentTime); + } + if(currentTime > 42 && currentTime <= 45) { + // start with the top layer and move down + int currentLayer = 45 - currentTime; + turnGlowingObsidianLayerToObsidian(currentLayer); + } + if(checkLevelChange(progress / SharedConstants::TicksPerSecond)) { + curLevel++; + spawnItems(getNumItemsPerLevel(curLevel)); + trySpawnPigZombies(NUM_PIG_ZOMBIE_SLOTS, getNumEnemiesPerLevel(curLevel)); + } + } + if(progress > SharedConstants::TicksPerSecond * 46) { + finishReactorRun(); + } + } else if(hasFinished) { + if(progress % SharedConstants::TicksPerSecond * 60 == 0) { + if(playersAreCloseBy()) { + trySpawnPigZombies(2, 3); + } else { + killPigZombies(); + } + } + } +} + +void NetherReactorTileEntity::load( CompoundTag* tag ) { + super::load(tag); + isInitialized = tag->getBoolean("IsInitialized"); + if(isInitialized) { + progress = tag->getShort("Progress"); + hasFinished = tag->getBoolean("HasFinished"); + } +} + +bool NetherReactorTileEntity::save( CompoundTag* tag ) { + super::save(tag); + tag->putBoolean("IsInitialized", isInitialized); + tag->putShort("Progress", progress); + tag->putBoolean("HasFinished", hasFinished); + if(isInitialized && !hasFinished) + level->setNightMode(true); + return true; +} + +std::string NetherReactorTileEntity::getName() const { + return "NetherReactor"; +} + +int NetherReactorTileEntity::getNumEnemiesPerLevel( int curLevel ) { + if(curLevel == 0) + return 3; + else if(curLevel < 4) + return 2; + else if(curLevel < 6) + return Mth::Max(0, level->random.nextInt(2)); + else + return Mth::Max(0, level->random.nextInt(1)); +} + +int NetherReactorTileEntity::getNumItemsPerLevel( int curLevel ) { + if(curLevel == 0) + return 3 * 3; + else if(curLevel < 4) + return 5 * 3; + else if(curLevel < 8) + return Mth::Max(0, level->random.nextInt(14 * 3) - 4); + else + return Mth::Max(0, level->random.nextInt(9 * 3) - 2); +} + +void NetherReactorTileEntity::spawnItems( int numItems ) { + for (int ii = 0; ii < numItems ; ii++) { + spawnItem(); + } +} +Vec3 NetherReactorTileEntity::getSpawnPosition( float minDistance, float varibleDistance, float offset ) { + float distance = minDistance + level->random.nextFloat() * varibleDistance; + float rad = level->random.nextFloat() * Mth::TWO_PI; + return Vec3(sin(rad) * distance + x, offset + y, cos(rad) * distance + z); +} +void NetherReactorTileEntity::spawnEnemy() { + Mob* mob = MobFactory::CreateMob(MobTypes::PigZombie, level); + Vec3 enemyPosition = getSpawnPosition(3, 4, -1); + while(enemyPosition.x < 0 || enemyPosition.z < 0 || enemyPosition.x >= LEVEL_WIDTH || enemyPosition.z >= LEVEL_DEPTH) { + enemyPosition = getSpawnPosition(3, 4, -1); + } + MobSpawner::addMob(level, mob, enemyPosition.x, enemyPosition.y, enemyPosition.z, 0, 0, true); +} + + + +void NetherReactorTileEntity::spawnItem() { + Vec3 itemPosition= getSpawnPosition(3, 4, -1); + while(itemPosition.x < 0 || itemPosition.z < 0 || itemPosition.x >= LEVEL_WIDTH || itemPosition.z >= LEVEL_DEPTH) { + itemPosition = getSpawnPosition(3, 4, -1); + } + ItemEntity* item = new ItemEntity(level, itemPosition.x, itemPosition.y, itemPosition.z, getSpawnItem()); + + item->throwTime = 10; + item->age = item->getLifeTime() - SharedConstants::TicksPerSecond * 30; + level->addEntity(item); +} + +ItemInstance NetherReactorTileEntity::getSpawnItem() { + int itemType = level->random.nextInt(8); + switch(itemType) { + case 0: return ItemInstance(Item::yellowDust, 3); + case 1: return ItemInstance(Item::seeds_melon); + case 2: return ItemInstance(Tile::mushroom1); + case 3: return ItemInstance(Tile::mushroom2); + case 4: return ItemInstance(Item::reeds); + case 5: return ItemInstance(Tile::cactus); + case 6: return ItemInstance(Item::netherQuartz, 4); + default: return GetLowOddsSpawnItem(); + } +} + +ItemInstance NetherReactorTileEntity::GetLowOddsSpawnItem() { + if(level->random.nextInt(10) <= 9 ) { + static Item* items[] = { + Item::arrow, + Item::bed, + Item::bone, + Item::book, + Item::bow, + Item::bowl, + Item::feather, + Item::painting, + Item::door_wood + }; + int itemIndex = level->random.nextInt(sizeof(items) / sizeof(Item*)); + Item* itemToSpawn = items[itemIndex]; + return ItemInstance(itemToSpawn); + } else { + static Tile* tiles[] = { + Tile::bookshelf + }; + int tileIndex = level->random.nextInt(sizeof(tiles) / sizeof(Tile*)); + Tile* tileToSpawn = tiles[tileIndex]; + return ItemInstance(tileToSpawn); + } +} + +bool NetherReactorTileEntity::checkLevelChange( int progress ) { + static const int levelChangeTime[] = {10, 13, 20, 22, 25, 30, 34, 36, 38, 40}; + const int count = sizeof(levelChangeTime) / 4; + for(int a = 0; a < count; ++a) { + if(levelChangeTime[a] == progress) + return true; + } + return false; +} + +void NetherReactorTileEntity::clearDomeSpace( int x, int y, int z ) { + for(int curX = -12; curX <= 12; ++curX) { + for(int curY = -3; curY < 40; ++curY) { + for(int curZ = -12; curZ <= 12; ++curZ) { + if(curY > 2 || curX < -1 || curX > 1 || curZ < -1 || curZ > 1) + level->setTile(curX + x, curY + y, curZ + z, 0); + } + } + } +} + +void NetherReactorTileEntity::finishReactorRun() { + NetherReactor::setPhase(level, x, y, z, 2); + level->setNightMode(false); + hasFinished = true; + deterioateDome(x, y, z); + for(int curX = x - 1; curX <= x + 1; ++curX) { + for(int curY = y - 1; curY <= y + 1; ++curY) { + for(int curZ = z - 1; curZ <= z + 1; ++curZ) { + if(curX != x || curY != y || curZ != z) + level->setTile(curX, curY, curZ, Tile::obsidian->id); + } + } + } +} + +int NetherReactorTileEntity::numOfFreeEnemySlots() { + int numPigZombiesFound = 0; + AABB bb((float)x, (float)y, (float)z, x + 1.0f, y + 1.0f, z + 1.0f); + EntityList nearby = level->getEntities(NULL, bb.grow(7, 7, 7)); + for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { + if((*it)->isEntityType(MobTypes::PigZombie) && (*it)->isAlive()) { + numPigZombiesFound++; + } + } + return NUM_PIG_ZOMBIE_SLOTS - numPigZombiesFound; +} + +void NetherReactorTileEntity::trySpawnPigZombies( int maxNumOfEnemies, int maxToSpawn ) { + if(level->difficulty == Difficulty::PEACEFUL) + return; + int currentNumOfPigZombies = NUM_PIG_ZOMBIE_SLOTS - numOfFreeEnemySlots(); + if(currentNumOfPigZombies < maxNumOfEnemies) { + for(int a = 0; a < maxToSpawn && currentNumOfPigZombies < maxNumOfEnemies; ++a) { + spawnEnemy(); + currentNumOfPigZombies++; + } + } +} + +void NetherReactorTileEntity::tickGlowingRedstoneTransformation( int currentTime ) { + switch(currentTime) { + case 2: return turnLayerToGlowingObsidian(0, Tile::stoneBrick->id); + case 3: return turnLayerToGlowingObsidian(1, Tile::stoneBrick->id); + case 4: return turnLayerToGlowingObsidian(2, Tile::stoneBrick->id); + case 7: return turnLayerToGlowingObsidian(0, Tile::goldBlock->id); + case 8: return turnLayerToGlowingObsidian(1, Tile::goldBlock->id); + case 9: return turnLayerToGlowingObsidian(2, Tile::goldBlock->id); + } +} + +void NetherReactorTileEntity::turnLayerToGlowingObsidian( int layer, const int type ) { + NetherReactorPattern pattern; + for(int checkX = -1; checkX <= 1; ++checkX) { + for(int checkZ = -1; checkZ <= 1; ++checkZ) { + if(pattern.getTileAt(layer, checkX + 1, checkZ + 1) == type) { + level->setTile(x + checkX, y - 1 + layer, z + checkZ, Tile::glowingObsidian->id); + } + } + } +} + +void NetherReactorTileEntity::turnGlowingObsidianLayerToObsidian( int layer ) { + NetherReactorPattern pattern; + for(int checkX = -1; checkX <= 1; ++checkX) { + for(int checkZ = -1; checkZ <= 1; ++checkZ) { + if(level->getTile(x + checkX, y - 1 + layer, z + checkZ) != Tile::netherReactor->id) { + level->setTile(x + checkX, y - 1 + layer, z + checkZ, Tile::obsidian->id); + } + } + } +} + +void NetherReactorTileEntity::buildDome( int x, int y, int z ) { + buildFloorVolume(x, y - 3, z, 8, 2, Tile::netherrack->id); + buildHollowedVolume(x, y - 1, z, 8, 4, Tile::netherrack->id, 0); + buildFloorVolume(x, y - 1 + 4, z, 8, 1, Tile::netherrack->id); + buildCrockedRoofVolume(false, x, y - 1 + 5, z, 8, 1, Tile::netherrack->id); + buildCrockedRoofVolume(true, x, y - 1 + 6, z, 5, 8, Tile::netherrack->id); + buildCrockedRoofVolume(false, x, y + -1 + 12, z, 3, 14, Tile::netherrack->id); +} + +void NetherReactorTileEntity::buildHollowedVolume( int x, int y, int z, int expandWidth, int height, const int wallTileId, const int clearTileId ) { + for(int curY = 0; curY < height; ++curY) { + for(int curX = -expandWidth; curX <= expandWidth; ++curX) { + for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { + if((curX == -expandWidth || curX == expandWidth) + || (curZ == -expandWidth || curZ == expandWidth)) { + level->setTile(curX + x, curY + y, curZ + z, wallTileId); + } else if(curY > 2 || curX < -1 || curX > 1 || curZ < -1 || curZ > 1) { + level->setTile(curX + x, curY + y, curZ + z, clearTileId); + } + } + } + } +} + +void NetherReactorTileEntity::buildFloorVolume( int x, int y, int z, int expandWidth, int height, const int tileId ) { + for(int curY = 0; curY < height; ++curY) { + for(int curX = -expandWidth; curX <= expandWidth; ++curX) { + for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { + level->setTile(curX + x, curY + y, curZ + z, tileId); + } + } + } +} + +void NetherReactorTileEntity::buildCrockedRoofVolume( bool inverted, int x, int y, int z, int expandWidth, int height, const int tileId ) { + int fullHeight = height + expandWidth; + for(int curX = -expandWidth; curX <= expandWidth; ++curX) { + for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { + int offset = inverted ? ((-curX - curZ) / 2) : ((curX + curZ) / 2); + int acceptHeight = fullHeight + offset; + for(int curY = 0; curY < fullHeight + expandWidth; ++curY) { + if(acceptHeight >= curY + && (isEdge(curX, expandWidth, curZ) + || acceptHeight == curY )) { + level->setTile(curX + x, curY + y, curZ + z, tileId); + } + } + } + } +} + +bool NetherReactorTileEntity::isEdge( int curX, int expandWidth, int curZ ) { + return (curX == -expandWidth || curX == expandWidth) + || (curZ == -expandWidth || curZ == expandWidth); +} + +void NetherReactorTileEntity::deterioateDome( int x, int y, int z ) { + deterioateHollowedVolume(x, y - 1, z, 8, 5, 0); + deterioateCrockedRoofVolume(false, x, y - 1 + 5, z, 8, 1, 0); + deterioateCrockedRoofVolume(true, x, y - 1 + 6, z, 5, 8, 0); + deterioateCrockedRoofVolume(false, x, y + -1 + 12, z, 3, 14, 0); +} + +void NetherReactorTileEntity::deterioateCrockedRoofVolume( bool inverted, int x, int y, int z, int expandWidth, int height, int tileId ) { + int fullHeight = height + expandWidth; + for(int curX = -expandWidth; curX <= expandWidth; ++curX) { + for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { + int offset = inverted ? ((-curX - curZ) / 2) : ((curX + curZ) / 2); + int acceptHeight = fullHeight + offset; + for(int curY = 0; curY < fullHeight + expandWidth; ++curY) { + if(acceptHeight >= curY + && (isEdge(curX, expandWidth, curZ))) { + if(level->random.nextInt(4) == 0) { + level->setTile(curX + x, curY + y, curZ + z, tileId); + } + } + } + } + } +} + +void NetherReactorTileEntity::deterioateHollowedVolume( int x, int y, int z, int expandWidth, int height, int tileId ) { + for(int curY = 0; curY < height; ++curY) { + for(int curX = -expandWidth; curX <= expandWidth; ++curX) { + for(int curZ = -expandWidth; curZ <= expandWidth; ++curZ) { + if((curX == -expandWidth || curX == expandWidth) + || (curZ == -expandWidth || curZ == expandWidth)) { + if(level->random.nextInt(3) == 0) + level->setTile(curX + x, curY + y, curZ + z, tileId); + } + } + } + } +} + +bool NetherReactorTileEntity::playersAreCloseBy() { + int numPlayers = 0; + AABB bb((float)x, (float)y, (float)z, x + 1.0f, y + 1.0f, z + 1.0f); + EntityList nearby = level->getEntities(NULL, bb.grow(40, 40, 40)); + for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { + if((*it)->isPlayer() && (*it)->isAlive() ) { + if((*it)->distanceTo((float)x, (float)y, (float)z) < 40) + numPlayers++; + } + } + return numPlayers != 0; +} + +void NetherReactorTileEntity::killPigZombies() { + AABB bb((float)x, (float)y, (float)z, x + 1.0f, y + 1.0f, z + 1.0f); + EntityList nearby = level->getEntities(NULL, bb.grow(40, 40, 40)); + for(EntityList::iterator it = nearby.begin(); it != nearby.end(); ++it) { + if((*it)->isEntityType(MobTypes::PigZombie)) { + (*it)->remove(); + } + } +} diff --git a/src/world/level/tile/entity/NetherReactorTileEntity.h b/src/world/level/tile/entity/NetherReactorTileEntity.hpp similarity index 97% rename from src/world/level/tile/entity/NetherReactorTileEntity.h rename to src/world/level/tile/entity/NetherReactorTileEntity.hpp index 6ecf549..55442ad 100755 --- a/src/world/level/tile/entity/NetherReactorTileEntity.h +++ b/src/world/level/tile/entity/NetherReactorTileEntity.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../../../Pos.h" -#include "TileEntity.h" +#include "world/Pos.hpp" +#include "TileEntity.hpp" class NetherReactorTileEntity : public TileEntity { typedef TileEntity super; static const int NUM_PIG_ZOMBIE_SLOTS = 3; diff --git a/src/world/level/tile/entity/SignTileEntity.cpp b/src/world/level/tile/entity/SignTileEntity.cpp index aa85f00..f019661 100755 --- a/src/world/level/tile/entity/SignTileEntity.cpp +++ b/src/world/level/tile/entity/SignTileEntity.cpp @@ -1,58 +1,58 @@ -#include "SignTileEntity.h" -#include "../../../../network/packet/SignUpdatePacket.h" -#include "../../Level.h" -SignTileEntity::SignTileEntity() -: super(TileEntityType::Sign), - selectedLine(-1), - editable(true) -{ - rendererId = TR_SIGN_RENDERER; -} - -bool SignTileEntity::save( CompoundTag* tag ) { - if (!super::save(tag)) - return false; - - tag->putString("Text1", messages[0]); - tag->putString("Text2", messages[1]); - tag->putString("Text3", messages[2]); - tag->putString("Text4", messages[3]); - return true; -} - -void SignTileEntity::load( CompoundTag* tag ) { - editable = false; - super::load(tag); - - messages[0] = tag->getString("Text1"); - messages[1] = tag->getString("Text2"); - messages[2] = tag->getString("Text3"); - messages[3] = tag->getString("Text4"); - - for (int i = 0; i < NUM_LINES; i++) - if (messages[i].length() > MAX_LINE_LENGTH) - messages[i].resize(MAX_LINE_LENGTH); -} - -bool SignTileEntity::shouldSave() { - return true; -} - -bool SignTileEntity::isEditable() { - return editable; -} - -void SignTileEntity::setEditable( bool isEditable ) { - this->editable = isEditable; -} - -Packet* SignTileEntity::getUpdatePacket() { - return new SignUpdatePacket(x, y, z, messages); -} - -void SignTileEntity::setLevelAndPos( Level* level, int x, int y, int z ) { - super::setLevelAndPos(level, x, y, z); - if(level->getTile(x, y, z) != Tile::sign->id) { - remove = true; - } -} +#include "SignTileEntity.hpp" +#include "network/packet/SignUpdatePacket.hpp" +#include "world/level/Level.hpp" +SignTileEntity::SignTileEntity() +: super(TileEntityType::Sign), + selectedLine(-1), + editable(true) +{ + rendererId = TR_SIGN_RENDERER; +} + +bool SignTileEntity::save( CompoundTag* tag ) { + if (!super::save(tag)) + return false; + + tag->putString("Text1", messages[0]); + tag->putString("Text2", messages[1]); + tag->putString("Text3", messages[2]); + tag->putString("Text4", messages[3]); + return true; +} + +void SignTileEntity::load( CompoundTag* tag ) { + editable = false; + super::load(tag); + + messages[0] = tag->getString("Text1"); + messages[1] = tag->getString("Text2"); + messages[2] = tag->getString("Text3"); + messages[3] = tag->getString("Text4"); + + for (int i = 0; i < NUM_LINES; i++) + if (messages[i].length() > MAX_LINE_LENGTH) + messages[i].resize(MAX_LINE_LENGTH); +} + +bool SignTileEntity::shouldSave() { + return true; +} + +bool SignTileEntity::isEditable() { + return editable; +} + +void SignTileEntity::setEditable( bool isEditable ) { + this->editable = isEditable; +} + +Packet* SignTileEntity::getUpdatePacket() { + return new SignUpdatePacket(x, y, z, messages); +} + +void SignTileEntity::setLevelAndPos( Level* level, int x, int y, int z ) { + super::setLevelAndPos(level, x, y, z); + if(level->getTile(x, y, z) != Tile::sign->id) { + remove = true; + } +} diff --git a/src/world/level/tile/entity/SignTileEntity.h b/src/world/level/tile/entity/SignTileEntity.hpp similarity index 90% rename from src/world/level/tile/entity/SignTileEntity.h rename to src/world/level/tile/entity/SignTileEntity.hpp index f9ffb39..0271b22 100755 --- a/src/world/level/tile/entity/SignTileEntity.h +++ b/src/world/level/tile/entity/SignTileEntity.hpp @@ -4,9 +4,9 @@ /* import net.minecraft.network.packet.* */ -#include "../../../../nbt/CompoundTag.h" +#include "nbt/CompoundTag.hpp" -#include "TileEntity.h" +#include "TileEntity.hpp" class SignTileEntity: public TileEntity { diff --git a/src/world/level/tile/entity/TileEntity.cpp b/src/world/level/tile/entity/TileEntity.cpp index 0c76b95..b763d52 100755 --- a/src/world/level/tile/entity/TileEntity.cpp +++ b/src/world/level/tile/entity/TileEntity.cpp @@ -1,221 +1,221 @@ -#include "TileEntity.h" - -TileEntity::MapIdType TileEntity::idClassMap; -TileEntity::MapTypeId TileEntity::classIdMap; - -#include "FurnaceTileEntity.h" -#include "ChestTileEntity.h" -#include "NetherReactorTileEntity.h" -#include "../../Level.h" -#include "../../../../nbt/CompoundTag.h" -#include "SignTileEntity.h" - -int TileEntity::_runningId = 0; - -// -// TileEntityFactory -// -TileEntity* TileEntityFactory::createTileEntity( int type ) -{ - switch(type) { - case TileEntityType::Furnace: return new FurnaceTileEntity(); - case TileEntityType::Chest: return new ChestTileEntity(); - case TileEntityType::Sign: return new SignTileEntity(); - case TileEntityType::NetherReactor: return new NetherReactorTileEntity(); - default: - LOGE("Can't find TileEntity of type: %d\n", type); - return NULL; - } -} - -// -// TileEntity -// - -void TileEntity::initTileEntities() -{ - setId(TileEntityType::Furnace, "Furnace"); - setId(TileEntityType::Chest, "Chest"); - setId(TileEntityType::NetherReactor, "NetherReactor"); - // setId(ChestTileEntity.class, "Chest"); - // setId(RecordPlayerTile.Entity.class, "RecordPlayer"); - // setId(DispenserTileEntity.class, "Trap"); - setId(TileEntityType::Sign, "Sign"); - // setId(MobSpawnerTileEntity.class, "MobSpawner"); - // setId(MusicTileEntity.class, "Music"); - // setId(PistonPieceEntity.class, "Piston"); - // setId(BrewingStandTileEntity.class, "Cauldron"); - // setId(EnchantmentTableEntity.class, "EnchantTable"); - // setId(TheEndPortalTileEntity.class, "Airportal"); -} - -void TileEntity::teardownTileEntities() -{ - -} - -TileEntity::TileEntity( int tileEntityType ) -: data(-1), - type(tileEntityType), - remove(false), - level(NULL), - tile(NULL), - clientSideOnly(false), - rendererId(TR_DEFAULT_RENDERER), - runningId(++_runningId) -{ -} - -void TileEntity::load( CompoundTag* tag ) -{ - x = tag->getInt("x"); - y = tag->getInt("y"); - z = tag->getInt("z"); - LOGI("Loaded tile entity @ %d, %d, %d\n", x, y, z); -} - -bool TileEntity::save( CompoundTag* tag ) -{ - MapTypeId::const_iterator it = classIdMap.find(type); - if (it == classIdMap.end()) { - LOGE("TileEntityType %d is missing a mapping! This is a bug!\n", type); - return false; - } - tag->putString("id", it->second); - tag->putInt("x", x); - tag->putInt("y", y); - tag->putInt("z", z); - return true; -} - -TileEntity* TileEntity::loadStatic( CompoundTag* tag ) -{ - TileEntity* entity = NULL; - - std::string id = tag->getString("id"); - MapIdType::const_iterator cit = idClassMap.find(id); - if (cit != idClassMap.end()) { - //LOGI("Loading Tile Entity @ %d,%d,%d\n", )); - entity = TileEntityFactory::createTileEntity(cit->second); - if (entity) { - //LOGI("Loading TileEntity: %d\n", entity->type); - entity->load(tag); - } - else - LOGE("Couldn't create TileEntity of type: '%d'\n", cit->second); - } else { - LOGE("Couldn't find TileEntity type: '%s'\n", id.c_str()); - } - return entity; -} - -int TileEntity::getData() -{ - if (data == -1) data = level->getData(x, y, z); - return data; -} - -void TileEntity::setData( int data ) -{ - this->data = data; - level->setData(x, y, z, data); -} - -void TileEntity::setChanged() -{ - if (level != NULL) { - data = level->getData(x, y, z); - level->tileEntityChanged(x, y, z, this); - } -} - -float TileEntity::distanceToSqr( float xPlayer, float yPlayer, float zPlayer ) -{ - float xd = (x + 0.5f) - xPlayer; - float yd = (y + 0.5f) - yPlayer; - float zd = (z + 0.5f) - zPlayer; - return xd * xd + yd * yd + zd * zd; -} - -Tile* TileEntity::getTile() { - if (tile == NULL) tile = Tile::tiles[level->getTile(x, y, z)]; - return tile; -} - -bool TileEntity::isRemoved() const -{ - return remove; -} - -void TileEntity::setRemoved() -{ - remove = true; -} - -void TileEntity::clearRemoved() -{ - remove = false; -} - -void TileEntity::triggerEvent( int b0, int b1 ) -{ -} - -void TileEntity::clearCache() -{ - tile = NULL; - data = -1; -} - -void TileEntity::setId( int type, const std::string& id ) -{ - MapIdType::const_iterator cit = idClassMap.find(id); - if (cit != idClassMap.end()) { - LOGE("Duplicate id: %s\n", id.c_str()); - return; - } - - idClassMap.insert(std::make_pair(id, type)); - classIdMap.insert(std::make_pair(type, id)); -} - -void TileEntity::setLevelAndPos( Level* level, int x, int y, int z ) { - this->level = level; - this->x = x; - this->y = y; - this->z = z; - - if (level) { - this->tile = Tile::tiles[level->getTile(x, y, z)]; - } -} - -bool TileEntity::isFinished() { - return false; -} - -Packet* TileEntity::getUpdatePacket() { - return NULL; -} - -bool TileEntity::isType( int Type ) { - return type == Type; -} - -bool TileEntity::isType( TileEntity* te, int Type ) { - return te != NULL && te->isType(Type); -} - - -int partitionTileEntities( const std::vector& in, std::vector& keep, std::vector& dontKeep ) { - std::map m; - for (unsigned int i = 0; i < in.size(); ++i) { - TileEntity* e = in[i]; - TilePos p(e->x, e->y, e->z); - if (m.find(p) == m.end() && e->shouldSave()) { - m.insert(std::make_pair(p, e)); - keep.push_back(e); - } else dontKeep.push_back(e); - } - return (int)keep.size(); -} +#include "TileEntity.hpp" + +TileEntity::MapIdType TileEntity::idClassMap; +TileEntity::MapTypeId TileEntity::classIdMap; + +#include "FurnaceTileEntity.hpp" +#include "ChestTileEntity.hpp" +#include "NetherReactorTileEntity.hpp" +#include "world/level/Level.hpp" +#include "nbt/CompoundTag.hpp" +#include "SignTileEntity.hpp" + +int TileEntity::_runningId = 0; + +// +// TileEntityFactory +// +TileEntity* TileEntityFactory::createTileEntity( int type ) +{ + switch(type) { + case TileEntityType::Furnace: return new FurnaceTileEntity(); + case TileEntityType::Chest: return new ChestTileEntity(); + case TileEntityType::Sign: return new SignTileEntity(); + case TileEntityType::NetherReactor: return new NetherReactorTileEntity(); + default: + LOGE("Can't find TileEntity of type: %d\n", type); + return NULL; + } +} + +// +// TileEntity +// + +void TileEntity::initTileEntities() +{ + setId(TileEntityType::Furnace, "Furnace"); + setId(TileEntityType::Chest, "Chest"); + setId(TileEntityType::NetherReactor, "NetherReactor"); + // setId(ChestTileEntity.class, "Chest"); + // setId(RecordPlayerTile.Entity.class, "RecordPlayer"); + // setId(DispenserTileEntity.class, "Trap"); + setId(TileEntityType::Sign, "Sign"); + // setId(MobSpawnerTileEntity.class, "MobSpawner"); + // setId(MusicTileEntity.class, "Music"); + // setId(PistonPieceEntity.class, "Piston"); + // setId(BrewingStandTileEntity.class, "Cauldron"); + // setId(EnchantmentTableEntity.class, "EnchantTable"); + // setId(TheEndPortalTileEntity.class, "Airportal"); +} + +void TileEntity::teardownTileEntities() +{ + +} + +TileEntity::TileEntity( int tileEntityType ) +: data(-1), + type(tileEntityType), + remove(false), + level(NULL), + tile(NULL), + clientSideOnly(false), + rendererId(TR_DEFAULT_RENDERER), + runningId(++_runningId) +{ +} + +void TileEntity::load( CompoundTag* tag ) +{ + x = tag->getInt("x"); + y = tag->getInt("y"); + z = tag->getInt("z"); + LOGI("Loaded tile entity @ %d, %d, %d\n", x, y, z); +} + +bool TileEntity::save( CompoundTag* tag ) +{ + MapTypeId::const_iterator it = classIdMap.find(type); + if (it == classIdMap.end()) { + LOGE("TileEntityType %d is missing a mapping! This is a bug!\n", type); + return false; + } + tag->putString("id", it->second); + tag->putInt("x", x); + tag->putInt("y", y); + tag->putInt("z", z); + return true; +} + +TileEntity* TileEntity::loadStatic( CompoundTag* tag ) +{ + TileEntity* entity = NULL; + + std::string id = tag->getString("id"); + MapIdType::const_iterator cit = idClassMap.find(id); + if (cit != idClassMap.end()) { + //LOGI("Loading Tile Entity @ %d,%d,%d\n", )); + entity = TileEntityFactory::createTileEntity(cit->second); + if (entity) { + //LOGI("Loading TileEntity: %d\n", entity->type); + entity->load(tag); + } + else + LOGE("Couldn't create TileEntity of type: '%d'\n", cit->second); + } else { + LOGE("Couldn't find TileEntity type: '%s'\n", id.c_str()); + } + return entity; +} + +int TileEntity::getData() +{ + if (data == -1) data = level->getData(x, y, z); + return data; +} + +void TileEntity::setData( int data ) +{ + this->data = data; + level->setData(x, y, z, data); +} + +void TileEntity::setChanged() +{ + if (level != NULL) { + data = level->getData(x, y, z); + level->tileEntityChanged(x, y, z, this); + } +} + +float TileEntity::distanceToSqr( float xPlayer, float yPlayer, float zPlayer ) +{ + float xd = (x + 0.5f) - xPlayer; + float yd = (y + 0.5f) - yPlayer; + float zd = (z + 0.5f) - zPlayer; + return xd * xd + yd * yd + zd * zd; +} + +Tile* TileEntity::getTile() { + if (tile == NULL) tile = Tile::tiles[level->getTile(x, y, z)]; + return tile; +} + +bool TileEntity::isRemoved() const +{ + return remove; +} + +void TileEntity::setRemoved() +{ + remove = true; +} + +void TileEntity::clearRemoved() +{ + remove = false; +} + +void TileEntity::triggerEvent( int b0, int b1 ) +{ +} + +void TileEntity::clearCache() +{ + tile = NULL; + data = -1; +} + +void TileEntity::setId( int type, const std::string& id ) +{ + MapIdType::const_iterator cit = idClassMap.find(id); + if (cit != idClassMap.end()) { + LOGE("Duplicate id: %s\n", id.c_str()); + return; + } + + idClassMap.insert(std::make_pair(id, type)); + classIdMap.insert(std::make_pair(type, id)); +} + +void TileEntity::setLevelAndPos( Level* level, int x, int y, int z ) { + this->level = level; + this->x = x; + this->y = y; + this->z = z; + + if (level) { + this->tile = Tile::tiles[level->getTile(x, y, z)]; + } +} + +bool TileEntity::isFinished() { + return false; +} + +Packet* TileEntity::getUpdatePacket() { + return NULL; +} + +bool TileEntity::isType( int Type ) { + return type == Type; +} + +bool TileEntity::isType( TileEntity* te, int Type ) { + return te != NULL && te->isType(Type); +} + + +int partitionTileEntities( const std::vector& in, std::vector& keep, std::vector& dontKeep ) { + std::map m; + for (unsigned int i = 0; i < in.size(); ++i) { + TileEntity* e = in[i]; + TilePos p(e->x, e->y, e->z); + if (m.find(p) == m.end() && e->shouldSave()) { + m.insert(std::make_pair(p, e)); + keep.push_back(e); + } else dontKeep.push_back(e); + } + return (int)keep.size(); +} diff --git a/src/world/level/tile/entity/TileEntity.h b/src/world/level/tile/entity/TileEntity.hpp similarity index 96% rename from src/world/level/tile/entity/TileEntity.h rename to src/world/level/tile/entity/TileEntity.hpp index c0a66b1..bafb2f5 100755 --- a/src/world/level/tile/entity/TileEntity.h +++ b/src/world/level/tile/entity/TileEntity.hpp @@ -2,10 +2,10 @@ //package net.minecraft.world.level->tile.entity; -#include "../Tile.h" +#include "world/level/tile/Tile.hpp" #include #include -#include "TileEntityRendererId.h" +#include "TileEntityRendererId.hpp" class Level; class TileEntity; diff --git a/src/world/level/tile/entity/TileEntityRendererId.h b/src/world/level/tile/entity/TileEntityRendererId.hpp similarity index 100% rename from src/world/level/tile/entity/TileEntityRendererId.h rename to src/world/level/tile/entity/TileEntityRendererId.hpp diff --git a/src/world/phys/AABB.h b/src/world/phys/AABB.hpp similarity index 99% rename from src/world/phys/AABB.h rename to src/world/phys/AABB.hpp index 3fa43ff..ad15192 100755 --- a/src/world/phys/AABB.h +++ b/src/world/phys/AABB.hpp @@ -3,8 +3,8 @@ //package net.minecraft.world.phys; #include -#include "Vec3.h" -#include "HitResult.h" +#include "Vec3.hpp" +#include "HitResult.hpp" #include class AABB diff --git a/src/world/phys/HitResult.cpp b/src/world/phys/HitResult.cpp index 493a372..6d61a8d 100755 --- a/src/world/phys/HitResult.cpp +++ b/src/world/phys/HitResult.cpp @@ -1,49 +1,49 @@ -#include "HitResult.h" -#include "../entity/Entity.h" - - -HitResult::HitResult() -: type(NO_HIT), - entity(NULL), - indirectHit(false) -{} - -HitResult::HitResult(int x, int y, int z, int f, const Vec3& pos) -: type(TILE), - x(x), - y(y), - z(z), - f(f), - pos(pos), - indirectHit(false), - entity(NULL) -{ -} - -HitResult::HitResult(Entity* entity) -: type(ENTITY), - entity(entity), - pos(entity->x, entity->y, entity->z), - indirectHit(false) -{ -} - -HitResult::HitResult(const HitResult& hr) - : type(hr.type), - x(hr.x), - y(hr.y), - z(hr.z), - f(hr.f), - pos(hr.pos), - indirectHit(hr.indirectHit), - entity(hr.entity) -{ -} - - -float HitResult::distanceTo(Entity* entity) const { - float xd = pos.x - entity->x; - float yd = pos.y - entity->y; - float zd = pos.z - entity->z; - return xd * xd + yd * yd + zd * zd; -} +#include "HitResult.hpp" +#include "world/entity/Entity.hpp" + + +HitResult::HitResult() +: type(NO_HIT), + entity(NULL), + indirectHit(false) +{} + +HitResult::HitResult(int x, int y, int z, int f, const Vec3& pos) +: type(TILE), + x(x), + y(y), + z(z), + f(f), + pos(pos), + indirectHit(false), + entity(NULL) +{ +} + +HitResult::HitResult(Entity* entity) +: type(ENTITY), + entity(entity), + pos(entity->x, entity->y, entity->z), + indirectHit(false) +{ +} + +HitResult::HitResult(const HitResult& hr) + : type(hr.type), + x(hr.x), + y(hr.y), + z(hr.z), + f(hr.f), + pos(hr.pos), + indirectHit(hr.indirectHit), + entity(hr.entity) +{ +} + + +float HitResult::distanceTo(Entity* entity) const { + float xd = pos.x - entity->x; + float yd = pos.y - entity->y; + float zd = pos.z - entity->z; + return xd * xd + yd * yd + zd * zd; +} diff --git a/src/world/phys/HitResult.h b/src/world/phys/HitResult.hpp similarity index 96% rename from src/world/phys/HitResult.h rename to src/world/phys/HitResult.hpp index 8317642..362ac69 100755 --- a/src/world/phys/HitResult.h +++ b/src/world/phys/HitResult.hpp @@ -2,7 +2,7 @@ //package net.minecraft.world.phys; -#include "Vec3.h" +#include "Vec3.hpp" class Entity; enum HitResultType { diff --git a/src/world/phys/Vec3.h b/src/world/phys/Vec3.hpp similarity index 100% rename from src/world/phys/Vec3.h rename to src/world/phys/Vec3.hpp