Visual Studio Project Overhaul + Cleanup (#80)

* Visual Studio Project Overhaul + Cleanup
* SDL2 project for Windows
* Re-added game client icon to SDL2 code
* Renamed "AppPlatform_windows" to "AppPlatform_win32" (this is the name of the Windows API and is not representative of the architecture type)
* Renamed "LoggerWindows" to "LoggerWin32"
* Renamed "SoundSystemWindows to "SoundSystemDS" (DirectSound). This may be used for the 360, so it wouldn't really be Windows-specific then.
* Moved "ClientSideNetworkHandler" from "network" to "client/network". We don't need it being compiled for the server if the client's the only thing that needs it.
* I wonder if this still works on macOS...

* Bugfixes & Fixed for macOS

* Options::savePropertiesToFile Logging Bugfix

* Silence Winsock Deprecation Warnings in RakNet

* VS Project Improvements
- Replaced 50 billion relative paths with $(MC_ROOT)
- Added $(RAKNET_PATH) variable to override RakNet location
- Re-added gitignore for .vcxproj.user files
- Added debugging config to Directory.Builds.props
- Slimmed down project configurations for SDL2

* VS Project Config Bugfixes
- Fixed RakNet header path for additional includes

* RakNet Target for XCode

* XCode Project Config Fixes

* Packet logging

* Network VS Project Filter Fix

* Fix RakNet Packet ID Length
We previously didn't have consistency between old and new C++ regarding PacketType enum length. Now we do. This is required or else it completely breaks networking between the versions.

* Additional RakNet Error Handling

* Disable packet logging

* * Fix CMakeLists.txt

This reflects the relocation of ClientSideNetworkHandler.cpp.

* * Also add renderer/GL/GL.cpp to the CMakeLists.txt

* * Replace libpng with stb_image

* * Fix buggy water behavior.

* * Put the CMakeLists of the SDL project in debug mode

* Visual Studio 2010 Support

* * Change the SdlIoCallbacks from an array to a single member.

This fixes compilation of the sdl2 target on VS.

* * Fix missing _error label.

* Revert "* Fix missing _error label."

This reverts commit 99a057fc84049a16c864bd840fb439a008af5c74.

* Revert "* Replace libpng with stb_image"

* info_updateGame Tiles

---------

Co-authored-by: Brent Da Mage <BrentDaMage@users.noreply.github.com>
Co-authored-by: iProgramInCpp <iprogramincpp@gmail.com>
This commit is contained in:
Brent
2023-10-22 02:08:59 -05:00
committed by GitHub
parent 8b0eb798cd
commit f12a3c1c61
138 changed files with 9846 additions and 9382 deletions

63
source/client/app/App.cpp Normal file
View File

@@ -0,0 +1,63 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "App.hpp"
void App::destroy()
{
}
void App::draw()
{
}
bool App::handleBack(bool b)
{
return false;
}
void App::init()
{
}
void App::loadState(void* a2, int a3)
{
}
AppPlatform* App::platform()
{
return m_pPlatform;
}
void App::quit()
{
m_bWantToQuit = true;
}
bool App::wantToQuit()
{
return m_bWantToQuit;
}
void App::saveState(void**, int)
{
}
void App::update()
{
}
void App::sizeUpdate(int newWidth, int newHeight)
{
}

46
source/client/app/App.hpp Normal file
View File

@@ -0,0 +1,46 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#pragma once
#include "AppPlatform.hpp"
class App
{
protected:
App()
{
m_bWantToQuit = false;
m_pPlatform = nullptr;
}
public:
virtual bool handleBack(bool);
virtual void init();
virtual void update();
virtual void sizeUpdate(int newWidth, int newHeight);
void destroy();
void draw();
void loadState(void*, int);
AppPlatform* platform();
void quit();
void saveState(void**, int);
bool wantToQuit();
public:
bool m_bWantToQuit;
// don't know what these are ...
int field_8;
int field_C;
int field_10;
AppPlatform* m_pPlatform;
};

View File

@@ -0,0 +1,168 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "AppPlatform.hpp"
#include "common/Utils.hpp"
AppPlatform* AppPlatform::m_singleton = nullptr;
AppPlatform* const AppPlatform::singleton()
{
return m_singleton;
}
AppPlatform::AppPlatform()
{
m_singleton = this;
}
AppPlatform::~AppPlatform()
{
}
void AppPlatform::_tick()
{
}
void AppPlatform::buyGame()
{
}
int AppPlatform::checkLicense()
{
return 0; // assume no license
}
void AppPlatform::createUserInput()
{
}
void AppPlatform::finish()
{
}
std::string AppPlatform::getDateString(int time)
{
return "";
}
// ??? AppPlatform::getOptionStrings()
int AppPlatform::getScreenWidth() const
{
return C_DEFAULT_SCREEN_WIDTH; // default rez of the XPERIA PLAY?
}
int AppPlatform::getScreenHeight() const
{
return C_DEFAULT_SCREEN_HEIGHT;
}
std::vector<std::string> AppPlatform::getUserInput()
{
return std::vector<std::string>();
}
int AppPlatform::getUserInputStatus()
{
return 0;
}
bool AppPlatform::hasBuyButtonWhenInvalidLicense()
{
return false;
}
// void AppPlatform::loadTexture(const std::string&, bool);
void AppPlatform::saveScreenshot(const std::string&, int, int)
{
}
void AppPlatform::showDialog(eDialogType type)
{
}
void AppPlatform::uploadPlatformDependentData(int, void*)
{
}
Texture AppPlatform::loadTexture(const std::string&, bool)
{
return Texture(0, 0, nullptr, 1, 0);
}
void AppPlatform::recenterMouse()
{
}
void AppPlatform::setMouseGrabbed(bool b)
{
}
void AppPlatform::getMouseDiff(int& x, int& y)
{
x = y = 0;
}
void AppPlatform::clearDiff()
{
}
void AppPlatform::updateFocused(bool focused)
{
}
bool AppPlatform::shiftPressed()
{
return false;
}
bool AppPlatform::hasFileSystemAccess()
{
return false;
}
std::string AppPlatform::getPatchData()
{
return "";
}
void AppPlatform::initSoundSystem()
{
}
SoundSystem* const AppPlatform::getSoundSystem() const
{
return nullptr;
}
std::string AppPlatform::getAssetPath(const std::string &path) const
{
std::string realPath = path;
if (realPath.size() && realPath[0] == '/')
{
// trim it off
realPath = realPath.substr(1);
}
realPath = "assets/" + realPath;
return realPath;
}

View File

@@ -0,0 +1,73 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#pragma once
#include <string>
#include <vector>
#include "client/renderer/Texture.hpp"
#include "client/sound/SoundSystem.hpp"
class AppPlatform
{
public:
enum eDialogType
{
DLG_CREATE_WORLD = 1,
DLG_CHAT,
DLG_OPTIONS,
DLG_RENAME_MP_WORLD,
};
private:
static AppPlatform* m_singleton;
public:
static AppPlatform* const singleton();
AppPlatform();
~AppPlatform();
virtual void buyGame();
virtual int checkLicense();
virtual void createUserInput();
virtual void finish();
virtual std::string getDateString(int);
virtual int getScreenWidth() const;
virtual int getScreenHeight() const;
virtual std::vector<std::string> getUserInput();
virtual int getUserInputStatus();
virtual bool hasBuyButtonWhenInvalidLicense();
virtual void saveScreenshot(const std::string&, int, int);
virtual void showDialog(eDialogType);
virtual void uploadPlatformDependentData(int, void*);
virtual Texture loadTexture(const std::string&, bool);
#ifndef ORIGINAL_CODE
// Also add these to allow proper turning within the game.
virtual void recenterMouse();
virtual void setMouseGrabbed(bool b);
virtual void getMouseDiff(int& x, int& y);
virtual void clearDiff();
virtual void updateFocused(bool focused);
// Also add this to allow proper text input within the game.
virtual bool shiftPressed();
virtual bool hasFileSystemAccess();
// Also add this to allow dynamic patching.
virtual std::string getPatchData();
virtual void initSoundSystem();
virtual SoundSystem* const getSoundSystem() const;
#endif
public:
virtual std::string getAssetPath(const std::string& path) const;
private:
virtual void _tick();
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#pragma once
#include "App.hpp"
#include "common/CThread.hpp"
#include "common/Mth.hpp"
#include "common/Timer.hpp"
#include "client/gui/Gui.hpp"
#include "client/gui/Screen.hpp"
#include "network/RakNetInstance.hpp"
#include "network/NetEventCallback.hpp"
#include "client/player/input/ITurnInput.hpp"
#include "client/renderer/GameRenderer.hpp"
#include "client/renderer/LevelRenderer.hpp"
#include "client/renderer/entity/EntityRenderDispatcher.hpp"
#include "client/sound/SoundEngine.hpp"
#include "world/level/Level.hpp"
#include "world/entity/LocalPlayer.hpp"
#include "world/gamemode/GameMode.hpp"
#include "world/particle/ParticleEngine.hpp"
class Screen; // in case we're included from Screen.hpp
class Minecraft : public App
{
public:
Minecraft();
virtual ~Minecraft();
int getLicenseId();
void setScreen(Screen * pScreen);
void releaseMouse();
void grabMouse();
void tick();
void tickInput();
void saveOptions();
void handleMouseClick(int type);
void handleMouseDown(int type, bool b);
bool isLevelGenerated();
void selectLevel(const std::string&, const std::string&, int);
void setLevel(Level*, const std::string&, LocalPlayer*);
void pauseGame();
void leaveGame(bool bCopyMap);
void hostMultiplayer();
void joinMultiplayer(const PingedCompatibleServer& serverInfo);
void cancelLocateMultiplayer();
void locateMultiplayer();
void tickMouse();
void handleCharInput(char chr);
void sendMessage(const std::string& message);
void resetPlayer(Player* player);
void respawnPlayer(Player* player);
std::string getVersionString();
virtual void update() override;
virtual void init() override;
virtual void onGraphicsReset();
virtual void sizeUpdate(int newWidth, int newHeight) override;
virtual int getFpsIntlCounter();
float getBestScaleForThisScreenSize(int width, int height);
void generateLevel(const std::string& unused, Level* pLevel);
void prepareLevel(const std::string& unused);
void _levelGenerated();
bool isOnline();
bool isOnlineClient();
static void* prepareLevel_tspawn(void* pMinecraft);
const char* getProgressMessage();
LevelStorageSource* getLevelSource();
ItemInstance* getSelectedItem();
Options* getOptions() const { return m_options; }
static void setGuiScaleMultiplier(float f);
public:
static float guiScaleMultiplier;
static int width, height;
static bool useAmbientOcclusion;
static const char* progressMessages[];
static const bool DEADMAU5_CAMERA_CHEATS;
static int customDebugId;
private:
Logger *m_Logger;
Options *m_options;
public:
bool field_18;
bool field_288;
LevelRenderer* m_pLevelRenderer;
GameRenderer* m_pGameRenderer;
ParticleEngine* m_pParticleEngine;
SoundEngine* m_pSoundEngine;
GameMode* m_pGameMode;
Textures* m_pTextures;
Font* m_pFont;
RakNetInstance* m_pRakNetInstance;
NetEventCallback* m_pNetEventCallback;
int field_2B0;
int field_2B4;
int field_2B8;
User* m_pUser;
Level* m_pLevel;
LocalPlayer* m_pLocalPlayer;
Mob* m_pMobPersp; // why is there a duplicate?
Gui m_gui;
int field_D0C;
CThread* m_pPrepThread;
Screen* m_pScreen;
int field_D18;
ITurnInput* m_pTurnInput;
float field_D20;
float field_D24;
bool m_bGrabbedMouse;
HitResult m_hitResult;
int m_progressPercent;
std::string m_externalStorageDir;
Timer m_timer;
bool m_bPreparingLevel;
LevelStorageSource* m_pLevelStorageSource; // TODO
int field_D9C;
int field_DA0;
int field_DA4;
int field_DA8;
int field_DAC;
bool m_bUsingScreen;
bool m_bHasQueuedScreen;
Screen* m_pQueuedScreen;
int m_licenseID;
ItemInstance m_CurrItemInstance;
// in 0.8. Offset 3368
double m_fDeltaTime, m_fLastUpdated;
};

View File

@@ -0,0 +1,154 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "NinecraftApp.hpp"
#include "world/item/Item.hpp"
#include "client/gui/screens/StartMenuScreen.hpp"
#ifdef DEMO
#include "world/level/storage/MemoryLevelStorageSource.hpp"
#else
#include "world/level/storage/ExternalFileLevelStorageSource.hpp"
#endif
bool NinecraftApp::_hasInitedStatics;
bool NinecraftApp::handleBack(bool b)
{
if (m_bPreparingLevel)
return true;
if (!m_pLevel)
{
if (!m_pScreen)
return false;
return m_pScreen->handleBackEvent(b);
}
if (b)
return 1;
if (!m_pScreen) return false;
if (m_pScreen->handleBackEvent(b))
return true;
setScreen(nullptr);
return true;
}
void NinecraftApp::initGLStates()
{
GL_TEXTURE_2D;
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.1f);
glCullFace(GL_BACK);
glEnable(GL_TEXTURE_2D);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glDisable(GL_LIGHTING);
}
int NinecraftApp::getFpsIntlCounter()
{
int ofps = m_fps;
m_fps = 0;
return ofps;
}
void NinecraftApp::init()
{
Mth::initMth();
if (!_hasInitedStatics)
{
_hasInitedStatics = true;
Material::initMaterials();
Tile::initTiles();
Item::initItems();
Biome::initBiomes();
}
initGLStates();
Tesselator::instance.init();
platform()->initSoundSystem();
Minecraft::init();
#ifdef DEMO
m_pLevelStorageSource = new MemoryLevelStorageSource;
#else
m_pLevelStorageSource = new ExternalFileLevelStorageSource(m_externalStorageDir);
#endif
field_D9C = 0;
setScreen(new StartMenuScreen);
}
void NinecraftApp::onGraphicsReset()
{
initGLStates();
Tesselator::instance.init();
Minecraft::onGraphicsReset();
}
void NinecraftApp::teardown()
{
}
void NinecraftApp::update()
{
++m_fps;
Minecraft::update();
#ifdef ORIGINAL_CODE
eglSwapBuffers(field_8, m_rotY);
#endif
Mouse::reset2();
updateStats();
}
void NinecraftApp::updateStats()
{
/*
int timeMs = getTimeMs();
if (timeMs > field_2B0 + 999)
{
if (m_pLocalPlayer)
{
Vec3 &pos = m_pLocalPlayer->m_pos;
LOG_I("%d fps\t%3d chunk updates. (%.2f, %.2f, %.2f)", m_fps, Chunk::updates, pos.x, pos.y, pos.z);
LOG_I("%s", m_pLevelRenderer->gatherStats1().c_str());
Chunk::updates = 0;
}
else
{
LOG_I("%d fps", m_fps);
}
field_2B0 = timeMs;
m_fps = 0;
}
*/
}
NinecraftApp::NinecraftApp()
{
field_DBC = 0;
field_DC0 = 1;
m_fps = 0;
}
NinecraftApp::~NinecraftApp()
{
teardown();
}

View File

@@ -0,0 +1,41 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#pragma once
#include "client/app/Minecraft.hpp"
#include "world/level/Level.hpp"
#include "world/tile/Tile.hpp"
//@TYPO: This is probably meant to say "MinecraftApp". Still not fixed in V0.3.0 though so not sure
// This is renamed to MinecraftClient in 0.13.1
class NinecraftApp : public Minecraft
{
public:
NinecraftApp();
virtual ~NinecraftApp();
bool handleBack(bool) override;
void init() override;
void update() override;
void onGraphicsReset() override;
void teardown();
void updateStats();
void initGLStates();
int getFpsIntlCounter() override;
private:
int field_DBC;
bool field_DC0;
int m_fps;
static bool _hasInitedStatics;
};

View File

@@ -6,7 +6,7 @@
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#include "client/gui/screens/IngameBlockSelectionScreen.hpp"
#include "client/gui/screens/ChatScreen.hpp"
#include "client/renderer/entity/ItemRenderer.hpp"

View File

@@ -9,7 +9,7 @@
#pragma once
#include "GuiComponent.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#include "common/Random.hpp"
#include "common/Utils.hpp"

View File

@@ -9,7 +9,7 @@
#pragma once
#include "../GuiComponent.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
class Screen;

View File

@@ -9,7 +9,7 @@
#pragma once
#include "../GuiComponent.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
class RolledSelectionList : public GuiComponent
{

View File

@@ -9,7 +9,7 @@
#pragma once
#include "../GuiComponent.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
class ScrolledSelectionList : public GuiComponent
{

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "TextInputBox.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#ifndef ORIGINAL_CODE
TextInputBox::TextInputBox(int id, int x, int y, int width, int height, const std::string& placeholder, const std::string& text)
@@ -111,16 +111,16 @@ void TextInputBox::keyPressed(Minecraft* minecraft, int key)
char chr = '\0';
// here we'll just use the raw key codes...
#ifdef _WIN32
#define AKEYCODE_FORWARD_DEL VK_DELETE
#define AKEYCODE_ARROW_LEFT VK_LEFT
#define AKEYCODE_ARROW_RIGHT VK_RIGHT
#define AKEYCODE_DEL VK_BACK
#elif defined(USE_SDL)
#ifdef USE_SDL
#define AKEYCODE_FORWARD_DEL SDLVK_DELETE
#define AKEYCODE_ARROW_LEFT SDLVK_LEFT
#define AKEYCODE_ARROW_RIGHT SDLVK_RIGHT
#define AKEYCODE_DEL SDLVK_BACKSPACE
#elif defined(_WIN32)
#define AKEYCODE_FORWARD_DEL VK_DELETE
#define AKEYCODE_ARROW_LEFT VK_LEFT
#define AKEYCODE_ARROW_RIGHT VK_RIGHT
#define AKEYCODE_DEL VK_BACK
#endif
switch (key)

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "Cube.hpp"
#include "common/Utils.hpp"
#include "renderer/GL/GL.hpp"
const float Cube::c = 180.0f / float(M_PI);

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "HumanoidModel.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
HumanoidModel::HumanoidModel(float a, float b):
m_head(0, 0),

View File

@@ -0,0 +1,509 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include <RakPeer.h>
#include "ClientSideNetworkHandler.hpp"
#include "common/Utils.hpp"
#include "client/gui/screens/StartMenuScreen.hpp"
// This lets you make the client shut up and not log events in the debug console.
#define VERBOSE_CLIENT
#if defined(ORIGINAL_CODE) || defined(VERBOSE_CLIENT)
#define puts_ignorable(str) LOG_I(str)
#define printf_ignorable(str, ...) LOG_I(str, __VA_ARGS__)
#else
#define puts_ignorable(str)
#define printf_ignorable(str, ...)
#endif
ClientSideNetworkHandler::ClientSideNetworkHandler(Minecraft* pMinecraft, RakNetInstance* pRakNetInstance)
{
m_pMinecraft = pMinecraft;
m_pRakNetInstance = pRakNetInstance;
m_pServerPeer = m_pRakNetInstance->getPeer();
m_chunksRequested = 0;
m_serverProtocolVersion = 0;
m_pLevel = nullptr;
m_field_14 = 0;
m_field_24 = 0;
}
void ClientSideNetworkHandler::levelGenerated(Level* level)
{
m_pLevel = level;
requestNextChunk();
}
void ClientSideNetworkHandler::onConnect(const RakNet::RakNetGUID& rakGuid) // server guid
{
RakNet::RakNetGUID localGuid = ((RakNet::RakPeer*)m_pServerPeer)->GetMyGUID();
printf_ignorable("onConnect, server guid: %s, local guid: %s", rakGuid.ToString(), localGuid.ToString());
m_serverGUID = rakGuid;
LoginPacket* pLoginPkt = new LoginPacket;
pLoginPkt->m_str = RakNet::RakString(m_pMinecraft->m_pUser->field_0.c_str());
m_pRakNetInstance->send(pLoginPkt);
}
void ClientSideNetworkHandler::onUnableToConnect()
{
puts_ignorable("onUnableToConnect");
// get rid of the prepare-thread to stop preparation immediately
if (m_pMinecraft->m_pPrepThread)
{
delete m_pMinecraft->m_pPrepThread;
m_pMinecraft->m_pPrepThread = nullptr;
}
// throw to the start menu for now
m_pMinecraft->setScreen(new StartMenuScreen);
}
void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& rakGuid)
{
puts_ignorable("onDisconnect");
if (m_pLevel)
m_pLevel->m_bIsMultiplayer = false;
m_pMinecraft->m_gui.addMessage("Disconnected from server");
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, MessagePacket* pMsgPkt)
{
puts_ignorable("MessagePacket");
m_pMinecraft->m_gui.addMessage(pMsgPkt->m_str.C_String());
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, StartGamePacket* pStartGamePkt)
{
puts_ignorable("StartGamePacket");
m_pMinecraft->getLevelSource()->deleteLevel("_LastJoinedServer");
m_pLevel = new Level(
m_pMinecraft->getLevelSource()->selectLevel("_LastJoinedServer", true),
"temp",
pStartGamePkt->field_4,
pStartGamePkt->field_8);
m_pLevel->m_bIsMultiplayer = true;
LocalPlayer *pLocalPlayer = new LocalPlayer(m_pMinecraft, m_pLevel, m_pMinecraft->m_pUser, m_pLevel->m_pDimension->field_50);
pLocalPlayer->m_guid = ((RakNet::RakPeer*)m_pServerPeer)->GetMyGUID();
pLocalPlayer->m_EntityID = pStartGamePkt->field_C;
pLocalPlayer->moveTo(
pStartGamePkt->field_10,
pStartGamePkt->field_14,
pStartGamePkt->field_18,
pLocalPlayer->m_yaw,
pLocalPlayer->m_pitch);
pLocalPlayer->m_pInventory->prepareCreativeInventory();
m_pLevel->setTime(pStartGamePkt->m_time);
m_serverProtocolVersion = pStartGamePkt->m_version;
m_pMinecraft->setLevel(m_pLevel, "ClientSideNetworkHandler -> setLevel", pLocalPlayer);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, AddPlayerPacket* pAddPlayerPkt)
{
puts_ignorable("AddPlayerPacket");
if (!m_pLevel) return;
Player* pPlayer = new Player(m_pLevel);
pPlayer->m_EntityID = pAddPlayerPkt->m_id;
m_pLevel->addEntity(pPlayer);
pPlayer->moveTo(
pAddPlayerPkt->m_x,
pAddPlayerPkt->m_y,
pAddPlayerPkt->m_z,
pPlayer->m_yaw,
pPlayer->m_pitch);
pPlayer->m_name = pAddPlayerPkt->m_name;
pPlayer->m_guid = pAddPlayerPkt->m_guid;
pPlayer->m_pInventory->prepareCreativeInventory();
m_pMinecraft->m_gui.addMessage(pPlayer->m_name + " joined the game");
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, RemoveEntityPacket* pRemoveEntityPkt)
{
if (!m_pLevel) return;
Entity* pEnt = m_pLevel->getEntity(pRemoveEntityPkt->m_id);
#if defined(ORIGINAL_CODE) || UINTPTR_MAX == UINT32_MAX
// @NOTE: On x64 systems, this won't print the right things.
printf_ignorable("RemoveEntityPacket %d %d", pEnt, m_pMinecraft->m_pLocalPlayer);
#else
printf_ignorable("RemoveEntityPacket %p %p", pEnt, m_pMinecraft->m_pLocalPlayer);
#endif
if (pEnt)
m_pLevel->removeEntity(pEnt);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, MovePlayerPacket* packet)
{
if (!m_pLevel) return;
Entity* pEntity = m_pLevel->getEntity(packet->m_id);
if (!pEntity)
{
LOG_E("No player with id %d", packet->m_id);
return;
}
pEntity->lerpTo(packet->m_x, packet->m_y, packet->m_z, packet->m_yaw, packet->m_pitch, 3);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlaceBlockPacket* pPlaceBlockPkt)
{
puts_ignorable("PlaceBlockPacket");
Player* pPlayer = (Player*)m_pLevel->getEntity(pPlaceBlockPkt->m_playerID);
if (!pPlayer)
{
LOG_E("No player with id %d", pPlaceBlockPkt->m_playerID);
return;
}
pPlayer->swing();
// @BUG: Not buffering the update.
if (!areAllChunksLoaded())
return;
int x = pPlaceBlockPkt->m_x;
int y = pPlaceBlockPkt->m_y;
int z = pPlaceBlockPkt->m_z;
int tile = pPlaceBlockPkt->m_tile;
int face = pPlaceBlockPkt->m_face;
if (!m_pLevel->mayPlace(tile, x, y, z, true))
return;
Tile* pTile = Tile::tiles[tile];
if (!m_pLevel->setTile(x, y, z, tile))
return;
Tile::tiles[tile]->setPlacedOnFace(m_pLevel, x, y, z, face);
Tile::tiles[tile]->setPlacedBy(m_pLevel, x, y, z, pPlayer);
const Tile::SoundType* pSound = pTile->m_pSound;
m_pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->field_18), 0.8f * pSound->field_1C);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, RemoveBlockPacket* pRemoveBlockPkt)
{
puts_ignorable("RemoveBlockPacket");
Player* pPlayer = (Player*)m_pLevel->getEntity(pRemoveBlockPkt->m_playerID);
if (!pPlayer)
{
LOG_E("No player with id %d", pRemoveBlockPkt->m_playerID);
return;
}
pPlayer->swing();
// @BUG: Not buffering the update.
if (!areAllChunksLoaded())
return;
int x = pRemoveBlockPkt->m_x;
int y = pRemoveBlockPkt->m_y;
int z = pRemoveBlockPkt->m_z;
Tile* pTile = Tile::tiles[m_pLevel->getTile(x, y, z)];
int data = m_pLevel->getData(x, y, z);
bool setTileResult = m_pLevel->setTile(x, y, z, TILE_AIR);
if (pTile && setTileResult)
{
const Tile::SoundType* pSound = pTile->m_pSound;
m_pLevel->playSound(float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->field_18), 0.8f * pSound->field_1C);
pTile->destroy(m_pLevel, x, y, z, data);
}
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, UpdateBlockPacket* pkt)
{
if (!areAllChunksLoaded())
{
m_bufferedBlockUpdates.push_back(SBufferedBlockUpdate(pkt->m_x, pkt->m_y, pkt->m_z, pkt->m_tile, pkt->m_data));
return;
}
m_pLevel->setTileAndData(pkt->m_x, pkt->m_y, pkt->m_z, pkt->m_tile, pkt->m_data);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, ChunkDataPacket* pChunkDataPkt)
{
if (!m_pLevel)
{
LOG_E("Level @ handle ChunkDataPacket is 0");
return;
}
LevelChunk* pChunk = m_pLevel->getChunkSource()->create(pChunkDataPkt->m_x, pChunkDataPkt->m_z);
if (!pChunk || pChunk->isEmpty())
{
LOG_E("Failed to find write-able chunk");
// @BUG: Not trying again.
return;
}
int x16 = 16 * pChunkDataPkt->m_x;
int z16 = 16 * pChunkDataPkt->m_z;
bool updated = false;
int minY = 128, maxY = 0;
int minX = 16, minZ = 16;
int maxX = 0, maxZ = 0;
for (int k = 0; k < 256; k++)
{
uint8_t updMap;
pChunkDataPkt->m_data.Read(updMap);
if (!updMap)
continue;
for (int j = 0; j < 8; j++)
{
if ((updMap >> j) & 1)
{
int yPos = j * 16;
TileID tiles[16];
uint8_t datas[16 / 2];
pChunkDataPkt->m_data.Read((char*)tiles, 16 * sizeof(TileID));
pChunkDataPkt->m_data.Read((char*)datas, 16 / 2);
for (int i = 0; i < 16; i++)
{
m_pLevel->setTileNoUpdate(x16 + (k & 0xF), yPos + i, z16 + (k >> 4), tiles[i]);
}
int idx = ((k & 0xF) << 11) | ((k >> 4) << 7) + yPos;
memcpy(&pChunk->m_tileData[idx >> 1], datas, sizeof datas);
}
int ymin = 16 * (1 << j);
if (minY >= ymin)
minY = ymin;
if (maxY < ymin + 15)
maxY = ymin + 15;
}
if (minX >= (k & 0xF))
minX = k & 0xF;
if (minZ >= (k >> 4))
minZ = k >> 4;
if (maxX <= (k & 0xF))
maxX = k & 0xF;
if (maxZ <= (k >> 4))
maxZ = k >> 4;
updated = true;
}
if (updated)
m_pLevel->setTilesDirty(minX + x16, minY, minZ, maxX + x16, maxY, maxZ + z16);
pChunk->m_bUnsaved = true;
if (m_serverProtocolVersion < 2)
{
if (areAllChunksLoaded())
flushAllBufferedUpdates();
else
requestNextChunk();
}
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlayerEquipmentPacket* pPlayerEquipmentPkt)
{
Player* pPlayer = (Player*)m_pLevel->getEntity(pPlayerEquipmentPkt->m_playerID);
if (!pPlayer)
return;
if (!Item::items[pPlayerEquipmentPkt->m_itemID])
{
LOG_W("That item %d doesn't actually exist!", pPlayerEquipmentPkt->m_itemID);
return;
}
if (pPlayer->m_guid == m_pServerPeer->GetMyGUID())
{
LOG_W("Attempted to modify local player's inventory");
return;
}
pPlayer->m_pInventory->selectItemById(pPlayerEquipmentPkt->m_itemID);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, LevelDataPacket* packet)
{
const int uncompMagic = 12847812, compMagic = 58712758, chunkSepMagic = 284787658;
RakNet::BitStream* bs = &packet->m_data, bs2;
int magicNum = 0;
bs->Read(magicNum);
if (magicNum != compMagic && magicNum != uncompMagic)
{
LOG_E("Invalid level data packet with magic %d", magicNum);
return;
}
// If our data is compressed
if (magicNum == compMagic)
{
// Decompress it before we handle it.
int uncompSize = 0, compSize = 0;
bs->Read(uncompSize);
bs->Read(compSize);
LOG_I("Decompressing level data. Compressed: %d bytes, uncompressed: %d bytes", compSize, uncompSize);
// Read the compressed data.
uint8_t* pCompData = new uint8_t[compSize];
bs->Read((char*)pCompData, compSize);
// Inflate it.
uint8_t* pUncompData = ZlibInflateToMemory(pCompData, compSize, uncompSize);
SAFE_DELETE_ARRAY(pCompData);
// If we couldn't, bail
if (!pUncompData)
{
LOG_E("Failed to decompress level data!");
return;
}
// Do some small scale hacks to get bs2 contain the uncompressed data.
bs2.Reset();
bs2.Write((const char*)pUncompData, uncompSize);
bs2.ResetReadPointer();
bs = &bs2;
// Delete the uncompressed data, since we've written it to our bitstream.
SAFE_DELETE_ARRAY(pUncompData);
bs->Read(magicNum);
}
int chunksX = 0, chunksZ = 0;
bs->Read(chunksX);
bs->Read(chunksZ);
if (chunksX != C_MAX_CHUNKS_X || chunksZ != C_MAX_CHUNKS_Z)
{
LOG_E("We don't yet support a level of size %d x %d chunks. Some chunks may disappear or be regenerated.", chunksX, chunksZ);
}
for (int x = 0; x < chunksX; x++)
{
for (int z = 0; z < chunksZ; z++)
{
bs->Read(magicNum);
if (magicNum != chunkSepMagic)
{
_FAIL_BECAUSE_INVALID:
LOG_E("Aborting because level data is invalid, reading chunk %d, %d. Magic: %d", x, z, magicNum);
return;
}
uint8_t ptype = 0;
// read the data size. This'll let us know how much to read.
int dataSize = 0;
bs->Read(dataSize);
LevelChunk* pChunk = m_pLevel->getChunk(x, z);
if (!pChunk || pChunk->isEmpty())
LOG_E("No chunk at %d, %d", x, z);
// continue reading anyway to skip over the offending chunk
// Seems like reading a bitstream from another bitstream reads all the way
// to the end, so we need to duplicate in this fashion.
RakNet::BitStream bs2;
bs2.Write(*bs, 8 * dataSize);
// Ensure the packet type is correct.
bs2.Read(ptype);
if (ptype != PACKET_CHUNK_DATA)
goto _FAIL_BECAUSE_INVALID;
// Read the chunk data packet itself, and handle it.
ChunkDataPacket cdp(x, z, pChunk);
cdp.read(&bs2);
if (pChunk)
handle(guid, &cdp);
// Handle lighting immediately, to ensure it doesn't get out of control.
while (m_pLevel->updateLights());
}
}
// All chunks are loaded. Also flush all the updates we've buffered.
m_chunksRequested = 256;
flushAllBufferedUpdates();
}
bool ClientSideNetworkHandler::areAllChunksLoaded()
{
return m_chunksRequested > 255;
}
void ClientSideNetworkHandler::requestNextChunk()
{
if (areAllChunksLoaded())
return;
// @BUG: The return value of areAllChunksLoaded() is actually true even before the
// 256th chunk is loaded.
if (m_serverProtocolVersion < 2)
{
m_pRakNetInstance->send(new RequestChunkPacket(m_chunksRequested % 16, m_chunksRequested / 16));
m_chunksRequested++;
}
else
{
m_pRakNetInstance->send(new RequestChunkPacket(-9999, -9999));
}
}
void ClientSideNetworkHandler::flushAllBufferedUpdates()
{
for (int i = 0; i < int(m_bufferedBlockUpdates.size()); i++)
{
SBufferedBlockUpdate& u = m_bufferedBlockUpdates[i];
m_pLevel->setTileAndData(u.x, u.y, u.z, u.tile, u.data);
}
}

View File

@@ -0,0 +1,64 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#pragma once
#include "network/NetEventCallback.hpp"
#include "client/app/Minecraft.hpp"
#include "network/RakNetInstance.hpp"
struct SBufferedBlockUpdate
{
int x, z;
uint8_t y;
uint8_t tile, data;
SBufferedBlockUpdate(int x, int y, int z, TileID tile, int data) :
x(x), y(uint8_t(y)), z(z), tile(uint8_t(tile)), data(uint8_t(data))
{}
};
// @TODO: Rename to ClientNetworkHandler?
class ClientSideNetworkHandler : public NetEventCallback
{
public:
ClientSideNetworkHandler(Minecraft*, RakNetInstance*);
void levelGenerated(Level*) override;
void onConnect(const RakNet::RakNetGUID&) override;
void onDisconnect(const RakNet::RakNetGUID&) override;
void onUnableToConnect() override;
void handle(const RakNet::RakNetGUID&, MessagePacket*) override;
void handle(const RakNet::RakNetGUID&, StartGamePacket*) override;
void handle(const RakNet::RakNetGUID&, AddPlayerPacket*) override;
void handle(const RakNet::RakNetGUID&, RemoveEntityPacket*) override;
void handle(const RakNet::RakNetGUID&, MovePlayerPacket*) override;
void handle(const RakNet::RakNetGUID&, PlaceBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, RemoveBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, UpdateBlockPacket*) override;
void handle(const RakNet::RakNetGUID&, ChunkDataPacket*) override;
void handle(const RakNet::RakNetGUID&, PlayerEquipmentPacket*) override;
void handle(const RakNet::RakNetGUID&, LevelDataPacket*) override;
bool areAllChunksLoaded();
void requestNextChunk();
void flushAllBufferedUpdates(); // inlined
private:
Minecraft* m_pMinecraft;
Level* m_pLevel;
RakNetInstance* m_pRakNetInstance;
RakNet::RakPeerInterface* m_pServerPeer;
int m_field_14;
RakNet::RakNetGUID m_serverGUID;
int m_field_24;
std::vector<SBufferedBlockUpdate> m_bufferedBlockUpdates;
int m_chunksRequested;
int m_serverProtocolVersion;
};

View File

@@ -0,0 +1,359 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include <fstream>
#include "Options.hpp"
#include "common/Util.hpp"
#include "compat/KeyCodes.hpp"
#include "client/app/Minecraft.hpp"
Options::Option
Options::Option::MUSIC (0, "options.music", true, false),
Options::Option::SOUND (1, "options.sound", true, false),
Options::Option::INVERT_MOUSE (2, "options.invertMouse", false, true),
Options::Option::SENSITIVITY (3, "options.sensitivity", true, false),
Options::Option::RENDER_DISTANCE (4, "options.renderDistance", false, false),
Options::Option::VIEW_BOBBING (5, "options.viewBobbing", false, true),
Options::Option::ANAGLYPH (6, "options.anaglyph", false, true),
Options::Option::LIMIT_FRAMERATE (7, "options.limitFramerate", false, true),
Options::Option::DIFFICULTY (8, "options.difficulty", false, false),
Options::Option::GRAPHICS (9, "options.graphics", false, false),
Options::Option::AMBIENT_OCCLUSION(10, "options.ao", false, true),
Options::Option::GUI_SCALE (11, "options.guiScale", false, false);
void Options::_initDefaultValues()
{
field_238 = 2;
field_244 = 1.0f;
m_bDontRenderGui = false;
field_248 = 1.0f;
m_bThirdPerson = false;
field_0 = 1.0f;
field_23E = 0;
m_fMasterVolume = 1.0f;
m_bFlyCheat = false;
field_241 = 0;
field_8 = 0.5f;
field_24C = 0;
m_bInvertMouse = false;
m_bAnaglyphs = false;
field_16 = 0;
m_bAmbientOcclusion = Minecraft::useAmbientOcclusion;
field_240 = 1;
m_iViewDistance = 2;
m_bViewBobbing = 1;
m_bAutoJump = true;
m_bFancyGraphics = true;
field_19 = 1;
field_1C = "Default";
m_playerName = "Steve";
m_bServerVisibleDefault = true;
m_bDebugText = false;
// Win32 key codes are being used by default
#define KM(idx, name, code) m_keyMappings[idx] = KeyMapping(name, code)
KM(KM_FORWARD, "key.forward", 'W');
KM(KM_LEFT, "key.left", 'A');
KM(KM_BACKWARD, "key.back", 'S');
KM(KM_RIGHT, "key.right", 'D');
KM(KM_JUMP, "key.jump", ' ');
KM(KM_INVENTORY, "key.inventory", 'E');
KM(KM_DROP, "key.drop", 'Q');
KM(KM_CHAT, "key.chat", 'T');
KM(KM_FOG, "key.fog", 'F');
KM(KM_SNEAK, "key.sneak", 0x10); // VK_SHIFT. In original, it's 10 (misspelling?)
KM(KM_DESTROY, "key.destroy", 'K'); // was 'X'
KM(KM_PLACE, "key.place", 'L'); // was 'C'
KM(KM_MENU_NEXT, "key.menu.next", 0x28); // VK_DOWN
KM(KM_MENU_PREVIOUS,"key.menu.previous", 0x26); // VK_UP
KM(KM_MENU_OK, "key.menu.ok", 0x0D); // VK_RETURN
KM(KM_MENU_CANCEL, "key.menu.cancel", 0x1B); // VK_ESCAPE, was 0x08 = VK_BACK
KM(KM_SLOT_1, "key.slot.1", '1');
KM(KM_SLOT_2, "key.slot.2", '2');
KM(KM_SLOT_3, "key.slot.3", '3');
KM(KM_SLOT_4, "key.slot.4", '4');
KM(KM_SLOT_5, "key.slot.5", '5');
KM(KM_SLOT_6, "key.slot.6", '6');
KM(KM_SLOT_7, "key.slot.7", '7');
KM(KM_SLOT_8, "key.slot.8", '8');
KM(KM_SLOT_9, "key.slot.9", '9');
KM(KM_SLOT_L, "key.slot.left", 'Y');
KM(KM_SLOT_R, "key.slot.right", 'U');
KM(KM_TOGGLEGUI, "key.fn.gui", 0x70); // VK_F1
KM(KM_SCREENSHOT, "key.fn.screenshot", 0x71); // VK_F2
KM(KM_TOGGLEDEBUG, "key.fn.debug", 0x72); // VK_F3
KM(KM_TOGGLEAO, "key.fn.ao", 0x73); // VK_F4
KM(KM_TOGGLE3RD, "key.fn.3rd", 0x74); // VK_F5
KM(KM_FLY_UP, "key.fly.up", 'X');
KM(KM_FLY_DOWN, "key.fly.down", 'C');
KM(KM_CHAT_CMD, "key.chat.cmd", 0xBF); // VK_OEM_2
#undef KM
#ifdef ORIGINAL_CODE
m_iViewDistance = 2;
m_bThirdPerson = 0;
field_19 = 0;
#endif
m_bFancyGraphics = 1;
#define KM(idx,code) m_keyMappings[idx].value = code
#ifdef USE_SDL
KM(KM_FORWARD, SDLVK_w);
KM(KM_LEFT, SDLVK_a);
KM(KM_BACKWARD, SDLVK_s);
KM(KM_RIGHT, SDLVK_d);
KM(KM_JUMP, SDLVK_SPACE);
KM(KM_DESTROY, SDLVK_x);
KM(KM_PLACE, SDLVK_c);
KM(KM_MENU_NEXT, SDLVK_DOWN);
KM(KM_MENU_PREVIOUS, SDLVK_UP);
KM(KM_MENU_OK, SDLVK_RETURN);
KM(KM_MENU_CANCEL, SDLVK_ESCAPE);
KM(KM_DROP, SDLVK_q);
KM(KM_CHAT, SDLVK_t);
KM(KM_FOG, SDLVK_f);
KM(KM_INVENTORY, SDLVK_e);
KM(KM_SNEAK, SDLVK_LSHIFT);
KM(KM_SLOT_1, SDLVK_1);
KM(KM_SLOT_2, SDLVK_2);
KM(KM_SLOT_3, SDLVK_3);
KM(KM_SLOT_4, SDLVK_4);
KM(KM_SLOT_5, SDLVK_5);
KM(KM_SLOT_6, SDLVK_6);
KM(KM_SLOT_7, SDLVK_7);
KM(KM_SLOT_8, SDLVK_8);
KM(KM_SLOT_9, SDLVK_9);
KM(KM_TOGGLEGUI, SDLVK_F1);
KM(KM_SCREENSHOT, SDLVK_F2);
KM(KM_TOGGLEDEBUG, SDLVK_F3);
KM(KM_TOGGLEAO, SDLVK_F4);
KM(KM_TOGGLE3RD, SDLVK_F5);
KM(KM_SLOT_L, SDLVK_y);
KM(KM_SLOT_R, SDLVK_u);
KM(KM_FLY_UP, SDLVK_c);
KM(KM_FLY_DOWN, SDLVK_x);
KM(KM_CHAT_CMD, SDLVK_SLASH);
#endif
#ifdef PLATFORM_ANDROID
// -- Original xperia play controls
//KM(KM_FORWARD, AKEYCODE_DPAD_UP);
//KM(KM_LEFT, AKEYCODE_DPAD_LEFT);
//KM(KM_BACKWARD, AKEYCODE_DPAD_DOWN);
//KM(KM_RIGHT, AKEYCODE_DPAD_RIGHT);
//KM(KM_JUMP, AKEYCODE_DPAD_CENTER);
//KM(KM_DESTROY, AKEYCODE_BUTTON_L1);
//KM(KM_PLACE, AKEYCODE_BUTTON_R1);
//KM(KM_MENU_NEXT, AKEYCODE_DPAD_DOWN);
//KM(KM_MENU_PREVIOUS, AKEYCODE_DPAD_UP);
//KM(KM_MENU_OK, AKEYCODE_DPAD_CENTER);
//KM(KM_MENU_CANCEL, AKEYCODE_BACK);
//custom
//KM(KM_INVENTORY, AKEYCODE_BUTTON_Y);
//KM(KM_SLOT_R, AKEYCODE_BACK);
//KM(KM_SLOT_L, AKEYCODE_BUTTON_X);
//KM(KM_FLY_UP, AKEYCODE_BUTTON_R1);
//KM(KM_FLY_DOWN, AKEYCODE_BUTTON_L1);
KM(KM_FORWARD, AKEYCODE_W);
KM(KM_LEFT, AKEYCODE_A);
KM(KM_BACKWARD, AKEYCODE_S);
KM(KM_RIGHT, AKEYCODE_D);
KM(KM_JUMP, AKEYCODE_SPACE);
KM(KM_DESTROY, AKEYCODE_X);
KM(KM_PLACE, AKEYCODE_C);
KM(KM_MENU_NEXT, AKEYCODE_DPAD_DOWN);
KM(KM_MENU_PREVIOUS, AKEYCODE_DPAD_UP);
KM(KM_MENU_OK, AKEYCODE_ENTER);
KM(KM_MENU_CANCEL, AKEYCODE_ESCAPE);
// custom
KM(KM_SLOT_L, AKEYCODE_Y);
KM(KM_SLOT_R, AKEYCODE_U);
KM(KM_DROP, AKEYCODE_Q);
KM(KM_CHAT, AKEYCODE_T);
KM(KM_FOG, AKEYCODE_F);
KM(KM_INVENTORY, AKEYCODE_F);
KM(KM_SNEAK, AKEYCODE_SHIFT_LEFT);
KM(KM_SLOT_1, AKEYCODE_1);
KM(KM_SLOT_2, AKEYCODE_2);
KM(KM_SLOT_3, AKEYCODE_3);
KM(KM_SLOT_4, AKEYCODE_4);
KM(KM_SLOT_5, AKEYCODE_5);
KM(KM_SLOT_6, AKEYCODE_6);
KM(KM_SLOT_7, AKEYCODE_7);
KM(KM_SLOT_8, AKEYCODE_8);
KM(KM_SLOT_9, AKEYCODE_9);
KM(KM_TOGGLEGUI, AKEYCODE_F1);
KM(KM_SCREENSHOT, AKEYCODE_F2);
KM(KM_TOGGLEDEBUG, AKEYCODE_F3);
KM(KM_TOGGLEAO, AKEYCODE_F4);
KM(KM_TOGGLE3RD, AKEYCODE_F5);
KM(KM_FLY_UP, AKEYCODE_C);
KM(KM_FLY_DOWN, AKEYCODE_X);
KM(KM_CHAT_CMD, AKEYCODE_SLASH);
#endif
#undef KM
}
Options::Options()
{
_initDefaultValues();
}
Options::Options(const std::string& folderPath)
{
m_filePath = folderPath + "/options.txt";
_initDefaultValues();
_load();
}
std::string getMessage(const Options::Option& option)
{
return "Options::getMessage - Not implemented";
}
void Options::_load()
{
std::vector<std::string> strings = readPropertiesFromFile(m_filePath);
for (int i = 0; i < strings.size(); i += 2)
{
std::string key = strings[i], value = strings[i + 1];
if (key == "mp_username")
m_playerName = value;
else if (key == "ctrl_invertmouse")
m_bInvertMouse = readBool(value);
else if (key == "ctrl_autojump")
m_bAutoJump = readBool(value);
else if (key == "gfx_fancygraphics")
m_bFancyGraphics = readBool(value);
else if (key == "mp_server_visible_default")
m_bServerVisibleDefault = readBool(value);
else if (key == "gfx_smoothlighting")
Minecraft::useAmbientOcclusion = m_bAmbientOcclusion = readBool(value);
else if (key == "gfx_viewdistance")
m_iViewDistance = readInt(value);
}
}
void Options::save()
{
savePropertiesToFile(m_filePath, getOptionStrings());
}
std::string Options::getMessage(const Options::Option& option)
{
return "Options::getMessage - Not implemented";
}
bool Options::readBool(const std::string& str)
{
std::string trimmed = Util::stringTrim(str);
if (trimmed == "true" || trimmed == "1")
return true;
if (trimmed == "false" || trimmed == "0")
return false;
return false;
}
int Options::readInt(const std::string& str)
{
int f;
if (!sscanf(str.c_str(), "%d", &f))
f = 0;
return f;
}
std::string Options::saveBool(bool b)
{
return b ? "true" : "false";
}
std::string Options::saveInt(int i)
{
std::stringstream ss;
ss << i;
return ss.str();
}
std::vector<std::string> Options::readPropertiesFromFile(const std::string& filePath)
{
std::vector<std::string> o;
const char* const path = filePath.c_str();
LOG_I("Loading options from %s", path);
std::ifstream ifs(path);
if (!ifs.is_open())
{
LOG_W("%s doesn't exist, resetting to defaults", path);
return o;
}
std::string str;
while (true)
{
if (!std::getline(ifs, str, '\n'))
break;
if (str.empty() || str[0] == '#')
continue;
std::stringstream ss;
ss << str;
std::string key, value;
if (std::getline(ss, key, ':') && std::getline(ss, value))
{
o.push_back(key);
o.push_back(value);
}
}
return o;
}
void Options::savePropertiesToFile(const std::string& filePath, std::vector<std::string> properties)
{
assert(properties.size() % 2 == 0);
std::ofstream os;
os.open(filePath.c_str());
if (!os.is_open())
{
LOG_E("Failed to read %s", filePath.c_str());
return;
}
os << "#Config file for Minecraft PE. The # at the start denotes a comment, removing it makes it a command.\n\n";
for (int i = 0; i < properties.size(); i += 2)
os << properties[i] << ':' << properties[i + 1] << '\n';
}
std::vector<std::string> Options::getOptionStrings()
{
std::vector<std::string> vec;
#define SO(optname, value) do { vec.push_back(optname); vec.push_back(value); } while (0)
SO("mp_username", m_playerName);
SO("ctrl_invertmouse", saveBool(m_bInvertMouse));
SO("ctrl_autojump", saveBool(m_bAutoJump));
SO("gfx_fancygraphics", saveBool(m_bFancyGraphics));
SO("mp_server_visible_default", saveBool(m_bServerVisibleDefault));
SO("gfx_smoothlighting", saveBool(m_bAmbientOcclusion));
SO("gfx_viewdistance", saveInt (m_iViewDistance));
return vec;
}

View File

@@ -0,0 +1,153 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#pragma once
#include <stdint.h>
#include <string>
#include <vector>
enum eKeyMappingIndex
{
KM_FORWARD,
KM_LEFT,
KM_BACKWARD,
KM_RIGHT,
KM_JUMP,
KM_INVENTORY,
KM_DROP,
KM_CHAT,
KM_FOG,
KM_SNEAK,
KM_DESTROY,
KM_PLACE,
KM_MENU_NEXT,
KM_MENU_PREVIOUS,
KM_MENU_OK,
KM_MENU_CANCEL, KM_BACK = KM_MENU_CANCEL,
KM_SLOT_1,
KM_SLOT_2,
KM_SLOT_3,
KM_SLOT_4,
KM_SLOT_5,
KM_SLOT_6,
KM_SLOT_7,
KM_SLOT_8,
KM_SLOT_9,
KM_SLOT_L,
KM_SLOT_R,
KM_TOGGLEGUI,
KM_SCREENSHOT,
KM_TOGGLEDEBUG,
KM_TOGGLEAO,
KM_TOGGLE3RD,
KM_FLY_UP,
KM_FLY_DOWN,
KM_CHAT_CMD, // called "Open Chat" in Release 1.8
KM_COUNT,
};
struct KeyMapping
{
std::string key;
int value;
KeyMapping() {}
KeyMapping(const char* keyName, int keyCode) : key(keyName), value(keyCode) {}
};
class Options
{
public:
struct Option;
struct KeyBind;
private:
static bool readBool(const std::string& str);
static int readInt(const std::string& str);
static std::string saveBool(bool b);
static std::string saveInt(int i);
static std::vector<std::string> readPropertiesFromFile(const std::string& filePath);
static void savePropertiesToFile(const std::string& filePath, std::vector<std::string> properties);
private:
void _initDefaultValues();
void _load();
public:
Options();
Options(const std::string& folderPath);
void save();
std::string getMessage(const Options::Option&);
std::vector<std::string> getOptionStrings();
int getKey(eKeyMappingIndex idx)
{
return m_keyMappings[idx].value;
}
bool isKey(eKeyMappingIndex idx, int keyCode)
{
return getKey(idx) == keyCode;
}
private:
std::string m_filePath;
public:
float field_0;
float m_fMasterVolume;
float field_8;
bool m_bInvertMouse;
int m_iViewDistance;
bool m_bViewBobbing;
bool m_bAnaglyphs;
uint8_t field_16;
bool m_bFancyGraphics;
bool m_bAmbientOcclusion;
uint8_t field_19;
std::string field_1C;
KeyMapping m_keyMappings[KM_COUNT];
int field_238;
bool m_bDontRenderGui;
bool m_bThirdPerson;
uint8_t field_23E;
bool m_bFlyCheat;
uint8_t field_240;
uint8_t field_241;
float field_244;
float field_248;
int field_24C;
std::string m_playerName;
bool m_bServerVisibleDefault;
bool m_bAutoJump;
bool m_bDebugText;
public:
struct Option
{
bool field_0;
bool field_1;
std::string str;
int field_1C;
Option(int i, const std::string& str, bool b1, bool b2) : field_0(b1), field_1(b2), str(str), field_1C(i) {}
static Option MUSIC;
static Option SOUND;
static Option INVERT_MOUSE;
static Option SENSITIVITY;
static Option RENDER_DISTANCE;
static Option VIEW_BOBBING;
static Option ANAGLYPH;
static Option LIMIT_FRAMERATE;
static Option DIFFICULTY;
static Option GRAPHICS;
static Option AMBIENT_OCCLUSION;
static Option GUI_SCALE;
};
};

View File

@@ -8,7 +8,7 @@
#pragma once
#include "common/Options.hpp"
#include "client/options/Options.hpp"
class KeyboardInput
{

View File

@@ -9,7 +9,7 @@
#pragma once
#include "ITurnInput.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
class Minecraft;
class MouseTurnInput : public ITurnInput

View File

@@ -9,7 +9,7 @@
#pragma once
#include "Textures.hpp"
#include "common/Options.hpp"
#include "client/options/Options.hpp"
class Font
{

View File

@@ -6,9 +6,9 @@
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "compat/GL.hpp"
#include "thirdparty/GL/GL.hpp"
#include "GameRenderer.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#include "Frustum.hpp"
int t_keepPic;

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "ItemInHandRenderer.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
ItemInHandRenderer::ItemInHandRenderer(Minecraft* pMC) :
m_ItemInstance(0, 1, 0),

View File

@@ -7,7 +7,8 @@
********************************************************************/
#include "LevelRenderer.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#include "renderer/GL/GL.hpp"
#include "world/tile/LeafTile.hpp"
LevelRenderer::LevelRenderer(Minecraft* pMC, Textures* pTexs)

View File

@@ -10,7 +10,7 @@
#include <algorithm>
#include <sstream>
#include "compat/GL.hpp"
#include "thirdparty/GL/GL.hpp"
#include "world/level/LevelListener.hpp"
#include "Textures.hpp"
#include "RenderList.hpp"

View File

@@ -1,9 +1,9 @@
#include "PatchManager.hpp"
#include "AppPlatform.hpp"
#include "client/app/AppPlatform.hpp"
#include "common/Utils.hpp"
#include "world/tile/Tile.hpp"
#include "world/item/Item.hpp"
#include "compat/GL.hpp"
#include "thirdparty/GL/GL.hpp"
#define PM_SEPARATOR ('|')

View File

@@ -8,7 +8,7 @@
#pragma once
#include "compat/GL.hpp"
#include "thirdparty/GL/GL.hpp"
class RenderChunk
{

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "Tesselator.hpp"
#include "compat/GL.hpp"
#include "thirdparty/GL/GL.hpp"
#include "common/Utils.hpp"
#include <cstddef>

View File

@@ -10,7 +10,7 @@
#include <stdint.h>
#include <map>
#include "compat/GL.hpp"
#include "thirdparty/GL/GL.hpp"
#include "RenderChunk.hpp"
#define GET_RED(c) (uint8_t(((c) >> 0) & 0xFF))

View File

@@ -9,9 +9,9 @@
#pragma once
#include <map>
#include "compat/GL.hpp"
#include "common/Options.hpp"
#include "AppPlatform.hpp"
#include "thirdparty/GL/GL.hpp"
#include "client/options/Options.hpp"
#include "client/app/AppPlatform.hpp"
#include "DynamicTexture.hpp"
class DynamicTexture; // in case we are being included from DynamicTexture. We don't store complete references to that

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "TileRenderer.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#include "client/renderer/PatchManager.hpp"
#include "world/tile/FireTile.hpp"
#include "world/tile/LiquidTile.hpp"

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "EntityRenderDispatcher.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#include "../ItemInHandRenderer.hpp"
EntityRenderDispatcher* EntityRenderDispatcher::instance;

View File

@@ -8,7 +8,7 @@
#include "HumanoidMobRenderer.hpp"
#include "EntityRenderDispatcher.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
#include "client/renderer/ItemInHandRenderer.hpp"
#include "client/renderer/TileRenderer.hpp"
#include "world/entity/Player.hpp"

View File

@@ -8,7 +8,7 @@
#include "MobRenderer.hpp"
#include "EntityRenderDispatcher.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
MobRenderer::MobRenderer(Model* pModel, float f)
{

View File

@@ -7,7 +7,7 @@
********************************************************************/
#include "TripodCameraRenderer.hpp"
#include "Minecraft.hpp"
#include "client/app/Minecraft.hpp"
TripodCameraRenderer::TripodCameraRenderer() :
m_tile(),

View File

@@ -9,14 +9,13 @@
#include "SoundEngine.hpp"
#include "SoundDefs.hpp"
SoundEngine::SoundEngine()
SoundEngine::SoundEngine(SoundSystem* soundSystem)
{
field_40 = 0;
field_A1C = 0;
#ifndef ORIGINAL_CODE
m_pOptions = nullptr;
field_A20 = 0;
#endif
m_pSoundSystem = soundSystem;
}
void SoundEngine::init(Options* options)
@@ -67,7 +66,7 @@ void SoundEngine::play(const std::string& name)
SoundDesc sd;
if (m_repository.get(name, sd)) {
m_soundSystem.playAt(sd, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
m_pSoundSystem->playAt(sd, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
}
}
@@ -79,6 +78,6 @@ void SoundEngine::play(const std::string& name, float x, float y, float z, float
SoundDesc sd;
if (m_repository.get(name, sd)) {
m_soundSystem.playAt(sd, x, y, z, volume, pitch);
m_pSoundSystem->playAt(sd, x, y, z, volume, pitch);
}
}

View File

@@ -8,23 +8,21 @@
#pragma once
#include "common/Options.hpp"
#include "client/options/Options.hpp"
#include "common/Random.hpp"
#include "SoundSystem.hpp"
#include "SoundRepository.hpp"
#include "platforms/PlatformDefinitions.hpp"
class SoundEngine
{
public:
SoundEngine();
SoundEngine(SoundSystem* soundSystem);
void init(Options*);
void play(const std::string& name);
void play(const std::string& name, float x, float y, float z, float volume, float pitch);
public:
SOUND_SYSTEM_TYPE m_soundSystem;
SoundSystem* m_pSoundSystem;
Options* m_pOptions;
int field_40;
Random m_random;

View File

@@ -8,6 +8,10 @@
#include "SoundSystem.hpp"
SoundSystem::~SoundSystem()
{
}
bool SoundSystem::isAvailable()
{
return false;

View File

@@ -14,6 +14,8 @@
class SoundSystem
{
public:
virtual ~SoundSystem();
virtual bool isAvailable();
virtual void setListenerPos(float x, float y, float z);
virtual void setListenerAngle(float yaw, float pitch);