* Initial commit.

:)
This commit is contained in:
iProgramInCpp
2023-07-30 22:22:02 +03:00
commit 9642818a88
613 changed files with 151754 additions and 0 deletions

61
source/App/App.cpp Normal file
View File

@@ -0,0 +1,61 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
App.cpp
The following code is licensed under the following license:
< no license yet :( >
********************************************************************/
#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()
{
}

40
source/App/App.hpp Normal file
View File

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

122
source/App/AppPlatform.cpp Normal file
View File

@@ -0,0 +1,122 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
AppPlatform.cpp
The following code is licensed under the following license:
< no license yet :( >
********************************************************************/
#include "AppPlatform.hpp"
#include "Utils.hpp"
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 {};
}
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);
}
std::vector<std::string> AppPlatform::getOptionStrings()
{
return {};
}
void AppPlatform::recenterMouse()
{
}
void AppPlatform::setMouseGrabbed(bool b)
{
}
void AppPlatform::getMouseDiff(int& x, int& y)
{
x = y = 0;
}
void AppPlatform::clearDiff()
{
}
bool AppPlatform::shiftPressed()
{
return false;
}

View File

@@ -0,0 +1,60 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
AppPlatform.hpp
The following code is licensed under the following license:
< no license yet :( >
********************************************************************/
#pragma once
#include <string>
#include <vector>
#include "Texture.hpp"
class AppPlatform
{
public:
enum eDialogType
{
DLG_CREATE_WORLD = 1,
DLG_CHAT,
DLG_OPTIONS,
DLG_RENAME_MP_WORLD,
};
public:
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);
virtual std::vector<std::string> getOptionStrings();
#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();
// Also add this to allow proper text input within the game.
virtual bool shiftPressed();
#endif
private:
virtual void _tick();
};

View File

@@ -0,0 +1,244 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
AppPlatform_windows.hpp
The following code is licensed under the following license:
< no license yet :( >
********************************************************************/
#include "AppPlatform_windows.hpp"
#include "Mouse.hpp"
#include "thirdparty/stb_image.h"
#include "thirdparty/stb_image_write.h"
extern LPCTSTR g_GameTitle;
void AppPlatform_windows::initConsts()
{
// just assume an 854x480 window for now:
m_ScreenWidth = C_DEFAULT_SCREEN_WIDTH;
m_ScreenHeight = C_DEFAULT_SCREEN_HEIGHT;
}
int AppPlatform_windows::checkLicense()
{
// we own the game!!
return 1;
}
void AppPlatform_windows::buyGame()
{
MessageBox(GetHWND(), TEXT("Buying the game!"), g_GameTitle, MB_OK | MB_ICONINFORMATION);
}
void AppPlatform_windows::saveScreenshot(const std::string& fileName, int width, int height)
{
int npixels = width * height;
uint32_t* pixels = new uint32_t[npixels];
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
stbi_flip_vertically_on_write(true);
stbi_write_png(fileName.c_str(), width, height, 4, pixels, width * 4);
delete[] pixels;
}
int AppPlatform_windows::getScreenWidth() const
{
return m_ScreenWidth;
}
int AppPlatform_windows::getScreenHeight() const
{
return m_ScreenHeight;
}
std::vector<std::string> AppPlatform_windows::getUserInput()
{
return m_UserInput;
}
int AppPlatform_windows::getUserInputStatus()
{
return m_UserInputStatus;
}
void AppPlatform_windows::createUserInput()
{
m_UserInput.clear();
m_UserInputStatus = -1;
}
void AppPlatform_windows::showDialog(eDialogType type)
{
// TODO
}
std::string AppPlatform_windows::getDateString(int time)
{
time_t tt = time;
struct tm t;
// using the _s variant. For a different platform there's gmtime_r. This is not directly portable however.
gmtime_s(&t, &tt);
//format it with strftime
char buf[2048];
strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
//strftime(buf, sizeof buf, "%a %b %d %H:%M:%S %Z %Y", &t);
return std::string(buf);
}
Texture AppPlatform_windows::loadTexture(const std::string& str, bool b)
{
std::string realPath = str;
if (realPath.size() && realPath[0] == '/')
// trim it off
realPath = realPath.substr(1);
realPath = "assets/" + realPath;
FILE* f = fopen(realPath.c_str(), "rb");
if (!f)
{
LogMsg("File %s couldn't be opened", realPath.c_str());
return Texture(0, 0, nullptr, 1, 0);
}
int width = 0, height = 0, channels = 0;
stbi_uc* img = stbi_load_from_file(f, &width, &height, &channels, STBI_rgb_alpha);
if (!img)
{
LogMsg("File %s couldn't be loaded via stb_image", realPath.c_str());
fclose(f);
return Texture(0, 0, nullptr, 1, 0);
}
fclose(f);
return Texture(width, height, (uint32_t*)img, 1, 0);
}
std::vector<std::string> AppPlatform_windows::getOptionStrings()
{
std::vector<std::string> o;
o.push_back("mp_username");
o.push_back("iProgramInCpp");
return o;
}
void AppPlatform_windows::setScreenSize(int width, int height)
{
m_ScreenWidth = width;
m_ScreenHeight = height;
}
void AppPlatform_windows::recenterMouse()
{
// only recenter the mouse if it's grabbed
if (!m_bGrabbedMouse)
return;
// If we aren't the foreground window, return
if (GetForegroundWindow() != GetHWND())
{
m_bWasUnfocused = true;
return;
}
POINT oldPos{ 0, 0 };
GetCursorPos(&oldPos);
RECT rect;
GetClientRect(GetHWND(), &rect);
POINT offs { m_ScreenWidth / 2, m_ScreenHeight / 2 };
ClientToScreen(GetHWND(), &offs);
SetCursorPos(offs.x, offs.y);
// Note. The only reason we do it this way instead of
// using the Mouse class is because, after SetCursorPos,
// we'll get an event on our window telling us "hey, the
// user has moved their cursor back to the center! Move
// the camera back as well", causing a camera that just
// refuses to move
// If we were unfocused last frame, ignore the diff data we have.
if (!m_bWasUnfocused)
{
m_MouseDiffX -= offs.x - oldPos.x;
m_MouseDiffY -= offs.y - oldPos.y;
}
m_bWasUnfocused = false;
}
void AppPlatform_windows::setMouseGrabbed(bool b)
{
// only if stuff has changed do we update
if (m_bGrabbedMouse == b)
return;
m_bGrabbedMouse = b;
if (!b)
{
//show the cursor
ShowCursor(TRUE);
//unconfine it
ClipCursor(NULL);
clearDiff();
}
else
{
//hide the cursor
ShowCursor(FALSE);
//confine it to our client area
RECT rect;
GetClientRect(GetHWND(), &rect);
POINT offs{ 0, 0 };
ClientToScreen(GetHWND(), &offs);
rect.left += offs.x;
rect.top += offs.y;
rect.right += offs.x;
rect.bottom += offs.y;
ClipCursor(&rect);
// set the cursor pos to the middle of the screen
recenterMouse();
clearDiff();
}
}
void AppPlatform_windows::getMouseDiff(int& x, int& y)
{
x = m_MouseDiffX;
y = m_MouseDiffY;
}
void AppPlatform_windows::clearDiff()
{
m_MouseDiffX = m_MouseDiffY = 0;
}
bool AppPlatform_windows::shiftPressed()
{
return m_bShiftPressed;
}
void AppPlatform_windows::setShiftPressed(bool b)
{
m_bShiftPressed = b;
}

View File

@@ -0,0 +1,67 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
AppPlatform_windows.hpp
The following code is licensed under the following license:
< no license yet :( >
********************************************************************/
#pragma once
#include "compat/GL.hpp"
#include <ctime>
#include "Utils.hpp"
#include "AppPlatform.hpp"
#ifdef ORIGINAL_CODE
#error "This isn't original code. You probably shouldn't try to compile this"
#endif
// note: probably won't add AppPlatform_android until it's time
// to build an Android app
class AppPlatform_windows : public AppPlatform
{
public:
void initConsts();
void buyGame() override;
void saveScreenshot(const std::string& fileName, int width, int height) override;
int checkLicense() override;
void createUserInput() override;
std::vector<std::string> getUserInput() override;
int getUserInputStatus() override;
int getScreenWidth() const override;
int getScreenHeight() const override;
void showDialog(eDialogType) override;
std::string getDateString(int time) override;
Texture loadTexture(const std::string& str, bool b) override;
std::vector<std::string> getOptionStrings() override;
// Also add these to allow proper turning within the game.
void recenterMouse() override;
void setMouseGrabbed(bool b) override;
void getMouseDiff(int& x, int& y) override;
void clearDiff() override;
// Also add these to allow proper text input within the game.
bool shiftPressed() override;
void setShiftPressed(bool b);
void setScreenSize(int width, int height);
private:
int m_ScreenWidth;
int m_ScreenHeight;
std::vector<std::string> m_UserInput;
int m_UserInputStatus = -1;
bool m_bGrabbedMouse = false;
bool m_bWasUnfocused = false;
bool m_bShiftPressed = false;
int m_MouseDiffX = 0, m_MouseDiffY = 0;
};

843
source/App/Minecraft.cpp Normal file
View File

@@ -0,0 +1,843 @@
#include "Minecraft.hpp"
#include "PauseScreen.hpp"
#include "StartMenuScreen.hpp"
#include "RenameMPLevelScreen.hpp"
#include "ServerSideNetworkHandler.hpp"
#include "ClientSideNetworkHandler.hpp"
#ifndef ORIGINAL_CODE
#include "MouseTurnInput.hpp"
#else
#include "ControllerTurnInput.hpp"
#endif
// note: Nothing changes these, so it'll think we're always running at 854x480 even if not
int Minecraft::width = C_DEFAULT_SCREEN_WIDTH;
int Minecraft::height = C_DEFAULT_SCREEN_HEIGHT;
bool Minecraft::useAmbientOcclusion = false;
int Minecraft::customDebugId = 0;
//@HUH: For the demo, this is defined as TRUE.
//@HUH: deadmau5 had camera cheats? That's interesting.
const bool Minecraft::DEADMAU5_CAMERA_CHEATS = true;
const char* Minecraft::progressMessages[] =
{
"Locating server",
"Building terrain",
"Preparing",
"Saving chunks",
};
Minecraft::Minecraft() : m_gui(this)
{
#ifndef ORIGINAL_CODE
m_pTurnInput = new MouseTurnInput(this);
#else
m_pTurnInput = new ControllerTurnInput;
#endif
m_pRakNetInstance = new RakNetInstance;
m_pSoundEngine = new SoundEngine;
m_pSoundEngine->init(&m_options);
}
int Minecraft::getLicenseId()
{
if (m_licenseID < 0)
m_licenseID = m_pPlatform->checkLicense();
return m_licenseID;
}
void Minecraft::releaseMouse()
{
if (!m_bGrabbedMouse)
return;
if (m_pLocalPlayer)
m_pLocalPlayer->m_pKeyboardInput->releaseAllKeys();
m_bGrabbedMouse = false;
platform()->setMouseGrabbed(false);
}
void Minecraft::grabMouse()
{
if (m_bGrabbedMouse)
return;
m_bGrabbedMouse = true;
field_D20 = 0.0f;
field_D24 = 0.0f;
setScreen(nullptr);
platform()->setMouseGrabbed(true);
}
void Minecraft::setScreen(Screen* pScreen)
{
if (field_DB0)
{
field_DB1 = 1;
m_pScreen = pScreen; //@BUG: potential memory leak?
}
else if (!pScreen || !pScreen->isErrorScreen())
{
if (field_D14)
{
field_D14->removed();
delete field_D14;
}
field_D14 = pScreen;
if (pScreen)
{
releaseMouse();
pScreen->init(this, int(width * Gui::InvGuiScale), int(height * Gui::InvGuiScale));
}
else
{
grabMouse();
}
}
//@BUG: memory leak?
#ifndef ORIGINAL_CODE
else
{
// @NOTE: Added this to not leak screens. A good idea unless you use the screen instance after calling setScreen()
delete pScreen;
}
#endif
}
void Minecraft::onGraphicsReset()
{
m_pTextures->clear();
m_pFont->onGraphicsReset();
if (m_pLevelRenderer)
m_pLevelRenderer->onGraphicsReset();
if (m_pGameRenderer)
m_pGameRenderer->onGraphicsReset();
EntityRenderDispatcher::getInstance()->onGraphicsReset();
}
void Minecraft::reloadOptions()
{
m_options.update(platform()->getOptionStrings());
}
bool Minecraft::isLevelGenerated()
{
if (m_pLevel)
return !m_bPreparingLevel;
return false;
}
bool Minecraft::isOnline()
{
return m_pNetEventCallback != nullptr;
}
bool Minecraft::isOnlineClient()
{
if (!m_pLevel)
return false;
return m_pLevel->field_11;
}
void Minecraft::handleMouseDown(int type, bool b)
{
if (!m_pGameMode->field_8 && (type != 1 || this->field_DA4 <= 0))
{
if (b && type == 1 && m_hitResult.m_hitType == HitResult::AABB && !m_hitResult.m_bUnk24)
{
m_pGameMode->continueDestroyBlock(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ, m_hitResult.m_hitSide);
m_pParticleEngine->crack(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ, m_hitResult.m_hitSide);
}
else
{
m_pGameMode->stopDestroyBlock();
}
}
}
void Minecraft::handleMouseClick(int type)
{
int a;
HitResult& hr = m_hitResult;
// @TODO: fix goto hell
if (type == 1)
{
if (field_DA4 > 0)
return;
m_pLocalPlayer->swing();
if (m_hitResult.m_hitType != HitResult::NONE)
goto label_3;
label_9:
if (type != 1)
goto label_5;
if (!m_pGameMode->isCreativeType())
field_DA4 = 10;
return;
}
if (m_hitResult.m_hitType == HitResult::NONE)
goto label_9;
label_3:
if (m_hitResult.m_hitType != HitResult::ENTITY)
{
if (m_hitResult.m_hitType != HitResult::AABB)
goto label_5;
// @NOTE: extra scope to avoid error
{
Tile* pTile = Tile::tiles[m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ)];
if (type == 1)
{
if (pTile)
{
// @BUG: This is only done on the client side.
m_pLevel->extinguishFire(hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide);
if (pTile != Tile::unbreakable || m_pLocalPlayer->field_B94 > 99 && !hr.m_bUnk24)
{
m_pGameMode->startDestroyBlock(hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide);
}
}
return;
}
ItemInstance item(m_pLocalPlayer->m_pInventory->getSelectedItemId(), 999, 0);
if (m_pGameMode->useItemOn(m_pLocalPlayer, m_pLevel, item.m_itemID < 0 ? nullptr : &item, hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide))
{
m_pLocalPlayer->swing();
if (!isOnline())
return;
if (item.m_itemID > C_MAX_TILES || item.m_itemID < 0)
return;
int dx = hr.m_tileX, dz = hr.m_tileZ;
uint8_t dy = uint8_t(hr.m_tileY);
if (m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ) != Tile::topSnow->m_ID)
{
switch (hr.m_hitSide)
{
case DIR_YNEG: dy--; break;
case DIR_YPOS: dy++; break;
case DIR_ZNEG: dz--; break;
case DIR_ZPOS: dz++; break;
case DIR_XNEG: dx--; break;
case DIR_XPOS: dx++; break;
}
}
m_pRakNetInstance->send(new PlaceBlockPacket(m_pLocalPlayer->m_EntityID, dx, dy, dz, uint8_t(item.m_itemID), uint8_t(hr.m_hitSide)));
return;
}
}
label_5:
if (type != 2)
return;
goto label_15;
}
if (type == 1)
{
m_pGameMode->attack(m_pLocalPlayer, hr.m_pEnt);
return;
}
if (type == 2)
{
a = hr.m_pEnt->interactPreventDefault();
m_pGameMode->interact(m_pLocalPlayer, hr.m_pEnt);
if (!a)
{
label_15:
int id = m_pLocalPlayer->m_pInventory->getSelectedItemId();
if (id >= 0)
{
ItemInstance item(m_pLocalPlayer->m_pInventory->getSelectedItemId(), 999, 0);
if (m_pGameMode->useItem(m_pLocalPlayer, m_pLevel, &item))
m_pGameRenderer->m_pItemInHandRenderer->itemUsed();
}
}
}
}
void Minecraft::tickInput()
{
if (field_D14)
{
if (!field_D14->field_10)
{
field_DB0 = 1;
field_D14->updateEvents();
field_DB0 = false;
if (field_DB1)
{
setScreen(m_pScreen);
m_pScreen = NULL;
field_DB1 = false;
}
return;
}
}
if (!m_pLocalPlayer)
return;
bool bIsInGUI = m_gui.isInside(Mouse::_x, Mouse::_y);
while (Mouse::_index + 1 < Mouse::_inputs.size())
{
Mouse::_index++;
if (getTimeMs() - field_2B4 > 200)
continue;
if (Mouse::_buttonStates[1])
m_gui.handleClick(1, Mouse::_x, Mouse::_y);
if (!bIsInGUI && m_options.field_19)
{
MouseInput& input = Mouse::_inputs[Mouse::_index];
if (input.field_0 == 1 && input.field_4 == 1)
{
handleMouseClick(1);
field_DAC = field_DA8;
}
if (input.field_0 == 2 && input.field_4 == 1)
{
handleMouseClick(2);
field_DAC = field_DA8;
}
}
}
while (Keyboard::_index + 1 < Keyboard::_inputs.size())
{
Keyboard::_index++;
Keyboard::Input& input = Keyboard::_inputs[Keyboard::_index];
int keyCode = input.field_4;
bool bPressed = input.field_0 == 1;
m_pLocalPlayer->m_pKeyboardInput->setKey(keyCode, bPressed);
if (bPressed)
{
m_gui.handleKeyPressed(keyCode);
int index = keyCode - '1';
if (index <= 8 && index >= 0)
{
m_pLocalPlayer->m_pInventory->selectSlot(index);
}
else if (keyCode == AKEYCODE_SEARCH)
{
m_options.field_23D ^= 1;
}
else if (keyCode == AKEYCODE_MENU)
{
pauseGame();
}
#ifdef ENH_ALLOW_AO
else if (keyCode == AKEYCODE_F4)
{
// Toggle ambient occlusion.
m_options.field_18 ^= 1;
Minecraft::useAmbientOcclusion = m_options.field_18;
m_pLevelRenderer->allChanged();
}
#endif
}
if (m_options.field_19)
continue;
if (getTimeMs() - field_2B4 <= 200)
{
if (m_options.m_keyBinds[Options::DESTROY].value == keyCode && bPressed)
handleMouseClick(1);
if (m_options.m_keyBinds[Options::PLACE].value == keyCode && bPressed)
handleMouseClick(2);
}
}
// @TODO: fix gotos
bool v12 = false;
if (m_options.field_19)
{
if (!Mouse::_buttonStates[1] || bIsInGUI)
goto label_12;
}
else if (Keyboard::_states[m_options.m_keyBinds[Options::DESTROY].value] != 1)
{
goto label_12;
}
if (!field_D14 && (field_DA8 - field_DAC) >= (m_timer.field_10 * 0.25f))
{
handleMouseClick(1);
field_DAC = field_DA8;
}
if (m_bGrabbedMouse)
{
v12 = true;
}
else
{
label_12:
v12 = false;
}
handleMouseDown(1, v12);
field_2B4 = getTimeMs();
Keyboard::_inputs.clear();
Keyboard::_index = -1;
Mouse::_inputs.clear();
Mouse::_index = -1;
#ifndef ORIGINAL_CODE
if (m_bGrabbedMouse)
{
platform()->recenterMouse();
}
#endif
}
void Minecraft::_levelGenerated()
{
if (m_pNetEventCallback)
m_pNetEventCallback->levelGenerated(m_pLevel);
}
void Minecraft::tick()
{
if (field_DA4 > 0)
field_DA4--;
tickInput();
m_gui.tick();
// if the level has been prepared, delete the prep thread
if (!m_bPreparingLevel)
{
if (m_pPrepThread)
{
delete m_pPrepThread;
m_pPrepThread = nullptr;
_levelGenerated();
}
if (m_pLevel && !field_288)
{
m_pGameRenderer->tick();
m_pLevelRenderer->tick();
m_pLevel->tickEntities();
m_pLevel->tick();
if (m_pLocalPlayer)
{
m_pLevel->animateTick(
Mth::floor(m_pLocalPlayer->m_pos.x),
Mth::floor(m_pLocalPlayer->m_pos.y),
Mth::floor(m_pLocalPlayer->m_pos.z));
}
}
m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
if (!field_288)
{
m_pTextures->tick();
m_pParticleEngine->tick();
}
if (field_D14)
field_D14->tick();
}
}
void Minecraft::update()
{
if (field_288 && m_pLevel)
{
float x = m_timer.field_18;
m_timer.advanceTime();
m_timer.field_18 = x;
}
else
{
m_timer.advanceTime();
}
if (m_pRakNetInstance)
{
m_pRakNetInstance->runEvents(m_pNetEventCallback);
}
if (m_timer.field_14 > 0)
{
for (int i = 0; i < m_timer.field_14; i++)
{
tick();
field_DA8++;
}
}
if (m_pLevel && !m_bPreparingLevel)
{
m_pLevel->updateLights();
}
m_pGameRenderer->render(m_timer.field_18);
}
void Minecraft::init()
{
m_pTextures = new Textures(&m_options, platform());
m_pTextures->addDynamicTexture(new WaterTexture);
m_pTextures->addDynamicTexture(new WaterSideTexture);
m_pLevelRenderer = new LevelRenderer(this, m_pTextures);
m_pGameRenderer = new GameRenderer(this);
m_pParticleEngine = new ParticleEngine(m_pLevel, m_pTextures);
m_pUser = new User("TestUser", "");
m_pGameMode = new SurvivalMode(this);
reloadOptions();
m_pFont = new Font(&m_options, "font/default.png", m_pTextures);
}
Minecraft::~Minecraft()
{
SAFE_DELETE(m_pNetEventCallback);
SAFE_DELETE(m_pRakNetInstance);
SAFE_DELETE(m_pLevelRenderer);
SAFE_DELETE(m_pGameRenderer);
SAFE_DELETE(m_pParticleEngine);
SAFE_DELETE(m_pSoundEngine);
SAFE_DELETE(m_pGameMode);
SAFE_DELETE(m_pFont);
SAFE_DELETE(m_pTextures);
if (m_pLevel)
{
LevelStorage* pStor = m_pLevel->getLevelStorage();
if (pStor)
delete pStor;
if (m_pLevel)
delete m_pLevel;
}
SAFE_DELETE(m_pUser);
SAFE_DELETE(m_pLevelStorageSource);
SAFE_DELETE(m_pTurnInput);
//@BUG: potentially leaking a CThread instance if this is destroyed early?
}
void Minecraft::prepareLevel(const std::string& unused)
{
field_DA0 = 1;
float startTime = getTimeS();
Level* pLevel = m_pLevel;
if (!pLevel->field_B0C)
{
pLevel->setUpdateLights(0);
}
for (int i = 8, i2 = 0; i != 8 + C_MAX_CHUNKS_X * 16; i += 16)
{
for (int j = 8; j != 8 + C_MAX_CHUNKS_Z * 16; j += 16, i2 += 100)
{
// this looks like some kind of progress tracking
m_progressPercent = i2 / (C_MAX_CHUNKS_X * C_MAX_CHUNKS_Z);
float time1 = getTimeS();
// generating all the chunks at once
TileID unused = m_pLevel->getTile(i, (C_MAX_Y + C_MIN_Y) / 2, j);
if (time1 != -1.0f)
getTimeS();
float time2 = getTimeS();
if (m_pLevel->field_B0C)
{
while (m_pLevel->updateLights());
}
if (time2 != -1.0f)
getTimeS();
}
}
if (startTime != -1.0f)
getTimeS();
m_pLevel->setUpdateLights(1);
startTime = getTimeS();
for (int x = 0; x < C_MAX_CHUNKS_X; x++)
{
for (int z = 0; z < C_MAX_CHUNKS_Z; z++)
{
LevelChunk* pChunk = m_pLevel->getChunk(x, z);
if (!pChunk)
continue;
if (pChunk->field_237)
continue;
pChunk->m_bUnsaved = false;
pChunk->clearUpdateMap();
}
}
if (startTime != -1.0f)
getTimeS();
field_DA0 = 3;
if (m_pLevel->field_B0C)
{
m_pLevel->setInitialSpawn();
m_pLevel->saveLevelData();
m_pLevel->getChunkSource()->saveAll();
}
else
{
m_pLevel->saveLevelData();
}
m_progressPercent = -1;
field_DA0 = 2;
startTime = getTimeS();
m_pLevel->prepare();
if (startTime != -1.0f)
getTimeS();
// These strings are initialized and then removed quickly afterwards. Probably some debug leftover
// "Generate level:";
// " - light: ";
// " - getTl: ";
// " - clear: ";
// " - prepr: ";
}
void Minecraft::generateLevel(const std::string& unused, Level* pLevel)
{
float time = getTimeS(); //@UNUSED
prepareLevel(unused);
if (time != -1.0f)
getTimeS(); //@QUIRK: unused return value
#pragma warning(disable : 26444) // C26444: Don't try to declare a local variable with no name.
std::string("Level generated: "); //@QUIRK: unused string instance
LocalPlayer* pLocalPlayer = m_pLocalPlayer;
if (!pLocalPlayer)
{
pLocalPlayer = m_pGameMode->createPlayer(pLevel);
m_pLocalPlayer = pLocalPlayer;
}
if (pLocalPlayer)
{
pLocalPlayer->m_pKeyboardInput = new KeyboardInput(&m_options);
}
if (m_pLevelRenderer)
m_pLevelRenderer->setLevel(pLevel);
if (m_pParticleEngine)
m_pParticleEngine->setLevel(pLevel);
m_pGameMode->adjustPlayer(m_pLocalPlayer);
pLevel->validateSpawn();
pLevel->loadPlayer(m_pLocalPlayer);
if (m_pLocalPlayer)
{
m_pLocalPlayer->resetPos();
}
m_pMobPersp = m_pLocalPlayer;
m_pLevel = pLevel;
m_bPreparingLevel = false;
if (m_pRakNetInstance->m_bIsHost)
m_pRakNetInstance->announceServer(m_pUser->field_0);
}
void* Minecraft::prepareLevel_tspawn(void* ptr)
{
Minecraft* pMinecraft = (Minecraft*)ptr;
pMinecraft->generateLevel("Currently not used", pMinecraft->m_pLevel);
return nullptr;
}
void Minecraft::pauseGame()
{
if (field_D14) return;
m_pLevel->savePlayerData();
setScreen(new PauseScreen);
}
void Minecraft::setLevel(Level* pLevel, const std::string& text, LocalPlayer* pLocalPlayer)
{
m_pMobPersp = nullptr;
if (pLevel)
{
m_pGameMode->initLevel(pLevel);
if (pLocalPlayer && m_pLocalPlayer == nullptr)
{
m_pLocalPlayer = pLocalPlayer;
pLocalPlayer->resetPos();
}
else if (m_pLocalPlayer)
{
m_pLocalPlayer->resetPos();
pLevel->addEntity(m_pLocalPlayer);
}
m_pLevel = pLevel;
m_bPreparingLevel = true;
m_pPrepThread = new CThread(&Minecraft::prepareLevel_tspawn, this);
}
else
{
m_pLocalPlayer = nullptr;
}
}
void Minecraft::selectLevel(const std::string& a, const std::string& b, int c)
{
LevelStorage* pStor = m_pLevelStorageSource->selectLevel(a, false);
Dimension* pDim = Dimension::getNew(0);
m_pLevel = new Level(pStor, b, c, 1, pDim);
setLevel(m_pLevel, "Generating level", nullptr);
field_D9C = 1;
}
const char* Minecraft::getProgressMessage()
{
return progressMessages[field_DA0];
}
LevelStorageSource* Minecraft::getLevelSource()
{
return m_pLevelStorageSource;
}
void Minecraft::leaveGame(bool bCopyMap)
{
m_bPreparingLevel = false;
m_pRakNetInstance->disconnect();
m_pMobPersp = nullptr;
m_pLevelRenderer->setLevel(nullptr);
m_pParticleEngine->setLevel(nullptr);
#ifndef ORIGINAL_CODE
// @BUG: Deleting ServerSideNetworkHandler too late! This causes
// access to invalid memory in the destructor seeing as we already deleted the level.
delete m_pNetEventCallback;
#endif
if (m_pLevel)
{
LevelStorage* pStorage = m_pLevel->getLevelStorage();
SAFE_DELETE(pStorage);
SAFE_DELETE(m_pLevel);
m_pLevel = nullptr;
}
#ifdef ORIGINAL_CODE
delete m_pNetEventCallback;
#endif
m_pLocalPlayer = nullptr;
m_pNetEventCallback = nullptr;
field_D9C = 0;
if (bCopyMap)
setScreen(new RenameMPLevelScreen("_LastJoinedServer"));
else
setScreen(new StartMenuScreen);
}
void Minecraft::hostMultiplayer()
{
m_pRakNetInstance->host(m_pUser->field_0, C_DEFAULT_PORT, C_MAX_CONNECTIONS);
m_pNetEventCallback = new ServerSideNetworkHandler(this, m_pRakNetInstance);
}
void Minecraft::joinMultiplayer(const PingedCompatibleServer& serverInfo)
{
if (field_18 && m_pNetEventCallback)
{
field_18 = false;
m_pRakNetInstance->connect(serverInfo.m_address.ToString(), serverInfo.m_address.GetPort());
}
}
void Minecraft::cancelLocateMultiplayer()
{
field_18 = false;
m_pRakNetInstance->stopPingForHosts();
delete m_pNetEventCallback;
m_pNetEventCallback = nullptr;
}
void Minecraft::locateMultiplayer()
{
field_18 = true;
m_pRakNetInstance->pingForHosts(C_DEFAULT_PORT);
m_pNetEventCallback = new ClientSideNetworkHandler(this, m_pRakNetInstance);
}

114
source/App/Minecraft.hpp Normal file
View File

@@ -0,0 +1,114 @@
#pragma once
#include "App.hpp"
#include "Mth.hpp"
#include "Gui.hpp"
#include "Screen.hpp"
#include "Timer.hpp"
#include "GameRenderer.hpp"
#include "LevelRenderer.hpp"
#include "Level.hpp"
#include "CThread.hpp"
#include "LocalPlayer.hpp"
#include "SurvivalMode.hpp"
#include "ITurnInput.hpp"
#include "EntityRenderDispatcher.hpp"
#include "ParticleEngine.hpp"
#include "SoundEngine.hpp"
#include "RakNetInstance.hpp"
#include "NetEventCallback.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 reloadOptions();
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();
virtual void onGraphicsReset();
virtual void update() override;
virtual void init() override;
static void* prepareLevel_tspawn(void* pMinecraft);
void generateLevel(const std::string& unused, Level* pLevel);
void prepareLevel(const std::string& unused);
void _levelGenerated();
bool isOnline();
bool isOnlineClient();
const char* getProgressMessage();
LevelStorageSource* getLevelSource();
public:
static int width, height;
static bool useAmbientOcclusion;
static const char* progressMessages[];
static const bool DEADMAU5_CAMERA_CHEATS;
static int customDebugId;
public:
bool field_18 = false;
Options m_options;
bool field_288 = false;
LevelRenderer* m_pLevelRenderer = nullptr;
GameRenderer* m_pGameRenderer = nullptr;
ParticleEngine* m_pParticleEngine = nullptr;
SoundEngine* m_pSoundEngine = nullptr;
GameMode* m_pGameMode = nullptr;
Textures* m_pTextures = nullptr;
Font* m_pFont = nullptr;
RakNetInstance* m_pRakNetInstance = nullptr;
NetEventCallback* m_pNetEventCallback = nullptr;
int field_2B0 = 0;
int field_2B4;
int field_2B8;
User* m_pUser = nullptr;
Level* m_pLevel = nullptr;
LocalPlayer* m_pLocalPlayer = nullptr;
Mob* m_pMobPersp = nullptr; // why is there a duplicate?
Gui m_gui;
int field_D0C = 0;
CThread* m_pPrepThread = nullptr;
Screen* field_D14 = nullptr;
int field_D18 = 10;
ITurnInput* m_pTurnInput = nullptr;
float field_D20 = 0.0f;
float field_D24 = 0.0f;
bool m_bGrabbedMouse = true;
HitResult m_hitResult;
int m_progressPercent = 0;
std::string field_D58;
Timer m_timer;
bool m_bPreparingLevel = false;
LevelStorageSource* m_pLevelStorageSource = nullptr; // TODO
int field_D9C = 0;
int field_DA0 = 0;
int field_DA4 = 0;
int field_DA8 = 0;
int field_DAC = 0;
bool field_DB0 = 0;
bool field_DB1 = 0;
Screen* m_pScreen = nullptr;
int m_licenseID = -2;
};

118
source/App/NinecraftApp.cpp Normal file
View File

@@ -0,0 +1,118 @@
#include "NinecraftApp.hpp"
#include "StartMenuScreen.hpp"
#include "MemoryLevelStorageSource.hpp"
#include "Item.hpp"
bool NinecraftApp::_hasInitedStatics;
bool NinecraftApp::handleBack(bool b)
{
if (m_bPreparingLevel)
return true;
if (!m_pLevel)
{
if (!field_D14)
return false;
return field_D14->handleBackEvent(b);
}
if (b)
return 1;
if (!field_D14) return false;
if (field_D14->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_NONE);
glEnable(GL_TEXTURE_2D);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
}
void NinecraftApp::init()
{
Mth::initMth();
if (!_hasInitedStatics)
{
_hasInitedStatics = true;
Material::initMaterials();
Tile::initTiles();
Item::initItems();
Biome::initBiomes();
}
initGLStates();
Tesselator::instance.init();
Minecraft::init();
m_pLevelStorageSource = new MemoryLevelStorageSource;
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, field_10);
#endif
Mouse::_xOld = Mouse::_x;
Mouse::_yOld = Mouse::_y;
updateStats();
}
void NinecraftApp::updateStats()
{
int timeMs = getTimeMs();
if (timeMs > field_2B0 + 999)
{
if (m_pLocalPlayer)
{
Vec3 &pos = m_pLocalPlayer->m_pos;
printf("%d fps\t%3d chunk updates. (%.2f, %.2f, %.2f)\n", m_fps, Chunk::updates, pos.x, pos.y, pos.z);
printf("%s", m_pLevelRenderer->gatherStats1());
Chunk::updates = 0;
}
else
{
printf("%d fps\n", m_fps);
}
field_2B0 = timeMs;
m_fps = 0;
}
}
NinecraftApp::~NinecraftApp()
{
teardown();
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include "Minecraft.hpp"
#include "Level.hpp"
#include "Tile.hpp"
//@TYPO: This is probably meant to say "MinecraftApp". Still not fixed in V0.3.0 though so not sure
class NinecraftApp : public Minecraft
{
public:
virtual ~NinecraftApp();
bool handleBack(bool) override;
void init() override;
void update() override;
void onGraphicsReset() override;
void teardown();
void updateStats();
void initGLStates();
private:
int field_DBC = 0;
bool field_DC0 = 1;
int m_fps = 0;
static bool _hasInitedStatics;
};