Integrate touch related development. (#90)

* * Add BuildActionIntention crap

* * Set Client and World projects to use MP compilation

* asd

* * Use the new BuildActionIntention to break and place blocks.

* * Reverse engineer the IArea system.

* * Copy break logic from survival into creative conditionally

* * Reverse IBuildInput and MouseHandler
* Replace the new relative paths in the client project with $(MC_ROOT) again

* * Reverse Multitouch, MouseDevice

* * Reverse a bunch of auxiliary classes for input.

* * Use CustomInputHolder instead of holding inputs manually.

* * Reverse a whole BUNCH of things!

* * Add feedback textures to the gitignore.

* * D-pad now renders! Also loads of other work.

* * More Stuff

* * Finish touch control bug fixing.

* * Finalize work.

* * One last thing..

* * Add a "cramped" mode to the options screen and start menu.

* * Oh, forgot to do something
This commit is contained in:
iProgramInCpp
2023-11-02 00:49:11 +02:00
committed by GitHub
parent 98d6b4e5e8
commit 60b21356a1
87 changed files with 3439 additions and 916 deletions

2
.gitignore vendored
View File

@@ -439,3 +439,5 @@ Win32/
# Ignore options.txt - where your configuration will be saved
/game/options.txt
/game/assetsO
/game/assets/gui/feedback_fill.png
/game/assets/gui/feedback_outer.png

View File

@@ -9,29 +9,11 @@
#define DEMO
#else
// TODO: Since this is the modded version, we don't need these anymore. Remove them
#if defined __ANDROID__ || defined TARGET_OS_IPHONE
#define MOBILE
#endif
// Enhancements
//#define ENH_ENTITY_SHADING // Allows shading of entities -- Currently we are abandoning this. Want to add normal support
#define ENH_SHADE_HELD_TILES // Allows shading of the item in hand
#define ENH_FIX_INVIS_STAIRS // Fixes a bug wherein a 16x16x16 chunk in the world that contains only stairs is invisible
#define ENH_ALLOW_AO // Allows using the F4 key to toggle ambient occlusion (buggy)
#define ENH_TRANSPARENT_HOTBAR // Allows the hotbar to be transparent. Due to a bug in the code, it is not.
#define ENH_INSTA_BREAK // Allows instant breaking of blocks. @TODO: Fix the mode without this
#define ENH_CAMERA_NO_PARTICLES // Hide particles from the view of a camera, such as smoke, that would otherwise render the resulting image useless.
#define ENH_USE_JAVA_LIGHT_RAMP // Use Java Beta 1.3 light ramp instead of flawed PE one
#define ENH_RUN_DAY_NIGHT_CYCLE // Allow the day/night cycle to run.
#define ENH_ENABLE_9TH_SLOT // Enable the 9th hotbar slot, instead of it being a "..." placeholder
#define ENH_USE_OWN_AO // Use own ambient occlusion engine - looks pretty much the same except it fixes the corners
#define ENH_ADD_OPTIONS_PAUSE // Add an 'options' button in the pause menu
#define ENH_EXTRA_ITEMS_IN_INV // Add extra items in a new 5th row in the inventory.
#define ENH_HIGHLIGHT_BY_HOVER // Highlight buttons by hovering them instead of the usual way.
#define ENH_ALLOW_SAND_GRAVITY // Allow sand to fall.
#define ENH_USE_GUI_SCALE_2 // Use a 2x GUI scale instead of 3x. Looks better on PC
#define ENH_ALLOW_SCROLL_WHEEL // Allow use of the scroll wheel to change selected inventory slots
#define ENH_DISABLE_TURN_ACCEL // Disable the turn acceleration mechanism. It should only be used on Xperia Play
#define ENH_3D_INVENTORY_TILES // Uses 3D rendered inventory tiles, use with ENH_SHADE_HELD_TILES to render correctly.
#define ENH_IMPROVED_SAVING // Improve world saving. The original Minecraft doesn't always really save for some reason
// TODO: Since this is the modded version, we don't need these anymore. Remove them
// Mods
//#define MOD_USE_FLAT_WORLD // Use a flat world instead of the regular world generation
@@ -42,6 +24,26 @@
// Tests
//#define TEST_DROPPED_ITEMS // Allow dropped items to be dropped and collected.
//#define TEST_SURVIVAL_MODE // Test survival mode.
#define TEST_TOUCH_SCREEN // Test touch screen controls. The mouse will simulate one touch finger.
// Enhancements
//#define ENH_ENTITY_SHADING // Allows shading of entities -- Currently we are abandoning this. Want to add normal support
#define ENH_SHADE_HELD_TILES // Allows shading of the item in hand
#define ENH_FIX_INVIS_STAIRS // Fixes a bug wherein a 16x16x16 chunk in the world that contains only stairs is invisible
#define ENH_ALLOW_AO // Allows using the F4 key to toggle ambient occlusion (buggy)
#define ENH_TRANSPARENT_HOTBAR // Allows the hotbar to be transparent. Due to a bug in the code, it is not.
#define ENH_CAMERA_NO_PARTICLES // Hide particles from the view of a camera, such as smoke, that would otherwise render the resulting image useless.
#define ENH_USE_JAVA_LIGHT_RAMP // Use Java Beta 1.3 light ramp instead of flawed PE one
#define ENH_RUN_DAY_NIGHT_CYCLE // Allow the day/night cycle to run.
#define ENH_USE_OWN_AO // Use own ambient occlusion engine - looks pretty much the same except it fixes the corners
#define ENH_ADD_OPTIONS_PAUSE // Add an 'options' button in the pause menu
#define ENH_EXTRA_ITEMS_IN_INV // Add extra items in a new 5th row in the inventory.
#define ENH_HIGHLIGHT_BY_HOVER // Highlight buttons by hovering them instead of the usual way.
#define ENH_ALLOW_SAND_GRAVITY // Allow sand to fall.
#define ENH_USE_GUI_SCALE_2 // Use a 2x GUI scale instead of 3x. Looks better on PC
#define ENH_ALLOW_SCROLL_WHEEL // Allow use of the scroll wheel to change selected inventory slots
#define ENH_3D_INVENTORY_TILES // Uses 3D rendered inventory tiles, use with ENH_SHADE_HELD_TILES to render correctly.
#define ENH_IMPROVED_SAVING // Improve world saving. The original Minecraft doesn't always really save for some reason
// Toggle Demo Mode
//#define DEMO

BIN
game/minecraftcpp.exe Normal file

Binary file not shown.

View File

@@ -11,6 +11,8 @@
#include <sstream>
#include <shlobj.h>
#include "GameMods.hpp"
#include "AppPlatform_win32.hpp"
#include "LoggerWin32.hpp"
@@ -190,6 +192,11 @@ Texture AppPlatform_win32::loadTexture(const std::string& str, bool b)
return Texture(width, height, img2, 1, 0);
}
bool AppPlatform_win32::isTouchscreen()
{
return false;
}
bool AppPlatform_win32::hasFileSystemAccess()
{
return true;
@@ -317,36 +324,36 @@ void AppPlatform_win32::updateFocused(bool focused)
setMouseGrabbed(m_bGrabbedMouse);
}
Mouse::ButtonType AppPlatform_win32::GetMouseButtonType(UINT iMsg)
MouseButtonType AppPlatform_win32::GetMouseButtonType(UINT iMsg)
{
switch (iMsg)
{
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
return Mouse::ButtonType::LEFT;
return BUTTON_LEFT;
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
return Mouse::ButtonType::RIGHT;
return BUTTON_RIGHT;
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
return Mouse::ButtonType::MIDDLE;
return BUTTON_MIDDLE;
case WM_MOUSEWHEEL:
return Mouse::ButtonType::SCROLLWHEEL;
return BUTTON_SCROLLWHEEL;
default:
return Mouse::ButtonType::NONE;
return BUTTON_NONE;
}
}
Mouse::ButtonState AppPlatform_win32::GetMouseButtonState(UINT iMsg, WPARAM wParam)
bool AppPlatform_win32::GetMouseButtonState(UINT iMsg, WPARAM wParam)
{
Mouse::ButtonState result;
bool result;
switch (iMsg)
{
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
result = Mouse::ButtonState::DOWN;
result = true;
break;
case WM_MOUSEWHEEL:
{
@@ -354,17 +361,17 @@ Mouse::ButtonState AppPlatform_win32::GetMouseButtonState(UINT iMsg, WPARAM wPar
if (wheelDelta > 0)
{
// "A positive value indicates that the wheel was rotated forward, away from the user."
result = Mouse::ButtonState::UP;
result = false;
}
else
{
// "A negative value indicates that the wheel was rotated backward, toward the user."
result = Mouse::ButtonState::DOWN;
result = true;
}
break;
}
default:
result = Mouse::ButtonState::UP;
result = false;
break;
}

View File

@@ -37,6 +37,9 @@ public:
std::string getDateString(int time) override;
Texture loadTexture(const std::string& str, bool b) override;
// From v0.1.1. Also add these to determine touch screen use within the game.
bool isTouchscreen() override;
// Also add these to allow proper turning within the game.
void recenterMouse() override;
void setMouseGrabbed(bool b) override;
@@ -57,8 +60,8 @@ public:
const char* const getWindowTitle() const { return m_WindowTitle; }
SoundSystem* const getSoundSystem() const override { return m_pSoundSystem; }
static Mouse::ButtonType GetMouseButtonType(UINT iMsg);
static Mouse::ButtonState GetMouseButtonState(UINT iMsg, WPARAM wParam);
static MouseButtonType GetMouseButtonType(UINT iMsg);
static bool GetMouseButtonState(UINT iMsg, WPARAM wParam);
static Keyboard::KeyState GetKeyState(UINT iMsg);
private:

View File

@@ -15,6 +15,8 @@
#include "client/app/App.hpp"
#include "client/app/NinecraftApp.hpp"
#include "client/player/input/Multitouch.hpp"
#include "AppPlatform_win32.hpp"
LPCTSTR g_WindowClassName = TEXT("MCPEClass");
@@ -45,8 +47,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
{
Mouse::ButtonType buttonType = AppPlatform_win32::GetMouseButtonType(iMsg);
Mouse::ButtonState buttonState = AppPlatform_win32::GetMouseButtonState(iMsg, wParam);
MouseButtonType buttonType = AppPlatform_win32::GetMouseButtonType(iMsg);
bool buttonState = AppPlatform_win32::GetMouseButtonState(iMsg, wParam);
int posX, posY;
if (iMsg == WM_MOUSEMOVE)
{
@@ -59,6 +61,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
posY = Mouse::getY();
}
Mouse::feed(buttonType, buttonState, posX, posY);
Multitouch::feed(buttonType, buttonState, posX, posY, 0);
break;
}

View File

@@ -120,6 +120,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -130,6 +131,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -142,6 +144,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -156,6 +159,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -168,6 +172,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -178,6 +183,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -190,6 +196,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -204,6 +211,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -291,6 +299,22 @@
<ClInclude Include="$(MC_ROOT)\source\client\sound\SoundEngine.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\sound\SoundRepository.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\sound\SoundSystem.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IArea.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IBuildInput.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IncludeExcludeArea.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\MouseHandler.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\PolygonArea.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\RectangleArea.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\MouseDevice.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\Multitouch.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\CustomInputHolder.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IInputHolder.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IMoveInput.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\ITouchScreenModel.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\TouchAreaModel.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\TouchInputHolder.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\TouchscreenInput_TestFps.hpp" />
<ClInclude Include="$(MC_ROOT)\source\client\player\input\UnifiedTurnBuild.hpp" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MC_ROOT)\source\client\app\App.cpp" />
@@ -371,6 +395,21 @@
<ClCompile Include="$(MC_ROOT)\source\client\sound\SoundEngine.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\sound\SoundRepository.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\sound\SoundSystem.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IBuildInput.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IncludeExcludeArea.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\MouseHandler.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\PolygonArea.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\RectangleArea.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\MouseDevice.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\Multitouch.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\CustomInputHolder.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IInputHolder.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IMoveInput.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\ITouchScreenModel.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\TouchAreaModel.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\TouchInputHolder.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\TouchscreenInput_TestFps.cpp" />
<ClCompile Include="$(MC_ROOT)\source\client\player\input\UnifiedTurnBuild.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common\Common.vcxproj">

View File

@@ -296,9 +296,6 @@
<ClInclude Include="$(MC_ROOT)\source\client\sound\SoundSystem.hpp">
<Filter>Header Files\Sound</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\GameMods.hpp">
<Filter>Source Files</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\app\App.hpp">
<Filter>Header Files\App</Filter>
</ClInclude>
@@ -317,6 +314,57 @@
<ClInclude Include="$(MC_ROOT)\source\client\network\ClientSideNetworkHandler.hpp">
<Filter>Header Files\Network</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\RectangleArea.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\PolygonArea.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\MouseHandler.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IncludeExcludeArea.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IArea.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IBuildInput.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\Multitouch.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\MouseDevice.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\TouchAreaModel.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\ITouchScreenModel.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IInputHolder.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\IMoveInput.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\CustomInputHolder.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\GameMods.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\UnifiedTurnBuild.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\TouchscreenInput_TestFps.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\client\player\input\TouchInputHolder.hpp">
<Filter>Header Files\Player\Input</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MC_ROOT)\source\client\gui\components\AvailableGamesList.cpp">
@@ -553,5 +601,50 @@
<ClCompile Include="$(MC_ROOT)\source\client\network\ClientSideNetworkHandler.cpp">
<Filter>Source Files\Network</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IncludeExcludeArea.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\PolygonArea.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\RectangleArea.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\MouseHandler.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IBuildInput.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\Multitouch.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\MouseDevice.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\ITouchScreenModel.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\TouchAreaModel.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IMoveInput.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\IInputHolder.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\CustomInputHolder.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\UnifiedTurnBuild.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\TouchscreenInput_TestFps.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\client\player\input\TouchInputHolder.cpp">
<Filter>Source Files\Player\Input</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -247,6 +247,7 @@
<ClCompile Include="$(MC_ROOT)\source\common\Timer.cpp" />
<ClCompile Include="$(MC_ROOT)\source\common\Util.cpp" />
<ClCompile Include="$(MC_ROOT)\source\common\Utils.cpp" />
<ClCompile Include="$(MC_ROOT)\source\common\SmoothFloat.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MC_ROOT)\source\common\CThread.hpp" />
@@ -258,6 +259,7 @@
<ClInclude Include="$(MC_ROOT)\source\common\Timer.hpp" />
<ClInclude Include="$(MC_ROOT)\source\common\Util.hpp" />
<ClInclude Include="$(MC_ROOT)\source\common\Utils.hpp" />
<ClInclude Include="$(MC_ROOT)\source\common\SmoothFloat.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -35,6 +35,9 @@
<ClCompile Include="$(MC_ROOT)\source\common\Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MC_ROOT)\source\common\SmoothFloat.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MC_ROOT)\source\common\CThread.hpp">
@@ -64,5 +67,8 @@
<ClInclude Include="$(MC_ROOT)\source\common\Utils.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MC_ROOT)\source\common\SmoothFloat.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -115,6 +115,7 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -126,6 +127,7 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -139,6 +141,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -154,6 +157,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -167,6 +171,7 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -178,6 +183,7 @@
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -191,6 +197,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -206,6 +213,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@@ -106,6 +106,11 @@ Texture AppPlatform::loadTexture(const std::string&, bool)
return Texture(0, 0, nullptr, 1, 0);
}
bool AppPlatform::isTouchscreen()
{
return true;
}
void AppPlatform::recenterMouse()
{

View File

@@ -49,6 +49,8 @@ public:
virtual Texture loadTexture(const std::string&, bool);
#ifndef ORIGINAL_CODE
// From v0.1.1. Also add these to determine touch screen use within the game.
virtual bool isTouchscreen();
// Also add these to allow proper turning within the game.
virtual void recenterMouse();
virtual void setMouseGrabbed(bool b);

View File

@@ -18,11 +18,13 @@
#include "world/gamemode/SurvivalMode.hpp"
#include "world/gamemode/CreativeMode.hpp"
#ifndef ORIGINAL_CODE
#include "client/player/input/MouseTurnInput.hpp"
#else
#include "client/player/input/ControllerTurnInput.hpp"
#endif
#include "client/player/input/MouseTurnInput.hpp"
#include "client/player/input/KeyboardInput.hpp"
#include "client/player/input/IBuildInput.hpp"
#include "client/player/input/CustomInputHolder.hpp"
#include "client/player/input/TouchInputHolder.hpp"
#include "client/player/input/Multitouch.hpp"
#include "world/tile/SandTile.hpp"
@@ -71,9 +73,7 @@ Minecraft::Minecraft() :
m_pPrepThread = nullptr;
m_pScreen = nullptr;
field_D18 = 10;
m_pTurnInput = nullptr;
field_D20 = 0.0f;
field_D24 = 0.0f;
m_pInputHolder = nullptr;
m_bGrabbedMouse = true;
m_progressPercent = 0;
m_bPreparingLevel = false;
@@ -107,10 +107,14 @@ void Minecraft::releaseMouse()
return;
if (m_pLocalPlayer)
m_pLocalPlayer->m_pKeyboardInput->releaseAllKeys();
m_pLocalPlayer->m_pMoveInput->releaseAllKeys();
m_bGrabbedMouse = false;
m_mouseHandler.release();
// Note, normally the platform stuff would be located within
// the mouse handler, but we don't have access to the platform
// from there!
platform()->setMouseGrabbed(false);
}
@@ -120,11 +124,11 @@ void Minecraft::grabMouse()
return;
m_bGrabbedMouse = true;
field_D20 = 0.0f;
field_D24 = 0.0f;
m_mouseHandler.grab();
setScreen(nullptr);
platform()->setMouseGrabbed(true);
platform()->setMouseGrabbed(!isTouchscreen());
}
void Minecraft::setScreen(Screen* pScreen)
@@ -209,6 +213,11 @@ bool Minecraft::isOnlineClient()
return m_pLevel->m_bIsMultiplayer;
}
bool Minecraft::isTouchscreen()
{
return m_bIsTouchscreen;
}
void Minecraft::setGuiScaleMultiplier(float f)
{
guiScaleMultiplier = f;
@@ -230,123 +239,129 @@ void Minecraft::handleMouseDown(int type, bool b)
}
}
void Minecraft::handleMouseClick(int type)
void Minecraft::handleBuildAction(BuildActionIntention* pAction)
{
int a;
HitResult& hr = m_hitResult;
// @TODO: fix goto hell
if (type == 1)
if (pAction->isRemove())
{
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)
bool bInteract = true;
if (!m_hitResult.isHit())
{
if (m_hitResult.m_hitType != HitResult::AABB)
goto label_5;
// @NOTE: extra scope to avoid error
if (pAction->isRemove() && !m_pGameMode->isCreativeType())
field_DA4 = 10;
}
else if (m_hitResult.m_hitType == HitResult::ENTITY)
{
if (pAction->isAttack())
{
Tile* pTile = Tile::tiles[m_pLevel->getTile(hr.m_tileX, hr.m_tileY, hr.m_tileZ)];
m_pGameMode->attack(m_pLocalPlayer, m_hitResult.m_pEnt);
}
else if (pAction->isInteract())
{
if (m_hitResult.m_pEnt->interactPreventDefault())
bInteract = false;
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);
m_pGameMode->interact(m_pLocalPlayer, m_hitResult.m_pEnt);
}
}
else if (m_hitResult.m_hitType == HitResult::AABB)
{
Tile* pTile = Tile::tiles[m_pLevel->getTile(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ)];
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);
}
}
if (pAction->isRemove())
{
if (!pTile)
return;
}
ItemInstance* pItem = getSelectedItem();
// @BUG: This is only done on the client side.
m_pLevel->extinguishFire(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ, m_hitResult.m_hitSide);
if (m_pGameMode->useItemOn(m_pLocalPlayer, m_pLevel, pItem->m_itemID <= 0 ? nullptr : pItem, hr.m_tileX, hr.m_tileY, hr.m_tileZ, hr.m_hitSide))
if (pTile != Tile::unbreakable || (m_pLocalPlayer->field_B94 > 99 && m_hitResult.m_bUnk24 != 1))
{
m_pLocalPlayer->swing();
if (!isOnline())
return;
if (pItem->m_itemID > C_MAX_TILES || pItem->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 HitResult::NOHIT: break;
case HitResult::MINY: dy--; break;
case HitResult::MAXY: dy++; break;
case HitResult::MINZ: dz--; break;
case HitResult::MAXZ: dz++; break;
case HitResult::MINX: dx--; break;
case HitResult::MAXX: dx++; break;
}
}
m_pRakNetInstance->send(new PlaceBlockPacket(m_pLocalPlayer->m_EntityID, dx, dy, dz, uint8_t(pItem->m_itemID), uint8_t(hr.m_hitSide)));
return;
m_pGameMode->startDestroyBlock(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ, m_hitResult.m_hitSide);
}
}
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)
else
{
label_15:
int id = m_pLocalPlayer->m_pInventory->getSelectedItemId();
if (id > 0)
ItemInstance* pItem = getSelectedItem();
if (m_pGameMode->useItemOn(
m_pLocalPlayer,
m_pLevel,
pItem->m_itemID <= 0 ? nullptr : pItem,
m_hitResult.m_tileX,
m_hitResult.m_tileY,
m_hitResult.m_tileZ,
m_hitResult.m_hitSide))
{
ItemInstance* pItem = getSelectedItem();
bInteract = false;
if (m_pGameMode->useItem(m_pLocalPlayer, m_pLevel, pItem))
m_pGameRenderer->m_pItemInHandRenderer->itemUsed();
m_pLocalPlayer->swing();
if (isOnline())
{
if (pItem->m_itemID > C_MAX_TILES || pItem->m_itemID < 0)
return;
int dx = m_hitResult.m_tileX, dz = m_hitResult.m_tileZ;
uint8_t dy = uint8_t(m_hitResult.m_tileY);
uint8_t hitSide = m_hitResult.m_hitSide;
if (m_pLevel->getTile(m_hitResult.m_tileX, m_hitResult.m_tileY, m_hitResult.m_tileZ) != Tile::topSnow->m_ID)
{
switch (m_hitResult.m_hitSide)
{
case HitResult::NOHIT: break;
case HitResult::MINY: dy--; break;
case HitResult::MAXY: dy++; break;
case HitResult::MINZ: dz--; break;
case HitResult::MAXZ: dz++; break;
case HitResult::MINX: dx--; break;
case HitResult::MAXX: dx++; break;
}
}
else
{
hitSide = HitResult::MINY;
}
m_pRakNetInstance->send(new PlaceBlockPacket(m_pLocalPlayer->m_EntityID, dx, dy, dz, uint8_t(pItem->m_itemID), hitSide));
}
}
}
}
if (bInteract && pAction->isInteract())
{
ItemInstance* pItem = getSelectedItem();
if (pItem)
{
if (m_pGameMode->useItem(m_pLocalPlayer, m_pLevel, pItem))
m_pGameRenderer->m_pItemInHandRenderer->itemUsed();
}
}
}
void Minecraft::handleMouseClick(int type)
{
if (!isTouchscreen())
{
if (type == 1)
{
BuildActionIntention bai(INTENT_HELD);
handleBuildAction(&bai);
}
if (type == 2)
{
BuildActionIntention bai(INTENT_CLICKED);
handleBuildAction(&bai);
}
}
}
void Minecraft::tickInput()
@@ -379,42 +394,40 @@ void Minecraft::tickInput()
if (getTimeMs() - field_2B4 > 200)
continue;
if (Mouse::isButtonDown(1))
if (Mouse::isButtonDown(BUTTON_LEFT))
m_gui.handleClick(1, Mouse::getX(), Mouse::getY());
if (!bIsInGUI && getOptions()->field_19)
{
if (Mouse::getEventButton() == Mouse::LEFT && Mouse::getEventButtonState() == Mouse::DOWN)
if (Mouse::getEventButton() == BUTTON_LEFT && Mouse::getEventButtonState())
{
handleMouseClick(1);
field_DAC = field_DA8;
}
if (Mouse::getEventButton() == Mouse::RIGHT && Mouse::getEventButtonState() == Mouse::DOWN)
if (Mouse::getEventButton() == BUTTON_RIGHT && Mouse::getEventButtonState())
{
handleMouseClick(2);
field_DAC = field_DA8;
}
#ifdef ENH_ALLOW_SCROLL_WHEEL
if (Mouse::getEventButton() == Mouse::SCROLLWHEEL)
if (Mouse::getEventButton() == BUTTON_SCROLLWHEEL)
{
int slot = m_pLocalPlayer->m_pInventory->m_SelectedHotbarSlot;
#ifdef ENH_ENABLE_9TH_SLOT
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 1)
#else
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 2)
#endif
int maxItems = m_gui.getNumSlots() - 1;
if (isTouchscreen())
maxItems--;
if (Mouse::getEventButtonState() <= 0) // @NOTE: Scroll up
if (Mouse::getEventButtonState() == 0) // @NOTE: Scroll up
{
if (slot-- == 0)
{
slot = MAX_ITEMS;
slot = maxItems;
}
}
else
{
if (slot++ == MAX_ITEMS) // @NOTE: Scroll down
if (slot++ == maxItems) // @NOTE: Scroll down
{
slot = 0;
}
@@ -431,13 +444,13 @@ void Minecraft::tickInput()
int keyCode = Keyboard::getEventKey();
bool bPressed = Keyboard::getEventKeyState() == 1;
m_pLocalPlayer->m_pKeyboardInput->setKey(keyCode, bPressed);
m_pLocalPlayer->m_pMoveInput->setKey(keyCode, bPressed);
if (bPressed)
{
m_gui.handleKeyPressed(keyCode);
for (int i = 0; i < 9; i++)
for (int i = 0; i < m_gui.getNumSlots(); i++)
{
if (getOptions()->isKey(eKeyMappingIndex(KM_SLOT_1 + i), keyCode))
m_pLocalPlayer->m_pInventory->selectSlot(i);
@@ -485,42 +498,41 @@ void Minecraft::tickInput()
if (getTimeMs() - field_2B4 <= 200)
{
if (getOptions()->getKey(KM_DESTROY) == keyCode && bPressed)
handleMouseClick(1);
{
BuildActionIntention intention(INTENT_HELD);
handleBuildAction(&intention);
}
if (getOptions()->getKey(KM_PLACE) == keyCode && bPressed)
handleMouseClick(2);
{
BuildActionIntention intention(INTENT_CLICKED);
handleBuildAction(&intention);
}
}
}
// @TODO: fix gotos
bool v12 = false;
BuildActionIntention bai;
bool b = m_pInputHolder->getBuildInput()->tickBuild(m_pLocalPlayer, &bai);
if (getOptions()->field_19)
{
if (!Mouse::isButtonDown(Mouse::LEFT) || bIsInGUI)
goto label_12;
}
else if (Keyboard::isKeyDown(getOptions()->getKey(KM_DESTROY)))
{
goto label_12;
}
if (b && !bai.isRemoveContinue())
handleBuildAction(&bai);
if (!m_pScreen && (field_DA8 - field_DAC) >= (m_timer.m_ticksPerSecond * 0.25f))
bool flag =
// If we are mouse operated, the LMB is held down and it's not in the GUI
((m_options->field_19 && Mouse::isButtonDown(BUTTON_LEFT) && !bIsInGUI) ||
// We are instead keyboard operated, so check for the KM_DESTROY key being held down
(!m_options->field_19 && Keyboard::isKeyDown(m_options->m_keyMappings[KM_DESTROY].value)) ||
// The build action intention is a remove one
b && bai.isRemove());
if (flag && !m_pScreen && (field_DA8 - field_DAC) >= (m_timer.m_ticksPerSecond * 0.25f))
{
handleMouseClick(1);
bai = BuildActionIntention(INTENT_HELD);
handleBuildAction(&bai); // handleMouseClick(BUTTON_LEFT)
field_DAC = field_DA8;
}
if (m_bGrabbedMouse)
{
v12 = true;
}
else
{
label_12:
v12 = false;
}
handleMouseDown(1, v12);
handleMouseDown(BUTTON_LEFT, flag);
field_2B4 = getTimeMs();
@@ -607,6 +619,38 @@ std::string Minecraft::getVersionString()
return "v0.1.0 alpha";
}
void Minecraft::_reloadInput()
{
if (m_pInputHolder)
delete m_pInputHolder;
if (isTouchscreen())
{
m_pInputHolder = new TouchInputHolder(this, m_options);
}
else
{
m_pInputHolder = new CustomInputHolder(
new KeyboardInput(m_options),
#ifdef ORIGINAL_CODE
new ControllerTurnInput,
#else
new MouseTurnInput(this),
#endif
new IBuildInput
);
}
m_mouseHandler.setTurnInput(m_pInputHolder->getTurnInput());
if (m_pLevel && m_pLocalPlayer)
{
m_pLocalPlayer->m_pMoveInput = m_pInputHolder->getMoveInput();
}
m_options->field_19 = !isTouchscreen();
}
void Minecraft::_levelGenerated()
{
if (m_pNetEventCallback)
@@ -678,6 +722,8 @@ void Minecraft::tick()
if (m_pScreen)
m_pScreen->tick();
Multitouch::reset();
}
}
@@ -731,11 +777,9 @@ void Minecraft::init()
else
m_options = new Options();
#ifndef ORIGINAL_CODE
m_pTurnInput = new MouseTurnInput(this);
#else
m_pTurnInput = new ControllerTurnInput;
#endif
m_bIsTouchscreen = platform()->isTouchscreen();
_reloadInput();
m_pRakNetInstance = new RakNetInstance;
@@ -796,7 +840,7 @@ Minecraft::~Minecraft()
SAFE_DELETE(m_pUser);
SAFE_DELETE(m_pLevelStorageSource);
SAFE_DELETE(m_pTurnInput);
SAFE_DELETE(m_pInputHolder);
SAFE_DELETE(m_Logger);
//@BUG: potentially leaking a CThread instance if this is destroyed early?
@@ -904,6 +948,9 @@ void Minecraft::sizeUpdate(int newWidth, int newHeight)
if (m_pScreen)
m_pScreen->setSize(int(Minecraft::width * Gui::InvGuiScale), int(Minecraft::height * Gui::InvGuiScale));
if (m_pInputHolder)
m_pInputHolder->setScreenSize(newWidth, newHeight);
}
float Minecraft::getBestScaleForThisScreenSize(int width, int height)
@@ -911,23 +958,25 @@ float Minecraft::getBestScaleForThisScreenSize(int width, int height)
if (height > 1800)
return 1.0f / 4.0f;
// phones only
#if !defined(_WIN32) && !defined(USE_SDL2)
if (height > 600)
return 1.0f / 4.0f;
if (isTouchscreen())
{
if (height > 600)
return 1.0f / 4.0f;
if (height > 400)
return 1.0f / 3.0f;
if (height > 400)
return 1.0f / 3.0f;
if (height > 300)
return 1.0f / 2.0f;
#else
if (height > 1000)
return 1.0f / 3.0f;
if (height > 300)
return 1.0f / 2.0f;
}
else
{
if (height > 1000)
return 1.0f / 3.0f;
if (height > 400)
return 1.0f / 2.0f;
#endif
if (height > 400)
return 1.0f / 2.0f;
}
return 1.0f;
}
@@ -953,9 +1002,7 @@ void Minecraft::generateLevel(const std::string& unused, Level* pLevel)
}
if (pLocalPlayer)
{
pLocalPlayer->m_pKeyboardInput = new KeyboardInput(m_options);
}
pLocalPlayer->m_pMoveInput = m_pInputHolder->getMoveInput();
if (m_pLevelRenderer)
m_pLevelRenderer->setLevel(pLevel);

View File

@@ -16,7 +16,9 @@
#include "client/gui/Screen.hpp"
#include "network/RakNetInstance.hpp"
#include "network/NetEventCallback.hpp"
#include "client/player/input/ITurnInput.hpp"
#include "client/player/input/IInputHolder.hpp"
#include "client/player/input/MouseHandler.hpp"
#include "client/player/input/BuildActionIntention.hpp"
#include "client/renderer/GameRenderer.hpp"
#include "client/renderer/LevelRenderer.hpp"
#include "client/renderer/entity/EntityRenderDispatcher.hpp"
@@ -43,6 +45,7 @@ public:
void saveOptions();
void handleMouseClick(int type);
void handleMouseDown(int type, bool b);
void handleBuildAction(BuildActionIntention*);
bool isLevelGenerated();
void selectLevel(const std::string&, const std::string&, int);
void setLevel(Level*, const std::string&, LocalPlayer*);
@@ -58,6 +61,7 @@ public:
void resetPlayer(Player* player);
void respawnPlayer(Player* player);
std::string getVersionString();
bool isTouchscreen();
virtual void update() override;
virtual void init() override;
@@ -68,7 +72,6 @@ public:
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);
@@ -80,6 +83,10 @@ public:
static void setGuiScaleMultiplier(float f);
private:
void _reloadInput();
void _levelGenerated();
public:
static float guiScaleMultiplier;
static int width, height;
@@ -116,10 +123,10 @@ public:
CThread* m_pPrepThread;
Screen* m_pScreen;
int field_D18;
ITurnInput* m_pTurnInput;
float field_D20;
float field_D24;
IInputHolder* m_pInputHolder;
MouseHandler m_mouseHandler;
bool m_bGrabbedMouse;
bool m_bIsTouchscreen;
HitResult m_hitResult;
int m_progressPercent;
std::string m_externalStorageDir;

View File

@@ -8,6 +8,7 @@
#include "NinecraftApp.hpp"
#include "world/item/Item.hpp"
#include "client/player/input/Multitouch.hpp"
#include "client/gui/screens/StartMenuScreen.hpp"
#ifdef DEMO
@@ -107,6 +108,7 @@ void NinecraftApp::teardown()
void NinecraftApp::update()
{
++m_fps;
Multitouch::commit();
Minecraft::update();
#ifdef ORIGINAL_CODE

View File

@@ -134,6 +134,8 @@ void Gui::render(float f, bool bHaveScreen, int mouseX, int mouseY)
if (!m->m_pLevel || !m->m_pLocalPlayer)
return;
bool isTouchscreen = m->isTouchscreen();
field_4 = -90.0f;
#ifndef ENH_TRANSPARENT_HOTBAR
@@ -156,25 +158,86 @@ void Gui::render(float f, bool bHaveScreen, int mouseX, int mouseY)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif
int nSlots = getNumSlots();
int hotbarWidth = 2 + nSlots * 20;
// hotbar
int cenX = width / 2;
blit(cenX - 182 / 2, height - 22, 0, 0, 182, 22, 0, 0);
blit(cenX - hotbarWidth / 2, height - 22, 0, 0, hotbarWidth, 22, 0, 0);
// selection mark
blit(cenX - 92 + 20 * pInventory->m_SelectedHotbarSlot, height - 23, 0, 22, 24, 22, 0, 0);
blit(cenX - 1 - hotbarWidth / 2 + 20 * pInventory->m_SelectedHotbarSlot, height - 23, 0, 22, 24, 22, 0, 0);
m->m_pTextures->loadAndBindTexture("gui/icons.png");
if (!isTouchscreen)
{
#ifndef ENH_TRANSPARENT_HOTBAR
glEnable(GL_BLEND);
glEnable(GL_BLEND);
#endif
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
blit(cenX - 8, height / 2 - 8, 0, 0, 16, 16, 0, 0);
#ifndef ENH_TRANSPARENT_HOTBAR
glDisable(GL_BLEND);
#endif
}
else
{
// if needed, draw feedback
// NOTE: real Minecraft PE takes it directly from the gamemode as "current progress" and
// "last progress". Well guess what? The game mode in question updates our field_8 with
// the pre-interpolated break progress! Isn't that awesome?!
float breakProgress = field_8;
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
// don't know about this if-structure, it feels like it'd be like
// if (field_C >= 0.0f && breakProgress <= 0.0f)
// that;
// else
// this;
if (breakProgress > 0.0f || m_pMinecraft->m_pInputHolder->m_feedbackAlpha < 0.0f)
{
if (breakProgress > 0.0f)
{
float xPos = m_pMinecraft->m_pInputHolder->m_feedbackX;
float yPos = m_pMinecraft->m_pInputHolder->m_feedbackY;
// crosshair
blit(cenX - 8, height / 2 - 8, 0, 0, 16, 16, 0, 0);
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/feedback_outer.png");
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
blit(InvGuiScale * xPos - 44.0f, InvGuiScale * yPos - 44.0f, 0, 0, 88, 88, 256, 256);
glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/feedback_fill.png");
// note: scale starts from 4.0f
float halfWidth = (40.0f * breakProgress + 48.0f) / 2.0f;
blit(InvGuiScale * xPos - halfWidth, InvGuiScale * yPos - halfWidth, 0, 0, halfWidth * 2, halfWidth * 2, 256, 256);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glDisable(GL_BLEND);
}
}
else
{
float xPos = m_pMinecraft->m_pInputHolder->m_feedbackX;
float yPos = m_pMinecraft->m_pInputHolder->m_feedbackY;
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/feedback_outer.png");
glColor4f(1.0f, 1.0f, 1.0f, Mth::Min(1.0f, m_pMinecraft->m_pInputHolder->m_feedbackAlpha));
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
blit(InvGuiScale * xPos - 44.0f, InvGuiScale * yPos - 44.0f, 0, 0, 88, 88, 256, 256);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glDisable(GL_BLEND);
}
}
#ifdef ENH_TRANSPARENT_HOTBAR
glDisable(GL_BLEND);
#endif
if (m_pMinecraft->m_pGameMode->canHurtPlayer())
{
@@ -259,29 +322,34 @@ void Gui::render(float f, bool bHaveScreen, int mouseX, int mouseY)
m->m_pTextures->loadAndBindTexture("gui/gui_blocks.png");
int slotX = cenX - 88;
for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++)
int diff = m->isTouchscreen();
int slotX = cenX - hotbarWidth / 2 + 3;
for (int i = 0; i < nSlots - diff; i++)
{
renderSlot(i, slotX, height - 19, f);
slotX += 20;
}
slotX = cenX - 88;
for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++)
slotX = cenX - hotbarWidth / 2 + 3;
for (int i = 0; i < nSlots - diff; i++)
{
renderSlotOverlay(i, slotX, height - 19, f);
slotX += 20;
}
#undef DIFF
field_A3C = false;
// blit the "more items" button
#ifndef ENH_ENABLE_9TH_SLOT
m->m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
blit(cenX + 72, height - 19, 208, 208, 16, 16, 0, 0);
#endif
if (m->isTouchscreen())
{
m->m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
blit(cenX + hotbarWidth / 2 - 19, height - 19, 208, 208, 16, 16, 0, 0);
}
// render messages
if (m_bRenderMessages)
@@ -339,16 +407,17 @@ int Gui::getSlotIdAt(int mouseX, int mouseY)
if (scaledY >= scaledHeight)
return -1;
if (scaledY < scaledHeight-19)
if (scaledY < scaledHeight - 19)
return -1;
int slotX = (int(InvGuiScale * mouseX) - int(InvGuiScale * Minecraft::width) / 2 + 88 + 20) / 20;
int hotbarOffset = getNumSlots() * 20 / 2 - 2;
int slotX = (int(InvGuiScale * mouseX) - int(InvGuiScale * Minecraft::width) / 2 + hotbarOffset + 20) / 20;
//@NOTE: Why not just -88?
if (slotX >= 0)
slotX--;
if (slotX > 8)
if (slotX > getNumSlots())
slotX = -1;
return slotX;
@@ -368,16 +437,10 @@ void Gui::handleClick(int clickID, int mouseX, int mouseY)
if (slot == -1)
return;
#ifndef ENH_ENABLE_9TH_SLOT
if (slot == 8)
{
if (m_pMinecraft->isTouchscreen() && slot == getNumSlots() - 1)
m_pMinecraft->setScreen(new IngameBlockSelectionScreen);
}
else
#endif
{
m_pMinecraft->m_pLocalPlayer->m_pInventory->selectSlot(slot);
}
}
void Gui::handleKeyPressed(int keyCode)
@@ -387,17 +450,16 @@ void Gui::handleKeyPressed(int keyCode)
m_pMinecraft->setScreen(new IngameBlockSelectionScreen);
return;
}
int maxItems = getNumSlots() - 1;
if (m_pMinecraft->isTouchscreen())
maxItems--;
if (m_pMinecraft->getOptions()->isKey(KM_SLOT_R, keyCode))
{
int* slot = &m_pMinecraft->m_pLocalPlayer->m_pInventory->m_SelectedHotbarSlot;
#ifdef ENH_ENABLE_9TH_SLOT
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 2)
#else
#define MAX_ITEMS (C_MAX_HOTBAR_ITEMS - 3)
#endif
//@HUH: for whatever reason, it ignores the 7th item
if (*slot <= MAX_ITEMS)
if (*slot <= maxItems)
(*slot)++;
return;
@@ -465,3 +527,22 @@ void Gui::renderMessages(bool bShowAll)
glDisable(GL_BLEND);
}
int Gui::getNumSlots()
{
if (m_pMinecraft->isTouchscreen())
return 4;
return 9;
}
RectangleArea Gui::getRectangleArea(bool b)
{
float centerX = Minecraft::width / 2;
float hotbarWidthHalf = (10 * getNumSlots() + 5) / InvGuiScale;
return RectangleArea(
b ? (centerX - hotbarWidthHalf) : 0,
Minecraft::height - 24.0f / InvGuiScale,
centerX + hotbarWidthHalf,
Minecraft::height);
}

View File

@@ -9,6 +9,7 @@
#pragma once
#include "GuiComponent.hpp"
#include "client/player/input/RectangleArea.hpp"
#include "client/app/Minecraft.hpp"
#include "common/Random.hpp"
#include "common/Utils.hpp"
@@ -41,6 +42,8 @@ public:
void handleClick(int id, int mx, int my);
void handleKeyPressed(int keyCode);
void renderMessages(bool bShowAll);
int getNumSlots();
RectangleArea getRectangleArea(bool b);
public:
static float InvGuiScale;

View File

@@ -97,7 +97,7 @@ void RolledSelectionList::render(int mouseX, int mouseY, float f)
int nItems = getNumberOfItems();
// @TODO: fix gotos.
if (!Mouse::isButtonDown(1))
if (!Mouse::isButtonDown(BUTTON_LEFT))
{
if (field_28 < 0)
{

View File

@@ -81,7 +81,7 @@ void ScrolledSelectionList::render(int mouseX, int mouseY, float f)
renderBackground();
int nItems = getNumberOfItems();
if (Mouse::isButtonDown(1))
if (Mouse::isButtonDown(BUTTON_LEFT))
{
if (float(mouseY) >= field_C && float(mouseY) <= field_10 && mouseY != field_28)
{

View File

@@ -46,7 +46,7 @@ void WorldSelectionList::tick()
{
RolledSelectionList::tick();
field_D0++;
if (Mouse::isButtonDown(1) || !field_28)
if (Mouse::isButtonDown(BUTTON_LEFT) || !field_28)
return;
m_selectedIndex = -1;

View File

@@ -7,6 +7,7 @@
********************************************************************/
#include "IngameBlockSelectionScreen.hpp"
#include "client/app/Minecraft.hpp"
#include "client/renderer/entity/ItemRenderer.hpp"
std::string g_sNotAvailableInDemoVersion = "Not available in the demo version";
@@ -178,7 +179,7 @@ void IngameBlockSelectionScreen::selectSlotAndClose()
{
Inventory* pInv = getInventory();
pInv->selectItem(m_selectedSlot);
pInv->selectItem(m_selectedSlot, m_pMinecraft->m_gui.getNumSlots());
m_pMinecraft->m_pSoundEngine->play("random.click");
m_pMinecraft->setScreen(nullptr);

View File

@@ -43,11 +43,11 @@ OptionsScreen::OptionsScreen()
{
}
#ifndef ORIGINAL_CODE
static std::string BoolOptionStr(bool b)
{
return b ? "ON" : "OFF";
}
static std::string ViewDistanceStr(int dist)
{
switch (dist)
@@ -66,7 +66,7 @@ static std::string ViewDistanceStr(int dist)
}
}
void OptionsScreen::UpdateTexts()
void OptionsScreen::updateTexts()
{
Options& o = *(m_pMinecraft->getOptions());
@@ -78,20 +78,62 @@ void OptionsScreen::UpdateTexts()
m_flightHaxButton.m_text = "Flight hax: " + BoolOptionStr(o.m_bFlyCheat);
m_autoJumpButton.m_text = "Auto Jump: " + BoolOptionStr(o.m_bAutoJump);
m_viewDistButton.m_text = "View distance: " + ViewDistanceStr(o.m_iViewDistance);
m_srvVisButton.m_text = "Server " + std::string(o.m_bServerVisibleDefault ? "visible" : "invisible") + " by default";
m_blockLinesButton.m_text = "Block outlines: " + BoolOptionStr(o.m_bBlockOutlines);
if (!isCramped())
m_srvVisButton.m_text = "Server " + std::string(o.m_bServerVisibleDefault ? "visible" : "invisible") + " by default";
else
m_srvVisButton.m_text = "Server " + std::string(o.m_bServerVisibleDefault ? "visible" : "invisible");
}
bool OptionsScreen::isCramped()
{
return m_width < 150 * 2 + 20 || m_height < 200;
}
void OptionsScreen::setWidthAllButtons(int width)
{
m_AOButton.m_width =
m_srvVisButton.m_width =
m_fancyGfxButton.m_width =
m_viewDistButton.m_width =
m_blockLinesButton.m_width =
m_invertYButton.m_width =
m_anaglyphsButton.m_width =
m_viewBobButton.m_width =
m_flightHaxButton.m_width =
m_autoJumpButton.m_width = width;
}
#endif
void OptionsScreen::init()
{
m_pMinecraft->platform()->showDialog(AppPlatform::DLG_OPTIONS);
m_pMinecraft->platform()->createUserInput();
#ifndef ORIGINAL_CODE
bool crampedMode = isCramped();
int incrementY = 25;
int yPos = 40;
int backGap = 12;
// If the screen's width can't fit two buttons and a small amount of padding,
// consider ourselves cramped.
if (crampedMode)
{
crampedMode = true;
incrementY = 22;
yPos = 20;
backGap = 5;
setWidthAllButtons(125);
}
else
{
// Initialize the default buttons' widths.
setWidthAllButtons(150);
}
m_BackButton.m_xPos = m_width / 2 - m_BackButton.m_width / 2;
m_BackButton.m_yPos = m_height - 33;
m_BackButton.m_height = 20;
m_BackButton.m_yPos = m_height - m_BackButton.m_height - backGap;
m_buttons.push_back(&m_BackButton);
m_AOButton.m_xPos =
@@ -106,12 +148,11 @@ void OptionsScreen::init()
m_flightHaxButton.m_xPos =
m_autoJumpButton.m_xPos = m_width / 2 + 5;
int yPos = 40;
m_AOButton.m_yPos = m_invertYButton.m_yPos = yPos; yPos += 25;
m_srvVisButton.m_yPos = m_anaglyphsButton.m_yPos = yPos; yPos += 25;
m_fancyGfxButton.m_yPos = m_viewBobButton.m_yPos = yPos; yPos += 25;
m_viewDistButton.m_yPos = m_flightHaxButton.m_yPos = yPos; yPos += 25;
m_autoJumpButton.m_yPos = m_blockLinesButton.m_yPos = yPos; yPos += 25;
m_AOButton.m_yPos = m_invertYButton.m_yPos = yPos; yPos += incrementY;
m_srvVisButton.m_yPos = m_anaglyphsButton.m_yPos = yPos; yPos += incrementY;
m_fancyGfxButton.m_yPos = m_viewBobButton.m_yPos = yPos; yPos += incrementY;
m_viewDistButton.m_yPos = m_flightHaxButton.m_yPos = yPos; yPos += incrementY;
m_autoJumpButton.m_yPos = m_blockLinesButton.m_yPos = yPos; yPos += incrementY;
m_buttons.push_back(&m_AOButton);
m_buttons.push_back(&m_srvVisButton);
@@ -137,12 +178,11 @@ void OptionsScreen::init()
m_buttonTabList.push_back(&m_BackButton);
UpdateTexts();
updateTexts();
#ifdef __EMSCRIPTEN__
m_srvVisButton.m_bEnabled = false;
#endif
#endif
}
void OptionsScreen::render(int a, int b, float c)
@@ -158,7 +198,7 @@ void OptionsScreen::render(int a, int b, float c)
}
#ifndef ORIGINAL_CODE
drawCenteredString(m_pFont, "Options", m_width / 2, 20, 0xFFFFFF);
drawCenteredString(m_pFont, "Options", m_width / 2, isCramped() ? 5 : 20, 0xFFFFFF);
Screen::render(a, b, c);
#endif
@@ -188,17 +228,17 @@ void OptionsScreen::buttonClicked(Button* pButton)
o.m_bAmbientOcclusion = !o.m_bAmbientOcclusion;
Minecraft::useAmbientOcclusion = o.m_bAmbientOcclusion;
m_pMinecraft->m_pLevelRenderer->allChanged();
UpdateTexts();
updateTexts();
return;
case OB_FANCY_GFX:
o.m_bFancyGraphics ^= 1;
m_pMinecraft->m_pLevelRenderer->allChanged();
UpdateTexts();
updateTexts();
return;
case OB_VIEW_DIST:
// @TODO: fix the 'extreme' render distance
o.m_iViewDistance = (o.m_iViewDistance + 1) % 4;
UpdateTexts();
updateTexts();
return;
case OB_ANAGLYPHS:
@@ -228,7 +268,7 @@ void OptionsScreen::buttonClicked(Button* pButton)
return;
*pOption = !(*pOption);
UpdateTexts();
updateTexts();
}
#endif

View File

@@ -21,7 +21,9 @@ public:
#ifndef ORIGINAL_CODE
void buttonClicked(Button* pButton) override;
void UpdateTexts();
void setWidthAllButtons(int width);
void updateTexts();
bool isCramped();
private:
Button m_BackButton;

View File

@@ -45,7 +45,7 @@ void SelectWorldScreen::init()
m_buttons.push_back(&m_btnBack);
m_buttons.push_back(&m_btnDelete);
field_12C = Mouse::getButtonState(Mouse::NONE) == Mouse::UP;
field_12C = Mouse::getButtonState(BUTTON_LEFT);
m_buttonTabList.push_back(&m_btnUnknown);
m_buttonTabList.push_back(&m_btnDelete);
@@ -173,7 +173,7 @@ void SelectWorldScreen::render(int mouseX, int mouseY, float f)
else
{
m_pWorldSelectionList->render(0, 0, f);
field_12C = Mouse::getButtonState(Mouse::LEFT) == Mouse::UP;
field_12C = Mouse::getButtonState(BUTTON_LEFT);
}
Screen::render(mouseX, mouseY, f);

View File

@@ -337,7 +337,6 @@ StartMenuScreen::StartMenuScreen() :
m_optionsButton(4, 0, 0, 78, 22, "Options"),
m_testButton (999, 0, 0, 78, 22, "Test"),
m_buyButton (5, 0, 0, 78, 22, "Buy")
//, m_testBox(1, 10, 10, 200, 16, "Insert some text...")
{
m_chosenSplash = -1;
}
@@ -466,9 +465,11 @@ void StartMenuScreen::render(int a, int b, float c)
int id = tx->loadTexture("gui/title.png", true);
Texture *pTex = tx->getTemporaryTextureData(id);
//const int titleYPos = 4;
//const int titleYPos = 30; // -- MC Java position
const int titleYPos = 15;
//int titleYPos = 4;
//int titleYPos = 30; // -- MC Java position
int titleYPos = 15;
bool crampedMode = false;
if (pTex)
{
@@ -482,6 +483,12 @@ void StartMenuScreen::render(int a, int b, float c)
int width = pTex->m_width;
int height = pTex->m_height;
if (m_width * 3 / 4 < width)
{
crampedMode = true;
titleYPos = 4;
}
Tesselator& t = Tesselator::instance;
glColor4f(1, 1, 1, 1);
t.begin();
@@ -495,12 +502,26 @@ void StartMenuScreen::render(int a, int b, float c)
drawString(m_pFont, field_170, field_188, 58 + titleYPos, 0xFFCCCCCC);
drawString(m_pFont, field_154, field_16C, m_height - 10, 0x00FFFFFF);
// Draw the splash text.
// Draw the splash text, if we have enough room.
if (!crampedMode)
drawSplash();
Screen::render(a, b, c);
}
void StartMenuScreen::tick()
{
Screen::tick();
_updateLicense();
}
void StartMenuScreen::drawSplash()
{
glPushMatrix();
std::string splashText = getSplashString();
int textWidth = m_pFont->width(splashText);
//int textHeight = m_pFont->height(splashText);
int textWidth = m_pFont->width(splashText);
//int textHeight = m_pFont->height(splashText);
glTranslatef(float(m_width) / 2.0f + 90.0f, 70.0f, 0.0f);
glRotatef(-20.0f, 0.0f, 0.0f, 1.0f);
@@ -513,21 +534,6 @@ void StartMenuScreen::render(int a, int b, float c)
drawCenteredString(m_pFont, splashText, 0, -8, 0xFFFF00);
glPopMatrix();
// for debugging
/*
m_pMinecraft->m_pTextures->loadAndBindTexture(C_TERRAIN_NAME);
glColor4f(1, 1, 1, 1);
blit(0, 0, 0, 0, 256, 256, 0, 0);
*/
Screen::render(a, b, c);
}
void StartMenuScreen::tick()
{
Screen::tick();
_updateLicense();
}
std::string StartMenuScreen::getSplashString()

View File

@@ -22,6 +22,8 @@ public:
void render(int, int, float) override;
void tick() override;
void drawSplash();
std::string getSplashString();
private:

View File

@@ -361,7 +361,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlayerE
return;
}
pPlayer->m_pInventory->selectItemById(pPlayerEquipmentPkt->m_itemID);
pPlayer->m_pInventory->selectItemById(pPlayerEquipmentPkt->m_itemID, C_MAX_HOTBAR_ITEMS);
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, LevelDataPacket* packet)

View File

@@ -50,12 +50,12 @@ void Options::_initDefaultValues()
m_bViewBobbing = 1;
m_bAutoJump = true;
m_bFancyGraphics = true;
field_19 = 1;
field_1C = "Default";
m_playerName = "Steve";
m_bServerVisibleDefault = true;
m_bDebugText = false;
m_bBlockOutlines = false;
field_19 = 1;
// Win32 key codes are being used by default
#define KM(idx, name, code) m_keyMappings[idx] = KeyMapping(name, code)

View File

@@ -108,7 +108,7 @@ public:
uint8_t field_16;
bool m_bFancyGraphics;
bool m_bAmbientOcclusion;
uint8_t field_19;
uint8_t field_19; // use Mouse as input for breaking
std::string field_1C;
KeyMapping m_keyMappings[KM_COUNT];
int field_238;

View File

@@ -0,0 +1,47 @@
/********************************************************************
ReMinecraftPE
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#pragma once
enum eBuildActionIntent
{
INTENT_CLICKED = 1, // touch screen was clicked
INTENT_HELD = 2, // touch screen is being held down
INTENT_FIRST_REMOVE = 10, // after a small delay, starts breaking with this as a signal
};
class BuildActionIntention
{
public:
BuildActionIntention() : m_type(0) {}
BuildActionIntention(int type) : m_type(type) {}
bool isAttack() const {
return m_type == INTENT_CLICKED;
}
bool isFirstRemove() const {
return m_type == INTENT_FIRST_REMOVE;
}
bool isInteract() const {
return m_type == INTENT_HELD;
}
bool isRemove() const {
return isFirstRemove() || isRemoveContinue();
}
bool isRemoveContinue() const {
return m_type == INTENT_HELD;
}
private:
int m_type;
};

View File

@@ -20,7 +20,7 @@ ControllerTurnInput::ControllerTurnInput()
field_18 = false;
}
ITurnInput::Delta ControllerTurnInput::getTurnDelta()
TurnDelta ControllerTurnInput::getTurnDelta()
{
bool isTouched = Controller::isTouched(m_stickNo);
float deltaX, deltaY;
@@ -129,5 +129,10 @@ ITurnInput::Delta ControllerTurnInput::getTurnDelta()
}
field_18 = isTouched;
return Delta(deltaX, deltaY);
return TurnDelta(deltaX, deltaY);
}
bool ControllerTurnInput::smoothTurning()
{
return true;
}

View File

@@ -14,7 +14,8 @@ class ControllerTurnInput : public ITurnInput
{
public:
ControllerTurnInput();
ITurnInput::Delta getTurnDelta();
TurnDelta getTurnDelta() override;
bool smoothTurning() override;
private:
int field_8;

View File

@@ -0,0 +1,36 @@
/********************************************************************
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 "CustomInputHolder.hpp"
CustomInputHolder::CustomInputHolder(IMoveInput* pMoveInput, ITurnInput* pTurnInput, IBuildInput* pBuildInput)
{
setInputs(pMoveInput, pTurnInput, pBuildInput);
}
IMoveInput* CustomInputHolder::getMoveInput()
{
return m_pMoveInput;
}
ITurnInput* CustomInputHolder::getTurnInput()
{
return m_pTurnInput;
}
IBuildInput* CustomInputHolder::getBuildInput()
{
return m_pBuildInput;
}
void CustomInputHolder::setInputs(IMoveInput* pMoveInput, ITurnInput* pTurnInput, IBuildInput* pBuildInput)
{
m_pMoveInput = pMoveInput;
m_pTurnInput = pTurnInput;
m_pBuildInput = pBuildInput;
}

View File

@@ -0,0 +1,30 @@
/********************************************************************
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 "IInputHolder.hpp"
class CustomInputHolder : public IInputHolder
{
public:
CustomInputHolder(IMoveInput*, ITurnInput*, IBuildInput*);
IMoveInput* getMoveInput() override;
ITurnInput* getTurnInput() override;
IBuildInput* getBuildInput() override;
void setInputs(IMoveInput*, ITurnInput*, IBuildInput*);
private:
IMoveInput* m_pMoveInput;
ITurnInput* m_pTurnInput;
IBuildInput* m_pBuildInput;
};

View File

@@ -0,0 +1,20 @@
/********************************************************************
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
class IArea
{
public:
IArea() : field_4(true) {}
virtual bool isInside(float, float) = 0;
public:
bool field_4; // could this mean something like "was allocated via new()"?
};

View File

@@ -0,0 +1,14 @@
#include "IBuildInput.hpp"
IBuildInput::~IBuildInput()
{
}
void IBuildInput::setScreenSize(int width, int height)
{
}
bool IBuildInput::tickBuild(Player* pPlayer, BuildActionIntention* pIntention)
{
return false;
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include "BuildActionIntention.hpp"
class Player;
class IBuildInput
{
public:
virtual ~IBuildInput();
virtual void setScreenSize(int width, int height);
virtual bool tickBuild(Player*, BuildActionIntention*);
};

View File

@@ -0,0 +1,34 @@
/********************************************************************
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 "IInputHolder.hpp"
#include "Mouse.hpp"
IInputHolder::IInputHolder() :
m_feedbackX(0),
m_feedbackY(0)
{
}
IInputHolder::~IInputHolder()
{
}
bool IInputHolder::allowPicking()
{
m_feedbackX = float(Mouse::getX());
m_feedbackY = float(Mouse::getY());
return Mouse::getButtonState(BUTTON_LEFT);
}
void IInputHolder::setScreenSize(int width, int height)
{
getMoveInput()->setScreenSize(width, height);
getTurnInput()->setScreenSize(width, height);
getBuildInput()->setScreenSize(width, height);
}

View File

@@ -0,0 +1,34 @@
/********************************************************************
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 "IMoveInput.hpp"
#include "ITurnInput.hpp"
#include "IBuildInput.hpp"
class IInputHolder
{
public:
IInputHolder();
virtual ~IInputHolder();
virtual bool allowPicking();
virtual void setScreenSize(int width, int height);
virtual IMoveInput* getMoveInput() = 0;
virtual ITurnInput* getTurnInput() = 0;
virtual IBuildInput* getBuildInput() = 0;
protected:
friend class UnifiedTurnBuild;
friend class GameRenderer;
friend class Gui;
float m_feedbackX;
float m_feedbackY;
float m_feedbackAlpha;
};

View File

@@ -0,0 +1,42 @@
/********************************************************************
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 "IMoveInput.hpp"
IMoveInput::IMoveInput() :
m_horzInput(0.0f),
m_vertInput(0.0f),
field_C(false),
m_bJumpButton(false),
m_bSneakButton(false)
{
}
IMoveInput::~IMoveInput()
{
}
void IMoveInput::releaseAllKeys()
{
}
void IMoveInput::render(float f)
{
}
void IMoveInput::setKey(int key, bool state)
{
}
void IMoveInput::setScreenSize(int width, int height)
{
}
void IMoveInput::tick(Player* pPlayer)
{
}

View File

@@ -0,0 +1,42 @@
/********************************************************************
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
class Player;
enum
{
INPUT_FORWARD,
INPUT_BACKWARD,
INPUT_LEFT,
INPUT_RIGHT,
INPUT_JUMP,
INPUT_SNEAK,
};
class IMoveInput
{
public:
IMoveInput();
virtual ~IMoveInput();
virtual void releaseAllKeys();
virtual void render(float f);
virtual void setKey(int key, bool state);
virtual void setScreenSize(int width, int height);
virtual void tick(Player*);
public:
float m_horzInput;
float m_vertInput;
bool field_C;
bool m_bJumpButton;
bool m_bSneakButton;
};

View File

@@ -0,0 +1,23 @@
/********************************************************************
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 "ITouchScreenModel.hpp"
ITouchScreenModel::~ITouchScreenModel()
{
}
int ITouchScreenModel::getPointerId(const MouseAction& action)
{
return action._fingerId;
}
int ITouchScreenModel::getPointerId(int x, int y, int pointerId)
{
return pointerId;
}

View File

@@ -0,0 +1,20 @@
/********************************************************************
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 "MouseDevice.hpp"
class ITouchScreenModel
{
public:
virtual ~ITouchScreenModel();
virtual int getPointerId(const MouseAction&);
virtual int getPointerId(int x, int y, int pointerId);
};

View File

@@ -9,6 +9,19 @@
#include "common/Utils.hpp"
#include "ITurnInput.hpp"
ITurnInput::~ITurnInput()
{
}
void ITurnInput::setScreenSize(int width, int height)
{
}
bool ITurnInput::smoothTurning()
{
return false;
}
float ITurnInput::getDeltaTime()
{
if (m_prevTime == -1.0f)
@@ -20,3 +33,24 @@ float ITurnInput::getDeltaTime()
return delta;
}
// @TODO: Where does the a1 parameter come from? It's not `this` because it's used
// directly as a float. Its mangled name is _ZN10ITurnInput15linearTransformEfffb
float ITurnInput::linearTransform(float a1, float a2, float a3, bool a4)
{
float v1;
if (a1 < 0.0f)
v1 = -a2;
else
v1 = a2;
float v2 = abs(v1);
if (v2 >= abs(a1))
return 0.0f;
float v3 = (a1 - v1) * a3;
if (a4 && abs(v3) > 1.0f)
v3 /= abs(v3);
return v3;
}

View File

@@ -8,25 +8,28 @@
#pragma once
struct TurnDelta
{
float x, y;
TurnDelta() { x = 0.0f; y = 0.0f; }
TurnDelta(float x, float y) : x(x), y(y) {}
};
class ITurnInput
{
public:
struct Delta
{
float x, y;
Delta() { x = 0.0f; y = 0.0f; }
Delta(float x, float y) : x(x), y(y) {}
};
protected:
ITurnInput()
{
m_prevTime = -1.0f;
}
public:
float getDeltaTime();
float linearTransform(float, float, float, bool);
virtual ~ITurnInput();
virtual Delta getTurnDelta() = 0;
virtual void setScreenSize(int width, int height);
virtual TurnDelta getTurnDelta() = 0;
virtual bool smoothTurning();
private:
float m_prevTime;

View File

@@ -0,0 +1,104 @@
/********************************************************************
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 "IncludeExcludeArea.hpp"
IncludeExcludeArea::IncludeExcludeArea()
{
}
IncludeExcludeArea::~IncludeExcludeArea()
{
clear();
}
void IncludeExcludeArea::include(IArea* pArea)
{
m_include.push_back(pArea);
}
void IncludeExcludeArea::exclude(IArea* pArea)
{
m_exclude.push_back(pArea);
}
void IncludeExcludeArea::clear()
{
if (field_4)
{
for (int i = 0; i < int(m_include.size()); i++)
{
IArea* area = m_include[i];
// @BUG: Invalid access order! If m_include[i] is null (which,
// by the way, _really_ shouldn't be, then there will
// be a NULL dereference!
#ifdef ORIGINAL_CODE
if (area->field_4 && area)
#else
if (area && area->field_4)
#endif
{
delete area;
}
}
for (int i = 0; i < int(m_exclude.size()); i++)
{
IArea* area = m_exclude[i];
// @BUG: Same as the include bug.
#ifdef ORIGINAL_CODE
if (area->field_4 && area)
#else
if (area && area->field_4)
#endif
{
delete area;
}
}
}
m_include.clear();
m_exclude.clear();
}
bool IncludeExcludeArea::isInside(float x, float y)
{
// @NOTE: This could be done a lot easier. Here's a way:
// for (each area in m_exclude)
// if (area.isInside(x,y))
// return false;
// for (each area in m_include)
// if (area.isInside(x,y))
// return true;
// return false;
for (int i = 0; i < int(m_include.size()); i++)
{
IArea* includeArea = m_include[i];
if (!includeArea->isInside(x, y))
continue;
bool good = true;
for (int j = 0; j < int(m_exclude.size()); j++)
{
IArea* excludeArea = m_exclude[j];
if (excludeArea->isInside(x, y))
{
good = false;
break;
}
}
if (good)
return true;
}
return false;
}

View File

@@ -0,0 +1,29 @@
/********************************************************************
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 <vector>
#include "IArea.hpp"
class IncludeExcludeArea : public IArea
{
public:
IncludeExcludeArea();
~IncludeExcludeArea();
void include(IArea*);
void exclude(IArea*);
void clear();
bool isInside(float x, float y) override;
private:
std::vector<IArea*> m_include;
std::vector<IArea*> m_exclude;
};

View File

@@ -45,20 +45,20 @@ void KeyboardInput::setKey(int keyCode, bool b)
m_keys[index] = b;
}
void KeyboardInput::tick(/* Player* */)
void KeyboardInput::tick(Player* pPlayer)
{
m_horzInput = 0.0f;
m_vertInput = 0.0f;
if (m_keys[FORWARD]) m_vertInput += 1.0f;
if (m_keys[BACKWARD]) m_vertInput -= 1.0f;
if (m_keys[LEFT]) m_horzInput += 1.0f;
if (m_keys[RIGHT]) m_horzInput -= 1.0f;
if (m_keys[INPUT_FORWARD]) m_vertInput += 1.0f;
if (m_keys[INPUT_BACKWARD]) m_vertInput -= 1.0f;
if (m_keys[INPUT_LEFT]) m_horzInput += 1.0f;
if (m_keys[INPUT_RIGHT]) m_horzInput -= 1.0f;
m_bJumpButton = m_keys[JUMP];
m_bSneakButton = m_keys[SNEAK];
m_bJumpButton = m_keys[INPUT_JUMP];
m_bSneakButton = m_keys[INPUT_SNEAK];
if (m_keys[SNEAK])
if (m_keys[INPUT_SNEAK])
{
m_horzInput = m_horzInput * 0.3f;
m_vertInput = m_vertInput * 0.3f;

View File

@@ -8,34 +8,22 @@
#pragma once
#include "IMoveInput.hpp"
#include "client/options/Options.hpp"
class KeyboardInput
class KeyboardInput : public IMoveInput
{
public:
enum
{
FORWARD,
BACKWARD,
LEFT,
RIGHT,
JUMP,
SNEAK,
};
public:
KeyboardInput(Options*);
virtual void releaseAllKeys();
virtual void setKey(int index, bool b);
virtual void tick(/* Player* */);
void releaseAllKeys() override;
void setKey(int index, bool b) override;
void tick(Player*) override;
public:
float m_horzInput;
float m_vertInput ;
bool field_C;
bool m_bJumpButton;
bool m_bSneakButton;
bool m_keys[10];
Options* m_pOptions;
};

View File

@@ -9,95 +9,59 @@
#include "Mouse.hpp"
#include "common/Utils.hpp"
std::vector<MouseAction> Mouse::_inputs;
int Mouse::_index, Mouse::_x, Mouse::_y;
int Mouse::_xOld, Mouse::_yOld;
Mouse::ButtonState Mouse::_buttonStates[Mouse::COUNT];
MouseDevice Mouse::_instance;
void Mouse::feed(ButtonType buttonType, ButtonState buttonState, int posX, int posY)
void Mouse::feed(MouseButtonType buttonType, bool buttonState, int posX, int posY)
{
if (buttonType != NONE)
_inputs.push_back(MouseAction(buttonType, buttonState, posX, posY));
// Make sure button type is valid
if (buttonType < COUNT)
{
// Check if we're processing a button-state update
if (buttonType != NONE)
_buttonStates[buttonType] = buttonState;
_xOld = _x;
_yOld = _y;
_x = posX;
_y = posY;
}
_instance.feed(buttonType, buttonState, posX, posY);
}
short Mouse::getX()
{
return short(_x);
return _instance.getX();
}
short Mouse::getY()
{
return short(_y);
return _instance.getY();
}
bool Mouse::next()
{
if (_index + 1 >= _inputs.size())
return false;
_index++;
return true;
return _instance.next();
}
Mouse::ButtonType Mouse::getEventButton()
bool Mouse::isButtonDown(MouseButtonType btn)
{
return _inputs[_index]._buttonType;
return _instance.isButtonDown(btn);
}
bool Mouse::isButtonDown(int btn)
bool Mouse::getButtonState(MouseButtonType btn)
{
return _buttonStates[btn];
return _instance.getButtonState(btn);
}
bool Mouse::getEventButtonState()
{
return _instance.getEventButtonState();
}
void Mouse::reset()
{
_inputs.clear();
_index = -1;
}
MouseAction* Mouse::getEvent()
{
return &_inputs[_index];
}
Mouse::ButtonState Mouse::getButtonState(ButtonType btn)
{
if (btn < MIN || btn >= COUNT)
return UP;
return _buttonStates[btn];
}
void Mouse::setX(int x)
{
_x = x;
}
void Mouse::setY(int y)
{
_y = y;
_instance.reset();
}
void Mouse::reset2()
{
_xOld = _x;
_yOld = _y;
_instance.reset2();
}
Mouse::ButtonState Mouse::getEventButtonState()
MouseButtonType Mouse::getEventButton()
{
return _inputs[_index]._buttonState;
return _instance.getEventButton();
}
MouseAction* Mouse::getEvent()
{
return _instance.getEvent();
}

View File

@@ -10,82 +10,27 @@
#include <vector>
#include "MouseDevice.hpp"
struct MouseAction;
class Mouse
{
public:
enum ButtonType
{
NONE,
LEFT,
RIGHT,
MIDDLE,
COUNT,
SCROLLWHEEL,
MIN = LEFT,
};
enum ButtonState
{
UP,
DOWN,
};
static void feed(ButtonType buttonType, ButtonState buttonState, int posX, int posY);
static void feed(MouseButtonType buttonType, bool buttonState, int posX, int posY);
static short getX();
static short getY();
static bool next();
static bool isButtonDown(int btn);
static ButtonState getButtonState(ButtonType btn);
static ButtonType getEventButton();
static ButtonState getEventButtonState();
static MouseAction* getEvent();
static void setX(int x);
static void setY(int y);
static bool isButtonDown(MouseButtonType btn);
static bool getButtonState(MouseButtonType btn);
static bool getEventButtonState();
//static void setX(int x);
//static void setY(int y);
static void reset();
static void reset2();
// @TODO: There's plenty of inlined code here. Out-line it.
static MouseButtonType getEventButton();
static MouseAction* getEvent();
private:
static std::vector<MouseAction> _inputs;
static int _index;
static int _x, _y;
static int _xOld, _yOld;
static ButtonState _buttonStates[Mouse::COUNT];
};
struct MouseAction
{
Mouse::ButtonType _buttonType;
Mouse::ButtonState _buttonState;
int _posX;
int _posY;
MouseAction()
{
_buttonType = Mouse::NONE;
_buttonState = Mouse::UP;
_posX = 0;
_posY = 0;
}
MouseAction(Mouse::ButtonType buttonType, Mouse::ButtonState buttonState, int posX, int posY)
{
_buttonType = buttonType;
_buttonState = buttonState;
_posX = posX;
_posY = posY;
}
bool isButton()
{
return
_buttonType == Mouse::LEFT ||
_buttonType == Mouse::RIGHT ||
_buttonType == Mouse::MIDDLE;
}
static MouseDevice _instance;
};

View File

@@ -0,0 +1,97 @@
/********************************************************************
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 "MouseDevice.hpp"
void MouseDevice::feed(MouseButtonType buttonType, bool buttonState, int posX, int posY)
{
if (buttonType != BUTTON_NONE)
_inputs.push_back(MouseAction(buttonType, buttonState, posX, posY, 0));
// Make sure button type is valid
if (buttonType < BUTTON_COUNT)
{
// Check if we're processing a button-state update
if (buttonType != BUTTON_NONE)
_buttonStates[buttonType] = buttonState;
_xOld = _x;
_yOld = _y;
_x = posX;
_y = posY;
}
}
short MouseDevice::getX()
{
return short(_x);
}
short MouseDevice::getY()
{
return short(_y);
}
bool MouseDevice::next()
{
if (_index + 1 >= _inputs.size())
return false;
_index++;
return true;
}
MouseButtonType MouseDevice::getEventButton()
{
return _inputs[_index]._buttonType;
}
bool MouseDevice::isButtonDown(MouseButtonType btn)
{
return getButtonState(btn);
}
void MouseDevice::reset()
{
_inputs.clear();
_index = -1;
}
MouseAction* MouseDevice::getEvent()
{
return &_inputs[_index];
}
bool MouseDevice::getButtonState(MouseButtonType btn)
{
if (btn < BUTTON_MIN || btn >= BUTTON_COUNT)
return false;
return _buttonStates[btn];
}
/*
void MouseDevice::setX(int x)
{
_x = x;
}
void MouseDevice::setY(int y)
{
_y = y;
}
*/
void MouseDevice::reset2()
{
_xOld = _x;
_yOld = _y;
}
bool MouseDevice::getEventButtonState()
{
return _inputs[_index]._buttonState;
}

View File

@@ -0,0 +1,83 @@
/********************************************************************
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 <vector>
enum MouseButtonType
{
BUTTON_NONE,
BUTTON_LEFT,
BUTTON_RIGHT,
BUTTON_MIDDLE,
BUTTON_COUNT,
BUTTON_SCROLLWHEEL,
BUTTON_MIN = BUTTON_LEFT,
};
struct MouseAction
{
MouseButtonType _buttonType;
bool _buttonState;
int _posX;
int _posY;
int _fingerId;
MouseAction()
{
_buttonType = BUTTON_NONE;
_buttonState = 0;
_posX = 0;
_posY = 0;
_fingerId = 0;
}
MouseAction(MouseButtonType buttonType, bool buttonState, int posX, int posY, int fingerId)
{
_buttonType = buttonType;
_buttonState = buttonState;
_posX = posX;
_posY = posY;
_fingerId = fingerId;
}
bool isButton()
{
return
_buttonType == BUTTON_LEFT ||
_buttonType == BUTTON_RIGHT ||
_buttonType == BUTTON_MIDDLE;
}
};
class MouseDevice
{
public:
void feed(MouseButtonType buttonType, bool buttonState, int posX, int posY);
short getX();
short getY();
bool next();
bool isButtonDown(MouseButtonType btn);
bool getButtonState(MouseButtonType btn);
bool getEventButtonState();
//void setX(int x);
//void setY(int y);
void reset();
void reset2();
MouseButtonType getEventButton();
MouseAction* getEvent();
private:
int _index;
int _x, _y;
int _xOld, _yOld;
bool _buttonStates[BUTTON_COUNT];
std::vector<MouseAction> _inputs;
};

View File

@@ -0,0 +1,34 @@
#include "MouseHandler.hpp"
MouseHandler::MouseHandler() :
m_pTurnInput(nullptr)
{
}
void MouseHandler::setTurnInput(ITurnInput* pTurnInput)
{
m_pTurnInput = pTurnInput;
}
void MouseHandler::grab()
{
m_delta = TurnDelta();
}
void MouseHandler::poll()
{
if (m_pTurnInput)
m_delta = m_pTurnInput->getTurnDelta();
}
void MouseHandler::release()
{
}
bool MouseHandler::smoothTurning()
{
if (!m_pTurnInput)
return false;
return m_pTurnInput->smoothTurning();
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "ITurnInput.hpp"
class MouseHandler
{
public:
MouseHandler();
void setTurnInput(ITurnInput*);
void grab();
void poll();
void release();
bool smoothTurning();
public:
TurnDelta m_delta;
ITurnInput* m_pTurnInput;
};

View File

@@ -17,17 +17,13 @@ MouseTurnInput::MouseTurnInput(Minecraft* pMC)
m_lastX = m_lastY = -1;
}
ITurnInput::~ITurnInput()
{
}
ITurnInput::Delta MouseTurnInput::getTurnDelta()
TurnDelta MouseTurnInput::getTurnDelta()
{
int deltaX = 0, deltaY = 0;
m_pMinecraft->platform()->getMouseDiff(deltaX, deltaY);
m_pMinecraft->platform()->clearDiff();
Delta d;
TurnDelta d;
d.x = C_SENSITIVITY * deltaX;
d.y = C_SENSITIVITY * deltaY;

View File

@@ -16,7 +16,7 @@ class MouseTurnInput : public ITurnInput
{
public:
MouseTurnInput(Minecraft*);
Delta getTurnDelta() override;
TurnDelta getTurnDelta() override;
private:
int m_lastX;

View File

@@ -0,0 +1,167 @@
/********************************************************************
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 "Multitouch.hpp"
int Multitouch::_activePointerCount;
int Multitouch::_activePointerList[MAX_TOUCHES];
int Multitouch::_index = -1;
bool Multitouch::_wasPressed[MAX_TOUCHES];
bool Multitouch::_wasReleased[MAX_TOUCHES];
bool Multitouch::_wasPressedThisUpdate[MAX_TOUCHES];
bool Multitouch::_wasReleasedThisUpdate[MAX_TOUCHES];
MouseDevice Multitouch::_pointers[MAX_TOUCHES];
std::vector<MouseAction> Multitouch::_inputs;
int Multitouch::_clampPointerId(int Id)
{
if (Id < 0)
return Id; //! @BUG
if (Id >= MAX_TOUCHES)
return MAX_TOUCHES - 1;
return Id;
}
void Multitouch::commit()
{
_activePointerCount = 0;
for (int i = 0; i < MAX_TOUCHES; i++)
{
if (_pointers[i].isButtonDown(BUTTON_LEFT))
{
_activePointerList[_activePointerCount++] = i;
}
}
}
void Multitouch::feed(MouseButtonType a1, bool a2, int a3, int a4, int fingerId)
{
fingerId = _clampPointerId(fingerId);
MouseAction action(a1, a2, a3, a4, fingerId);
_inputs.push_back(action);
MouseDevice* pDevice = g(fingerId);
pDevice->feed(a1, a2, a3, a4);
if (a1)
{
if (a2)
{
_wasPressed[fingerId] = true;
_wasPressedThisUpdate[fingerId] = true;
}
else if (a2 == 0)
{
_wasReleased[fingerId] = true;
_wasReleasedThisUpdate[fingerId] = true;
}
}
}
MouseDevice* Multitouch::g(int Index)
{
return &_pointers[_clampPointerId(Index)];
}
int Multitouch::getActivePointerIds(const int** out)
{
*out = _activePointerList;
return _activePointerCount;
}
MouseAction* Multitouch::getEvent()
{
return &_inputs[_index];
}
int Multitouch::getFirstActivePointerIdEx()
{
for (int i = 0; i < MAX_TOUCHES; i++)
{
if (_pointers[i].isButtonDown(BUTTON_LEFT))
return i;
}
for (int i = 0; i < MAX_TOUCHES; i++)
{
if (_wasReleased[i])
return i;
}
return -1;
}
int Multitouch::getFirstActivePointerIdExThisUpdate()
{
for (int i = 0; i < MAX_TOUCHES; i++)
{
if (_pointers[i].isButtonDown(BUTTON_LEFT))
return i;
}
for (int i = 0; i < MAX_TOUCHES; i++)
{
if (_wasReleasedThisUpdate[i])
return i;
}
return -1;
}
int Multitouch::getX(int fingerId)
{
return g(fingerId)->getX();
}
int Multitouch::getY(int fingerId)
{
return g(fingerId)->getY();
}
bool Multitouch::isPressed(int fingerId)
{
return _wasPressed[_clampPointerId(fingerId)];
}
bool Multitouch::next()
{
if (_index + 1 >= _inputs.size())
return false;
_index++;
return true;
}
void Multitouch::reset()
{
_inputs.clear();
_index = -1;
for (int i = 0; i < MAX_TOUCHES; i++)
{
g(i)->reset();
_wasPressed[i] = 0;
_wasReleased[i] = 0;
}
}
void Multitouch::resetThisUpdate()
{
for (int i = 0; i < MAX_TOUCHES; i++)
{
_wasPressedThisUpdate[i] = 0;
_wasReleasedThisUpdate[i] = 0;
}
}
void Multitouch::rewind()
{
_index = -1;
}

View File

@@ -0,0 +1,50 @@
/********************************************************************
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 <vector>
#include "Mouse.hpp"
#include "MouseDevice.hpp"
#define MAX_TOUCHES (8)
struct MouseAction;
class MouseDevice;
class Multitouch
{
public:
static int _clampPointerId(int Id);
static void commit();
static void feed(MouseButtonType, bool state, int x, int y, int fingerId);
static MouseDevice* g(int Index);
static int getActivePointerIds(const int** out);
static MouseAction* getEvent();
static int getFirstActivePointerIdEx();
static int getFirstActivePointerIdExThisUpdate();
static int getX(int fingerId);
static int getY(int fingerId);
static bool isPressed(int fingerId);
static bool next();
static void reset();
static void resetThisUpdate();
static void rewind();
private:
static int _activePointerCount;
static int _activePointerList[MAX_TOUCHES];
static int _index;
static bool _wasPressed[MAX_TOUCHES];
static bool _wasReleased[MAX_TOUCHES];
static bool _wasPressedThisUpdate[MAX_TOUCHES];
static bool _wasReleasedThisUpdate[MAX_TOUCHES];
static MouseDevice _pointers[MAX_TOUCHES];
static std::vector<MouseAction> _inputs;
};

View File

@@ -0,0 +1,43 @@
#include "PolygonArea.hpp"
#include "common/Utils.hpp"
PolygonArea::PolygonArea(int count, const float* x, const float* y)
{
m_count = count;
m_xPos = new float[count];
m_yPos = new float[count];
for (int i = 0; i < count; i++)
{
m_xPos[i] = x[i];
m_yPos[i] = y[i];
}
}
PolygonArea::~PolygonArea()
{
SAFE_DELETE_ARRAY(m_xPos);
SAFE_DELETE_ARRAY(m_yPos);
}
bool PolygonArea::isInside(float x, float y)
{
bool result = false;
int idx = 0, idx2 = m_count - 1;
while (idx < m_count)
{
// horrible ass condition
if ((m_yPos[idx] <= y && m_yPos[idx2] > y || m_yPos[idx2] <= y && m_yPos[idx] > y)
&& ((((m_xPos[idx2] - m_xPos[idx]) * (y - m_yPos[idx]))
/ (m_yPos[idx2] - m_yPos[idx]))
+ m_xPos[idx]) > x)
{
result = !result;
}
idx2 = idx++;
}
return result;
}

View File

@@ -0,0 +1,26 @@
/********************************************************************
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 "IArea.hpp"
class PolygonArea : public IArea
{
public:
PolygonArea(int count, const float* x, const float* y);
~PolygonArea();
bool isInside(float x, float y) override;
public:
float* m_xPos;
float* m_yPos;
int m_count;
};

View File

@@ -0,0 +1,25 @@
/********************************************************************
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 "RectangleArea.hpp"
RectangleArea::RectangleArea(float _left, float _top, float _right, float _bottom) :
left(_left),
right(_right),
top(_top),
bottom(_bottom)
{
}
bool RectangleArea::isInside(float x, float y)
{
return left <= x &&
right >= x &&
top <= y &&
bottom >= y;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "IArea.hpp"
class RectangleArea : public IArea
{
public:
RectangleArea(float _left, float _right, float _top, float _bottom);
bool isInside(float x, float y) override;
protected:
friend class UnifiedTurnBuild;
float left;
float right;
float top;
float bottom;
};

View File

@@ -0,0 +1,54 @@
/********************************************************************
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 "TouchAreaModel.hpp"
TouchAreaModel::~TouchAreaModel()
{
clear();
}
int TouchAreaModel::getPointerId(const MouseAction& action)
{
return getPointerId(action._posX, action._posY, action._fingerId);
}
int TouchAreaModel::getPointerId(int x, int y, int pointerId)
{
// Yes, it explicitly uses .size() in the original
for (size_t i = 0; i < m_areas.size(); i++)
{
Area* pArea = m_areas[i];
if (pArea->m_pArea->isInside(float(x), float(y)))
return pArea->m_id;
}
return pointerId;
}
void TouchAreaModel::clear()
{
for (size_t i = 0; i < m_areas.size(); i++)
delete m_areas[i];
m_areas.clear();
}
void TouchAreaModel::addArea(int id, IArea* pArea)
{
Area* pTArea = new Area();
// NOTE: The original code first initializes the
// fields of the new Area instance to zero, and
// then sets them to these values.
// So we do the same here.
pTArea->m_pArea = pArea;
pTArea->m_id = id;
m_areas.push_back(pTArea);
}

View File

@@ -0,0 +1,37 @@
/********************************************************************
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 "ITouchScreenModel.hpp"
#include "IArea.hpp"
class TouchAreaModel : public ITouchScreenModel
{
public:
struct Area
{
IArea* m_pArea;
int m_id;
Area() : m_pArea(0), m_id(0) {}
};
public:
~TouchAreaModel();
int getPointerId(const MouseAction&) override;
int getPointerId(int x, int y, int pointerId) override;
void clear();
void addArea(int id, IArea* m_pArea);
private:
std::vector<Area*> m_areas;
};

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 "TouchInputHolder.hpp"
#include "Multitouch.hpp"
#include "client/app/Minecraft.hpp"
#include "client/options/Options.hpp"
TouchInputHolder::TouchInputHolder(Minecraft* pMinecraft, Options* pOptions) :
m_touchScreenInput(pMinecraft, pOptions),
m_unifiedTurnBuild(2, Minecraft::width, Minecraft::height, 200.0f, 1.05f, this),
m_pMinecraft(pMinecraft)
{
}
bool TouchInputHolder::allowPicking()
{
const int* ids;
int count = Multitouch::getActivePointerIds(&ids);
for (int i = 0; i < count; ++i)
{
int finger = ids[i];
float x = float(Multitouch::getX(finger));
float y = float(Multitouch::getY(finger));
if (m_unifiedTurnBuild.isInsideArea(x, y))
{
m_feedbackX = x;
m_feedbackY = y;
return true;
}
}
return false;
}
IMoveInput* TouchInputHolder::getMoveInput()
{
return &m_touchScreenInput;
}
ITurnInput* TouchInputHolder::getTurnInput()
{
return &m_unifiedTurnBuild;
}
IBuildInput* TouchInputHolder::getBuildInput()
{
return &m_unifiedTurnBuild;
}
void TouchInputHolder::setScreenSize(int width, int height)
{
m_touchScreenInput.setScreenSize(width, height);
m_unifiedTurnBuild.field_40 = m_touchScreenInput.getRectangleArea();
m_unifiedTurnBuild.field_58 = m_pMinecraft->m_gui.getRectangleArea(false);
m_unifiedTurnBuild.setScreenSize(width, height);
}

View File

@@ -0,0 +1,33 @@
/********************************************************************
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 "IInputHolder.hpp"
#include "TouchscreenInput_TestFps.hpp"
#include "UnifiedTurnBuild.hpp"
class Minecraft;
class Options;
class TouchInputHolder : public IInputHolder
{
public:
TouchInputHolder(Minecraft*, Options*);
bool allowPicking() override;
IMoveInput* getMoveInput() override;
ITurnInput* getTurnInput() override;
IBuildInput* getBuildInput() override;
void setScreenSize(int width, int height) override;
public:
TouchscreenInput_TestFps m_touchScreenInput;
UnifiedTurnBuild m_unifiedTurnBuild;
Minecraft* m_pMinecraft;
};

View File

@@ -0,0 +1,289 @@
/********************************************************************
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 "TouchscreenInput_TestFps.hpp"
#include "Multitouch.hpp"
#include "client/app/Minecraft.hpp"
#include "client/options/Options.hpp"
#include "world/entity/Player.hpp"
TouchscreenInput_TestFps::TouchscreenInput_TestFps(Minecraft* pMinecraft, Options* pOptions) :
m_rectArea(0.0f, 0.0f, 1.0f, 1.0f),
m_pOptions(pOptions),
field_40(false),
m_bJumpBeingHeld(false),
m_pMinecraft(pMinecraft),
m_pAreaLeft(nullptr),
m_pAreaRight(nullptr),
m_pAreaForward(nullptr),
m_pAreaBackward(nullptr),
m_pAreaJump(nullptr)
{
for (int i = 0; i < 10; i++)
field_30[i] = 0;
// Note! Only the first five button entries are used.
for (int i = 0; i < 8; i++)
field_6C[i] = 0;
setScreenSize(Minecraft::width, Minecraft::height);
}
void TouchscreenInput_TestFps::releaseAllKeys()
{
m_horzInput = 0.0f;
m_vertInput = 0.0f;
for (int i = 0; i < 5; i++)
field_6C[i] = false;
}
void TouchscreenInput_TestFps::setKey(int key, bool state)
{
}
static void CopyCoordinateArray(int count, float* xs, float* ys, float* xd, float* yd)
{
for (int i = 0; i < count; i++)
{
xd[i] = xs[i];
yd[i] = ys[i];
}
}
static void MultiplyCoordinateArray(int count, float* x, float* y, float xm, float ym)
{
for (int i = 0; i < count; i++)
{
x[i] *= xm;
y[i] *= ym;
}
}
static void AddCoordinateArray(int count, float* x, float* y, float xd, float yd)
{
for (int i = 0; i < count; i++)
{
x[i] += xd;
y[i] += yd;
}
}
static void TransformArray(int count, float* x1, float* y1, float* x2, float* y2, float xd, float yd, float xm, float ym)
{
CopyCoordinateArray(count, x1, y1, x2, y2);
MultiplyCoordinateArray(count, x2, y2, xm, ym);
AddCoordinateArray(count, x2, y2, xd, yd);
}
void TouchscreenInput_TestFps::setScreenSize(int width, int height)
{
m_touchAreaModel.clear();
float widthM = float(width) * 0.11f;
float heightM = float(height) * 0.18f;
float x1[4], y1[4], x2[4], y2[4];
x1[0] = 0.0f; x1[1] = widthM; x1[2] = widthM; x1[3] = 0.0f;
y1[0] = 0.0f; y1[1] = 0.0f; y1[2] = heightM; y1[3] = heightM;
x2[0] = 0.0f; x2[1] = 0.0f; x2[2] = 0.0f; x2[3] = 0.0f;
y2[0] = 0.0f; y2[1] = 0.0f; y2[2] = 0.0f; y2[3] = 0.0f;
float rx1, rx2, ry1, ry2;
float offX = 8.0f;
rx1 = 0.0f;
ry1 = height - 8.0f - heightM * 3.0f;
rx2 = widthM * 3.0f + 8.0f;
ry2 = ry1 + heightM * 3.0f;
m_rectArea = RectangleArea(rx1, ry1, rx2, ry2);
float middleX = offX + widthM;
float middleY = ry1 + heightM;
TransformArray(4, x1, y1, x2, y2, middleX, middleY - heightM, 1.0f, 1.0f);
m_pAreaForward = new PolygonArea(4, x2, y2);
m_touchAreaModel.addArea(100 + INPUT_FORWARD, m_pAreaForward);
TransformArray(4, x1, y1, x2, y2, middleX, middleY, 1.0f, 1.0f);
m_pAreaJump = new PolygonArea(4, x2, y2);
m_touchAreaModel.addArea(100 + INPUT_JUMP, m_pAreaJump);
TransformArray(4, x1, y1, x2, y2, middleX, middleY + heightM, 1.0f, 1.0f);
m_pAreaBackward = new PolygonArea(4, x2, y2);
m_touchAreaModel.addArea(100 + INPUT_BACKWARD, m_pAreaBackward);
TransformArray(4, x1, y1, x2, y2, middleX - widthM, ry1 + heightM, 1.0f, 1.0f);
m_pAreaLeft = new PolygonArea(4, x2, y2);
m_touchAreaModel.addArea(100 + INPUT_LEFT, m_pAreaLeft);
TransformArray(4, x1, y1, x2, y2, middleX + widthM, ry1 + heightM, 1.0f, 1.0f);
m_pAreaRight = new PolygonArea(4, x2, y2);
m_touchAreaModel.addArea(100 + INPUT_RIGHT, m_pAreaRight);
// NOTE: We are not leaking memory! Since by default IArea's constructor sets
// field_4 to true, TouchAreaModel owns the pointers, so when it's destroyed,
// so are these areas we allocated.
}
void TouchscreenInput_TestFps::tick(Player* pPlayer)
{
m_horzInput = 0.0f;
m_vertInput = 0.0f;
m_bJumpButton = false;
for (int i = 0; i < 5; i++)
field_6C[i] = false;
const int* activePointers;
int activePointerCount = Multitouch::getActivePointerIds(&activePointers);
bool bJumpPressed = false, bForwardPressed = false;
for (int i = 0; i < activePointerCount; i++)
{
int finger = activePointers[i];
int x = Multitouch::getX(finger);
int y = Multitouch::getY(finger);
int pointerId = m_touchAreaModel.getPointerId(x, y, finger);
if (pointerId > 99)
field_6C[pointerId - 100] = true;
if (pointerId == 100 + INPUT_SNEAK) // Unused
{
if (pPlayer->isInWater())
m_bJumpButton = true;
else
bJumpPressed = true;
pointerId = 100; // forward
}
if (pointerId == 100 + INPUT_JUMP) // jump
{
if (pPlayer->isInWater())
m_bJumpButton = true;
else if (Multitouch::isPressed(finger))
m_bJumpButton = true;
else if (field_40)
{
pointerId = 100; // forward
bJumpPressed = true;
m_vertInput += 1.0f;
}
}
switch (pointerId)
{
case 100 + INPUT_FORWARD:
if (pPlayer->isInWater())
m_bJumpButton = true;
else
bForwardPressed = true;
m_vertInput += 1.0f;
break;
case 100 + INPUT_BACKWARD:
m_vertInput -= 1.0f;
break;
case 100 + INPUT_LEFT:
m_horzInput += 1.0f;
break;
case 100 + INPUT_RIGHT:
m_horzInput -= 1.0f;
break;
}
}
field_40 = bForwardPressed;
if (bJumpPressed)
{
// Don't allow the player to hold jump to repeatedly jump.
// Only let them jump once - have them jump again
if (!m_bJumpBeingHeld)
m_bJumpButton = true;
m_bJumpBeingHeld = true;
}
else
{
m_bJumpBeingHeld = false;
}
}
static void RenderTouchButton(Tesselator* t, PolygonArea* pArea, int srcX, int srcY)
{
float tc[8];
tc[0] = float(srcX) / 256.0f;
tc[1] = float(srcY) / 256.0f;
tc[2] = tc[0] + 64.0f / 256.0f;
tc[3] = tc[1];
tc[4] = tc[2];
tc[5] = tc[1] + 64.0f / 256.0f;
tc[6] = tc[0];
tc[7] = tc[5];
for (int i = 0; i < pArea->m_count; i++)
{
t->vertexUV(
Gui::InvGuiScale * pArea->m_xPos[i],
Gui::InvGuiScale * pArea->m_yPos[i],
0.0f,
tc[(2 * i) % 8],
tc[(2 * i + 1) % 8]
);
}
}
void TouchscreenInput_TestFps::render(float f)
{
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
m_pMinecraft->m_pTextures->loadAndBindTexture("gui/gui.png");
Tesselator& t = Tesselator::instance;
t.begin();
t.color(isButtonDown(100 + INPUT_LEFT) ? 0xC0C0C0 : 0xFFFFFF, 0x80);
RenderTouchButton(&t, m_pAreaLeft, 64, 112);
t.color(isButtonDown(100 + INPUT_RIGHT) ? 0xC0C0C0 : 0xFFFFFF, 0x80);
RenderTouchButton(&t, m_pAreaRight, 192, 112);
t.color(isButtonDown(100 + INPUT_FORWARD) ? 0xC0C0C0 : 0xFFFFFF, 0x80);
RenderTouchButton(&t, m_pAreaForward, 0, 112);
t.color(isButtonDown(100 + INPUT_BACKWARD) ? 0xC0C0C0 : 0xFFFFFF, 0x80);
RenderTouchButton(&t, m_pAreaBackward, 128, 112);
t.color(isButtonDown(100 + INPUT_JUMP) ? 0xC0C0C0 : 0xFFFFFF, 0x80);
RenderTouchButton(&t, m_pAreaJump, 0, 176);
t.draw();
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
}
RectangleArea TouchscreenInput_TestFps::getRectangleArea()
{
return m_rectArea;
}
bool TouchscreenInput_TestFps::isButtonDown(int key)
{
return field_6C[key - 100];
}

View File

@@ -0,0 +1,50 @@
/********************************************************************
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 "IMoveInput.hpp"
#include "client/gui/GuiComponent.hpp"
#include "RectangleArea.hpp"
#include "PolygonArea.hpp"
#include "TouchAreaModel.hpp"
class Minecraft;
class Options;
class TouchscreenInput_TestFps : public IMoveInput, public GuiComponent
{
public:
TouchscreenInput_TestFps(Minecraft*, Options*);
// IMoveInput
void releaseAllKeys() override;
void setKey(int key, bool state) override;
void setScreenSize(int width, int height) override;
void tick(Player*) override;
void render(float f) override;
RectangleArea getRectangleArea();
bool isButtonDown(int key);
private:
RectangleArea m_rectArea;
bool field_30[10];
Options* m_pOptions;
bool field_40;
bool m_bJumpBeingHeld;
TouchAreaModel m_touchAreaModel;
Minecraft* m_pMinecraft;
PolygonArea* m_pAreaLeft;
PolygonArea* m_pAreaRight;
PolygonArea* m_pAreaForward;
PolygonArea* m_pAreaBackward;
PolygonArea* m_pAreaJump;
bool field_6C[8];
};

View File

@@ -0,0 +1,242 @@
/********************************************************************
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 "UnifiedTurnBuild.hpp"
#include "Multitouch.hpp"
#include "common/Utils.hpp"
#include "world/entity/Player.hpp"
UnifiedTurnBuild::UnifiedTurnBuild(int a, int width, int height, float d, float e, IInputHolder* pHolder) :
field_C(a),
field_10(0),
m_screenArea(-1, -1, 0, 0),
field_40(-1, -1, 0, 0),
field_58(-1, -1, 0, 0),
m_pInputHolder(pHolder),
field_78(0.0f),
field_7C(0.0f),
m_bWasTouched(false),
field_BC(0.0f),
field_C0(d),
field_C4(e),
m_pPlayer(nullptr),
field_D8(0)
{
m_includeExcludeArea.field_4 = false;
setScreenSize(width, height);
field_B8 = getTimeS();
field_CC = field_B8;
field_D0 = 0;
field_24 = 0;
field_D4 = false;
}
void UnifiedTurnBuild::setScreenSize(int width, int height)
{
m_screenArea = RectangleArea(0.0f, 0.0f, float(width), float(height));
field_40.right += 10.0f + 0.05f * (field_40.right - field_40.left);
field_40.top -= 10.0f + 0.05f * (field_40.bottom - field_40.top);
m_includeExcludeArea.clear();
m_includeExcludeArea.include(&m_screenArea);
m_includeExcludeArea.exclude(&field_40);
m_includeExcludeArea.exclude(&field_58);
m_touchAreaModel.clear();
m_touchAreaModel.addArea(100, &m_includeExcludeArea);
}
TurnDelta UnifiedTurnBuild::getTurnDelta()
{
float timeS = getTimeS();
float m1 = 0.0f, m2 = 0.0f;
float xd = 0.0f, yd = 0.0f;
bool touched = false;
const int* activePtrs;
int activePtrCount = Multitouch::getActivePointerIds(&activePtrs);
for (int i = 0; i < activePtrCount; i++)
{
int finger = activePtrs[i];
int x = Multitouch::getX(finger);
int y = Multitouch::getY(finger);
if (m_touchAreaModel.getPointerId(x, y, finger) == 100)
{
touched = true;
m1 = float(x) * 0.5f;
m2 = float(y) * -0.5f;
break;
}
}
if (touched && !m_bWasTouched) // if this is the first frame we were touched
{
field_B8 = timeS;
field_BC = 0.0f;
bool b2 = m_pPlayer && getSpeedSquared(m_pPlayer) > 0.01f;
field_D8 = 1;
field_D4 = !b2;
field_24 = 0;
}
else if (m_bWasTouched && !touched) // if that was the last frame we were touched
{
field_24 = 0;
field_D8 = 0;
}
if (field_C == 2 && (m_bWasTouched || touched))
{
// note: return value dropped
(void) getDeltaTime();
if (!m_bWasTouched)
{
field_78 = m1;
field_7C = m2;
}
if (touched)
{
xd = field_C4 * linearTransform(m1 - field_78, 0.0f, 1.0f, false);
yd = field_C4 * linearTransform(m2 - field_7C, 0.0f, 1.0f, false);
float c3 = abs(xd) * abs(yd);
if (field_C0 < c3)
c3 = yd = xd = 0.0f;
field_BC += c3;
if (field_D8 == 1 && field_BC >= 20.0f)
field_D8 = 2;
if (field_D8 == 1 && timeS - field_B8 >= 0.4f)
{
bool check = m_pPlayer && getSpeedSquared(m_pPlayer) > 0.01f;
if (field_BC > 20.0f || check)
field_D8 = 2;
else
field_D8 = 3;
}
if (field_D8 == 1)
{
xd = yd = 0.0f;
}
field_78 = m1;
field_7C = m2;
}
}
if (field_D4)
{
// Yes, again, this is what IDA gave me. It was either a switch that the compiler
// for some reason forgot to optimize into a jump table, or was actually an if chain.
// I believe it's the latter though because the build I'm reversing (0.1.1j) is unoptimized)
if (field_D8 == 1)
m_pInputHolder->m_feedbackAlpha = m_smoothFloat.getNewDeltaValue((timeS - field_B8) / 0.4f, 0.05f);
else if (field_D8 == 3)
m_pInputHolder->m_feedbackAlpha = m_smoothFloat.getNewDeltaValue(1.0f, 0.25f);
else if (field_D8 == 2)
m_pInputHolder->m_feedbackAlpha = m_smoothFloat.getNewDeltaValue(-0.05f, 0.5f);
else if (field_D8 == 0)
m_pInputHolder->m_feedbackAlpha = m_smoothFloat.getNewDeltaValue(-0.05f, 0.5f);
}
else
{
m_pInputHolder->m_feedbackAlpha = -0.05f;
}
m_bWasTouched = touched;
return TurnDelta(xd, -yd);
}
bool UnifiedTurnBuild::smoothTurning()
{
return true;
}
bool UnifiedTurnBuild::tickBuild(Player* pPlayer, BuildActionIntention* pIntention)
{
m_pPlayer = pPlayer;
if (field_D8 == 3)
{
if (field_24 != 1)
{
*pIntention = BuildActionIntention(INTENT_FIRST_REMOVE);
field_24 = 1;
}
else
{
*pIntention = BuildActionIntention(INTENT_HELD);
}
return true;
}
Multitouch::rewind();
float timeS = getTimeS();
field_10 = 0;
bool wroteIntention = false;
while (Multitouch::next())
{
MouseAction* pEvent = Multitouch::getEvent();
if (pEvent->_buttonType)
{
int finger = m_touchAreaModel.getPointerId(pEvent->_posX, pEvent->_posY, pEvent->_fingerId);
if (finger == 100)
{
if (field_BC > 20.0f || pEvent->_buttonState || wroteIntention)
{
if (pEvent->_buttonState)
{
field_CC = timeS;
field_D0 = 0;
field_D8 = 1;
}
}
else
{
float delta = timeS - field_CC;
if (field_D8 <= 1 && delta >= 0.0f && delta < 0.25f)
{
*pIntention = BuildActionIntention(INTENT_CLICKED);
wroteIntention = true;
}
field_D8 = 0;
}
}
}
}
return wroteIntention;
}
bool UnifiedTurnBuild::isInsideArea(float x, float y)
{
return m_includeExcludeArea.isInside(x, y);
}
float UnifiedTurnBuild::getSpeedSquared(Entity* pEnt)
{
return (pEnt->m_pos - pEnt->field_3C).lengthSqr();
}

View File

@@ -0,0 +1,62 @@
/********************************************************************
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 "ITurnInput.hpp"
#include "IBuildInput.hpp"
#include "IInputHolder.hpp"
#include "common/SmoothFloat.hpp"
#include "RectangleArea.hpp"
#include "IncludeExcludeArea.hpp"
#include "TouchAreaModel.hpp"
class Entity;
class UnifiedTurnBuild : public ITurnInput, public IBuildInput
{
public:
UnifiedTurnBuild(int, int width, int height, float, float, IInputHolder*);
// ITurnInput
void setScreenSize(int width, int height) override; // actually IBuildInput also has it
TurnDelta getTurnDelta() override;
bool smoothTurning() override;
// IBuildInput
bool tickBuild(Player*, BuildActionIntention*) override;
bool isInsideArea(float x, float y);
static float getSpeedSquared(Entity* pEnt);
public:
int field_C;
int field_10;
SmoothFloat m_smoothFloat;
int field_24;
RectangleArea m_screenArea;
RectangleArea field_40;
RectangleArea field_58;
IInputHolder* m_pInputHolder;
float field_78;
float field_7C;
bool m_bWasTouched;
TouchAreaModel m_touchAreaModel;
IncludeExcludeArea m_includeExcludeArea;
float field_B8;
float field_BC;
float field_C0;
float field_C4;
Entity* m_pPlayer;
float field_CC;
int field_D0;
bool field_D4;
int field_D8;
};

View File

@@ -9,8 +9,11 @@
#include "thirdparty/GL/GL.hpp"
#include "GameRenderer.hpp"
#include "client/app/Minecraft.hpp"
#include "client/player/input/Multitouch.hpp"
#include "Frustum.hpp"
#include "renderer/GL/GL.hpp"
static int t_keepHitResult; // that is its address in v0.1.1j
int t_keepPic;
void GameRenderer::_init()
@@ -534,62 +537,64 @@ void GameRenderer::render(float f)
if (m_pMinecraft->m_pLocalPlayer && m_pMinecraft->m_bGrabbedMouse)
{
Minecraft *pMC = m_pMinecraft;
ITurnInput::Delta delta = pMC->m_pTurnInput->getTurnDelta();
pMC->field_D20 = delta.x;
pMC->field_D24 = delta.y;
pMC->m_mouseHandler.poll();
#ifndef ENH_DISABLE_TURN_ACCEL
float multPitch = -1.0f;
float mult1 = 2.0f * (0.2f + pMC->getOptions()->field_8 * 0.6f);
mult1 = mult1 * mult1 * mult1;
float xd = 4.0f * mult1 * pMC->field_D20;
float yd = 4.0f * mult1 * pMC->field_D24;
float old_field_84 = field_84;
field_84 = float(m_rotX) + f;
float diff_field_84 = field_84 - old_field_84;
field_74 += xd;
field_78 += yd;
if (diff_field_84 > 3.0f)
diff_field_84 = 3.0f;
if (pMC->getOptions()->m_bInvertMouse)
multPitch = 1.0f;
if (!pMC->getOptions()->field_240)
float multPitch, diff_field_84;
if (pMC->m_mouseHandler.smoothTurning())
{
// @TODO: untangle this code
float v17 = xd + m_rotZ;
float v18 = field_18;
float v19 = field_1C;
m_rotZ = v17;
float v20 = mult1 * 0.25f * (v17 - v18);
float v21 = v19 + (v20 - v19) * 0.5f;
field_1C = v21;
if ((v20 <= 0.0 || v20 <= v21) && (v20 >= 0.0 || v20 >= v21))
v21 = mult1 * 0.25f * (v17 - v18);
float v22 = yd + field_20;
field_18 = v18 + v21;
float v23 = field_24;
field_20 = v22;
float v24 = mult1 * 0.15f * (v22 - v23);
float v25 = field_28 + (v24 - field_28) * 0.5f;
field_28 = v25;
if ((v24 <= 0.0 || v24 <= v25) && (v24 >= 0.0 || v24 >= v25))
v25 = v24;
field_24 = v23 + v25;
}
#else
float multPitch = -1.0f;
if (pMC->getOptions()->m_bInvertMouse)
multPitch = 1.0f;
multPitch = -1.0f;
float mult1 = 2.0f * (0.2f + pMC->getOptions()->field_8 * 0.6f);
mult1 = mult1 * mult1 * mult1;
float diff_field_84 = 1.0f;
field_7C = pMC->field_D20;
field_80 = pMC->field_D24;
#endif
float xd = 4.0f * mult1 * pMC->m_mouseHandler.m_delta.x;
float yd = 4.0f * mult1 * pMC->m_mouseHandler.m_delta.y;
float old_field_84 = field_84;
field_84 = float(field_C) + f;
diff_field_84 = field_84 - old_field_84;
field_74 += xd;
field_78 += yd;
if (diff_field_84 > 3.0f)
diff_field_84 = 3.0f;
if (pMC->getOptions()->m_bInvertMouse)
multPitch = 1.0f;
if (!pMC->getOptions()->field_240)
{
// @TODO: untangle this code
float v17 = xd + field_14;
float v18 = field_18;
float v19 = field_1C;
field_14 = v17;
float v20 = mult1 * 0.25f * (v17 - v18);
float v21 = v19 + (v20 - v19) * 0.5f;
field_1C = v21;
if ((v20 <= 0.0 || v20 <= v21) && (v20 >= 0.0 || v20 >= v21))
v21 = mult1 * 0.25f * (v17 - v18);
float v22 = yd + field_20;
field_18 = v18 + v21;
float v23 = field_24;
field_20 = v22;
float v24 = mult1 * 0.15f * (v22 - v23);
float v25 = field_28 + (v24 - field_28) * 0.5f;
field_28 = v25;
if ((v24 <= 0.0 || v24 <= v25) && (v24 >= 0.0 || v24 >= v25))
v25 = v24;
field_24 = v23 + v25;
}
}
else
{
multPitch = -1.0f;
if (pMC->getOptions()->m_bInvertMouse)
multPitch = 1.0f;
diff_field_84 = 1.0f;
field_7C = pMC->m_mouseHandler.m_delta.x;
field_80 = pMC->m_mouseHandler.m_delta.y;
}
pMC->m_pLocalPlayer->turn(diff_field_84 * field_7C, diff_field_84 * multPitch * field_80);
}
@@ -597,7 +602,20 @@ void GameRenderer::render(float f)
int mouseX = int(Mouse::getX() * Gui::InvGuiScale);
int mouseY = int(Mouse::getY() * Gui::InvGuiScale);
// note: Multitouch code here
if (m_pMinecraft->isTouchscreen())
{
int pointerId = Multitouch::getFirstActivePointerIdExThisUpdate();
if (pointerId < 0)
{
mouseX = -9999;
mouseY = -9999;
}
else
{
mouseX = int(float(Multitouch::getX(pointerId)) * Gui::InvGuiScale);
mouseY = int(float(Multitouch::getY(pointerId)) * Gui::InvGuiScale);
}
}
if (m_pMinecraft->isLevelGenerated())
{
@@ -623,6 +641,10 @@ void GameRenderer::render(float f)
setupGuiScreen();
}
if (m_pMinecraft->m_pLocalPlayer &&
m_pMinecraft->m_pLocalPlayer->m_pMoveInput)
m_pMinecraft->m_pLocalPlayer->m_pMoveInput->render(f);
if (m_pMinecraft->m_pScreen)
{
glClear(GL_ACCUM);
@@ -677,45 +699,54 @@ void GameRenderer::tick()
t_keepPic = -100;
#endif
if (m_pMinecraft->m_pLocalPlayer)
if (!m_pMinecraft->m_pLocalPlayer)
return;
if (--t_keepHitResult == 0)
m_pMinecraft->m_hitResult.m_hitType = HitResult::NONE;
#ifndef ORIGINAL_CODE
// Not harmless to let it underflow, but we won't anyway
if (t_keepHitResult < -100)
t_keepHitResult = -100;
#endif
float x1 = powf(fabsf(field_74), 1.2f);
field_7C = x1 * 0.4f;
if (field_74 < 0.0f)
field_7C = -field_7C;
float x2 = powf(fabsf(field_78), 1.2f);
field_80 = x2 * 0.4f;
if (field_78 < 0.0f)
field_80 = -field_80;
field_74 = 0.0f;
field_78 = 0.0f;
field_6C = field_70;
field_30 = field_2C;
field_38 = field_34;
field_40 = field_3C;
field_54 = field_50;
field_5C = field_58;
Mob* pMob = m_pMinecraft->m_pMobPersp;
if (!pMob)
{
float x1 = powf(fabsf(field_74), 1.2f);
field_7C = x1 * 0.4f;
if (field_74 < 0.0f)
field_7C = -field_7C;
float x2 = powf(fabsf(field_78), 1.2f);
field_80 = x2 * 0.4f;
if (field_78 < 0.0f)
field_80 = -field_80;
field_74 = 0.0f;
field_78 = 0.0f;
field_6C = field_70;
field_30 = field_2C;
field_38 = field_34;
field_40 = field_3C;
field_54 = field_50;
field_5C = field_58;
Mob* pMob = m_pMinecraft->m_pMobPersp;
if (!pMob)
{
pMob = m_pMinecraft->m_pMobPersp = m_pMinecraft->m_pLocalPlayer;
}
float bright = m_pMinecraft->m_pLevel->getBrightness(Mth::floor(pMob->m_pos.x), Mth::floor(pMob->m_pos.y), Mth::floor(pMob->m_pos.z));
float x3 = float(3 - m_pMinecraft->getOptions()->m_iViewDistance);
field_C++;
float x4 = x3 / 3.0f;
float x5 = (x4 + bright * (1.0f - x4) - field_70) * 0.1f;
field_70 += x5;
m_pItemInHandRenderer->tick();
pMob = m_pMinecraft->m_pMobPersp = m_pMinecraft->m_pLocalPlayer;
}
float bright = m_pMinecraft->m_pLevel->getBrightness(Mth::floor(pMob->m_pos.x), Mth::floor(pMob->m_pos.y), Mth::floor(pMob->m_pos.z));
float x3 = float(3 - m_pMinecraft->getOptions()->m_iViewDistance);
field_C++;
float x4 = x3 / 3.0f;
float x5 = (x4 + bright * (1.0f - x4) - field_70) * 0.1f;
field_70 += x5;
m_pItemInHandRenderer->tick();
}
void GameRenderer::renderItemInHand(float f, int i)
@@ -784,25 +815,95 @@ void GameRenderer::pick(float f)
if (!m_pMinecraft->m_pMobPersp || !m_pMinecraft->m_pLevel)
return;
HitResult& mchr = m_pMinecraft->m_hitResult;
Mob* pMob = m_pMinecraft->m_pMobPersp;
HitResult& mchr = m_pMinecraft->m_hitResult;
float dist = m_pMinecraft->m_pGameMode->getPickRange();
bool isFirstPerson = !m_pMinecraft->getOptions()->m_bThirdPerson;
HitResult hrMob = pMob->pick(dist, f);
mchr = hrMob;
if (m_pMinecraft->isTouchscreen())
{
Vec3 mobPos = pMob->getPos(f);
Vec3 foundPosNear, foundPosFar;
bool flag = true;
float offset = isFirstPerson ? 6.0f : 12.0f;
if (m_pMinecraft->m_pInputHolder->allowPicking())
{
int viewport[4] = { 0 };
viewport[2] = Minecraft::width;
viewport[3] = Minecraft::height;
float obj_coord[3] = { 0 };
if (glhUnProjectf(m_pMinecraft->m_pInputHolder->m_feedbackX,
Minecraft::height - m_pMinecraft->m_pInputHolder->m_feedbackY,
1.0f,
m_matrix_model_view,
m_matrix_projection,
viewport,
obj_coord))
{
foundPosFar = mobPos + Vec3(obj_coord[0], obj_coord[1], obj_coord[2]);
glhUnProjectf(m_pMinecraft->m_pInputHolder->m_feedbackX,
Minecraft::height - m_pMinecraft->m_pInputHolder->m_feedbackY,
0.0f,
m_matrix_model_view,
m_matrix_projection,
viewport,
obj_coord);
foundPosNear = mobPos + Vec3(obj_coord[0], obj_coord[1], obj_coord[2]);
Vec3 diff = foundPosFar - foundPosNear;
Vec3 normDiff = diff.normalize();
Vec3 normScaledDiff = normDiff.scale(offset);
mobPos = foundPosNear + normScaledDiff;
foundPosFar = mobPos;
}
// keep the hit result forever
t_keepHitResult = -1;
}
else
{
t_keepHitResult = 1; // keep the tick result for exactly one frame
flag = false;
}
if (flag)
{
if (isFirstPerson)
{
mchr = m_pMinecraft->m_pLevel->clip(foundPosNear, foundPosFar, false);
}
else
{
HitResult hr = m_pMinecraft->m_pLevel->clip(foundPosNear, foundPosFar, false);
float diffX = float(hr.m_tileX) - m_pMinecraft->m_pMobPersp->m_pos.x;
float diffY = float(hr.m_tileY) - m_pMinecraft->m_pMobPersp->m_pos.y;
float diffZ = float(hr.m_tileZ) - m_pMinecraft->m_pMobPersp->m_pos.z;
if (hr.m_hitType == HitResult::NONE || diffX * diffX + diffY * diffY + diffZ * diffZ > offset * offset)
mchr.m_hitType = HitResult::NONE;
else
mchr = hr;
}
}
}
else
{
// easy case: pick from the middle of the screen
HitResult hrMob = pMob->pick(dist, f);
mchr = hrMob;
}
Vec3 mobPos = pMob->getPos(f);
if (m_pMinecraft->m_hitResult.m_hitType != HitResult::NONE)
{
float dX = mobPos.x - mchr.m_hitPos.x;
float dY = mobPos.y - mchr.m_hitPos.y;
float dZ = mobPos.z - mchr.m_hitPos.z;
dist = sqrtf(dX * dX + dY * dY + dZ * dZ);
}
dist = mchr.m_hitPos.distanceTo(mobPos);
if (m_pMinecraft->m_pGameMode->isCreativeType())
dist = 32.0f;

View File

@@ -0,0 +1,31 @@
/********************************************************************
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 "SmoothFloat.hpp"
SmoothFloat::SmoothFloat() :
field_0(0),
field_4(0),
field_8(0)
{
}
float SmoothFloat::getNewDeltaValue(float a1, float a2)
{
field_0 += a1;
float v1 = (field_0 - field_4) * a2;
field_8 += 0.5f * (v1 - field_8);
if (v1 > 0.0f && field_8 < v1 || v1<0.0f && field_8>v1)
v1 = field_8;
field_4 += v1;
return v1;
}

View File

@@ -0,0 +1,22 @@
/********************************************************************
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
class SmoothFloat
{
public:
SmoothFloat();
float getNewDeltaValue(float, float);
private:
float field_0;
float field_4;
float field_8;
};

View File

@@ -287,7 +287,7 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, PlayerEqui
return;
}
pPlayer->m_pInventory->selectItemById(packet->m_itemID);
pPlayer->m_pInventory->selectItemById(packet->m_itemID, C_MAX_HOTBAR_ITEMS);
redistributePacket(packet, guid);
}

View File

@@ -25,4 +25,298 @@ void drawArrayVTC(GLuint buffer, int count, int stride)
xglDisableClientState(GL_VERTEX_ARRAY);
xglDisableClientState(GL_TEXTURE_COORD_ARRAY);
xglDisableClientState(GL_COLOR_ARRAY);
}
}
// It appears Mojang took the code from:
// https://www.khronos.org/opengl/wiki/GluProject_and_gluUnProject_code
int glhProjectf(float objx, float objy, float objz, float* modelview, float* projection, int* viewport, float* windowCoordinate)
{
// Transformation vectors
float fTempo[8];
// Modelview transform
fTempo[0] = modelview[0] * objx + modelview[4] * objy + modelview[8] * objz + modelview[12]; // w is always 1
fTempo[1] = modelview[1] * objx + modelview[5] * objy + modelview[9] * objz + modelview[13];
fTempo[2] = modelview[2] * objx + modelview[6] * objy + modelview[10] * objz + modelview[14];
fTempo[3] = modelview[3] * objx + modelview[7] * objy + modelview[11] * objz + modelview[15];
// Projection transform, the final row of projection matrix is always [0 0 -1 0]
// so we optimize for that.
fTempo[4] = projection[0] * fTempo[0] + projection[4] * fTempo[1] + projection[8] * fTempo[2] + projection[12] * fTempo[3];
fTempo[5] = projection[1] * fTempo[0] + projection[5] * fTempo[1] + projection[9] * fTempo[2] + projection[13] * fTempo[3];
fTempo[6] = projection[2] * fTempo[0] + projection[6] * fTempo[1] + projection[10] * fTempo[2] + projection[14] * fTempo[3];
fTempo[7] = -fTempo[2];
// The result normalizes between -1 and 1
if (fTempo[7] == 0.0) // The w value
return 0;
fTempo[7] = 1.0 / fTempo[7];
// Perspective division
fTempo[4] *= fTempo[7];
fTempo[5] *= fTempo[7];
fTempo[6] *= fTempo[7];
// Window coordinates
// Map x, y to range 0-1
windowCoordinate[0] = (fTempo[4] * 0.5 + 0.5) * viewport[2] + viewport[0];
windowCoordinate[1] = (fTempo[5] * 0.5 + 0.5) * viewport[3] + viewport[1];
// This is only correct when glDepthRange(0.0, 1.0)
windowCoordinate[2] = (1.0 + fTempo[6]) * 0.5; // Between 0 and 1
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.0 - 1.0;
in[1] = (winy - (float)viewport[1]) / (float)viewport[3] * 2.0 - 1.0;
in[2] = 2.0 * winz - 1.0;
in[3] = 1.0;
// Objects coordinates
MultiplyMatrixByVector4by4OpenGL_FLOAT(out, m, in);
if (out[3] == 0.0)
return 0;
out[3] = 1.0 / out[3];
objectCoordinate[0] = out[0] * out[3];
objectCoordinate[1] = out[1] * out[3];
objectCoordinate[2] = out[2] * out[3];
return 1;
}
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.0, r0[5] = r0[6] = r0[7] = 0.0,
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.0, r1[4] = r1[6] = r1[7] = 0.0,
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.0, r2[4] = r2[5] = r2[7] = 0.0,
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.0, r3[4] = r3[5] = r3[6] = 0.0;
/* 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.0 == 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.0) {
r1[4] -= m1 * s;
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r0[5];
if (s != 0.0) {
r1[5] -= m1 * s;
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r0[6];
if (s != 0.0) {
r1[6] -= m1 * s;
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r0[7];
if (s != 0.0) {
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.0 == 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.0 != s) {
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r1[5];
if (0.0 != s) {
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r1[6];
if (0.0 != s) {
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r1[7];
if (0.0 != 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.0 == 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.0 == r3[3])
return 0;
s = 1.0 / 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.0 / 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.0 / 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.0 / 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;
}

View File

@@ -3,4 +3,11 @@
#include "thirdparty/GL/GL.hpp"
void drawArrayVT(GLuint buffer, int count, int stride);
void drawArrayVTC(GLuint buffer, int count, int stride);
void drawArrayVTC(GLuint buffer, int count, int stride);
int glhInvertMatrixf2(float* m, float* out);
int glhProjectf(float objx, float objy, float objz, float* modelview, float* projection, int* viewport, float* windowCoordinate);
int glhUnProjectf(float winx, float winy, float winz, float* modelview, float* projection, int* viewport, float* objectCoordinate);
void MultiplyMatrices4by4OpenGL_FLOAT(float* result, float* matrix1, float* matrix2);
void MultiplyMatrixByVector4by4OpenGL_FLOAT(float* resultvector, const float* matrix, const float* pvector);

View File

@@ -34,7 +34,7 @@ LocalPlayer::LocalPlayer(Minecraft* pMinecraft, Level* pLevel, User* pUser, int
field_C34 = 0.0f;
// multiplayer related -- end
field_C38 = 0;
m_pKeyboardInput = nullptr;
m_pMoveInput = nullptr;
m_pMinecraft = pMinecraft;
m_name = pUser->field_0;
@@ -45,17 +45,13 @@ LocalPlayer::LocalPlayer(Minecraft* pMinecraft, Level* pLevel, User* pUser, int
LocalPlayer::~LocalPlayer()
{
if (m_pKeyboardInput)
delete m_pKeyboardInput;
}
void LocalPlayer::aiStep()
{
m_pKeyboardInput->tick(/* this */);
if (m_pKeyboardInput->m_bSneakButton && field_A4 < 0.2f)
{
m_pMoveInput->tick(this);
if (m_pMoveInput->m_bSneakButton && field_A4 < 0.2f)
field_A4 = 0.2f;
}
Mob::aiStep();
Player::aiStep();
@@ -120,7 +116,7 @@ void LocalPlayer::respawn()
bool LocalPlayer::isSneaking()
{
return m_pKeyboardInput->m_bSneakButton;
return m_pMoveInput->m_bSneakButton;
}
int LocalPlayer::move(float x, float y, float z)
@@ -157,7 +153,7 @@ int LocalPlayer::move(float x, float y, float z)
if (m_nAutoJumpFrames > 0)
{
m_nAutoJumpFrames--;
m_pKeyboardInput->m_bJumpButton = true;
m_pMoveInput->m_bJumpButton = true;
}
float posX = m_pos.x;
@@ -235,10 +231,10 @@ void LocalPlayer::updateAi()
{
Player::updateAi();
field_B00 = m_pKeyboardInput->m_horzInput;
field_B04 = m_pKeyboardInput->m_vertInput;
field_B00 = m_pMoveInput->m_horzInput;
field_B04 = m_pMoveInput->m_vertInput;
field_B0C = m_pKeyboardInput->m_bJumpButton || m_nAutoJumpFrames > 0;
field_B0C = m_pMoveInput->m_bJumpButton || m_nAutoJumpFrames > 0;
}
bool LocalPlayer::isLocalPlayer()

View File

@@ -9,7 +9,7 @@
#pragma once
#include "world/entity/Player.hpp"
#include "client/player/input/KeyboardInput.hpp"
#include "client/player/input/IMoveInput.hpp"
#include "client/player/input/User.hpp"
class Minecraft;
@@ -57,5 +57,5 @@ public:
// multiplayer related -- end
int field_C38;
Minecraft* m_pMinecraft;
KeyboardInput* m_pKeyboardInput;
IMoveInput* m_pMoveInput;
};

View File

@@ -39,6 +39,111 @@ bool CreativeMode::destroyBlock(int x, int y, int z, int i)
return true;
}
// @NOTE: Duplicate of SurvivalMode's break logic!
void CreativeMode::startDestroyBlock(int x, int y, int z, int i)
{
if (!m_pMinecraft->isTouchscreen())
{
GameMode::startDestroyBlock(x, y, z, i);
return;
}
TileID tile = m_pMinecraft->m_pLevel->getTile(x, y, z);
if (tile <= 0)
return;
if (m_destroyProgress == 0.0f)
{
Tile::tiles[tile]->attack(m_pMinecraft->m_pLevel, x, y, z, m_pMinecraft->m_pLocalPlayer);
}
if (Tile::tiles[tile]->getDestroyProgress(m_pMinecraft->m_pLocalPlayer) >= 1.0f)
{
destroyBlock(x, y, z, i);
}
return;
}
void CreativeMode::continueDestroyBlock(int x, int y, int z, int i)
{
if (!m_pMinecraft->isTouchscreen())
{
GameMode::continueDestroyBlock(x, y, z, i);
return;
}
if (m_destroyCooldown > 0)
{
m_destroyCooldown--;
return;
}
if (m_destroyingX != x || m_destroyingY != y || m_destroyingZ != z)
{
m_destroyProgress = 0.0f;
m_lastDestroyProgress = 0.0f;
m_destroyTicks = 0;
m_destroyingX = x;
m_destroyingY = y;
m_destroyingZ = z;
return;
}
TileID tile = m_pMinecraft->m_pLevel->getTile(m_destroyingX, m_destroyingY, m_destroyingZ);
if (!tile)
return;
Tile* pTile = Tile::tiles[tile];
float destroyProgress = pTile->getDestroyProgress(m_pMinecraft->m_pLocalPlayer);
m_destroyProgress += 16.0f * destroyProgress;
m_destroyTicks++;
if ((m_destroyTicks & 3) == 1)
{
m_pMinecraft->m_pSoundEngine->play("step." + pTile->m_pSound->m_name,
float(x) + 0.5f, float(y) + 0.5f, float(z) + 0.5f,
0.5f * (1.0f + pTile->m_pSound->field_18), 0.8f * pTile->m_pSound->field_1C);
}
if (m_destroyProgress >= 1.0f)
{
destroyBlock(m_destroyingX, m_destroyingY, m_destroyingZ, i);
m_destroyTicks = 0;
m_destroyCooldown = 5;
m_destroyProgress = 0.0f;
m_lastDestroyProgress = 0.0f;
}
}
void CreativeMode::stopDestroyBlock()
{
m_destroyProgress = 0.0f;
m_destroyCooldown = 0;
}
void CreativeMode::tick()
{
m_lastDestroyProgress = m_destroyProgress;
}
void CreativeMode::render(float f)
{
if (m_destroyProgress <= 0.0f)
{
m_pMinecraft->m_gui.field_8 = 0.0f;
m_pMinecraft->m_pLevelRenderer->field_10 = 0.0f;
}
else
{
float x = m_lastDestroyProgress + (m_destroyProgress - m_lastDestroyProgress) * f;
m_pMinecraft->m_gui.field_8 = x;
m_pMinecraft->m_pLevelRenderer->field_10 = x;
}
}
void CreativeMode::initPlayer(Player* p)
{
p->m_yaw = -180.0f;

View File

@@ -19,6 +19,21 @@ public:
float getPickRange() override;
bool isCreativeType() override;
bool isSurvivalType() override;
void initPlayer(Player*) override;
void startDestroyBlock(int x, int y, int z, int i) override;
void continueDestroyBlock(int x, int y, int z, int i) override;
void stopDestroyBlock() override;
void tick();
void render(float f);
public:
int m_destroyingX;
int m_destroyingY;
int m_destroyingZ;
float m_destroyProgress;
float m_lastDestroyProgress;
int m_destroyTicks;
int m_destroyCooldown;
};

View File

@@ -238,13 +238,13 @@ int Inventory::getSelectedItemId()
return getQuickSlotItemId(m_SelectedHotbarSlot);
}
void Inventory::selectItem(int slotNo)
void Inventory::selectItem(int slotNo, int maxHotBarSlot)
{
if (slotNo < 0 || slotNo >= getNumItems())
return;
// look for it in the hotbar
for (int i = 0; i < C_MAX_HOTBAR_ITEMS; i++)
for (int i = 0; i < maxHotBarSlot; i++)
{
if (m_hotbar[i] == slotNo)
{
@@ -253,7 +253,7 @@ void Inventory::selectItem(int slotNo)
}
}
for (int i = C_MAX_HOTBAR_ITEMS - 2; i >= 0; i--)
for (int i = maxHotBarSlot - 2; i >= 0; i--)
m_hotbar[i + 1] = m_hotbar[i];
m_hotbar[0] = slotNo;
@@ -288,14 +288,14 @@ void Inventory::setQuickSlotIndexByItemId(int slotNo, int itemID)
m_hotbar[slotNo] = -1;
}
void Inventory::selectItemById(int itemID)
void Inventory::selectItemById(int itemID, int maxHotBarSlot)
{
for (int i = 0; i < getNumItems(); i++)
{
if (m_items[i].m_itemID != itemID)
continue;
selectItem(i);
selectItem(i, maxHotBarSlot);
return;
}

View File

@@ -32,11 +32,11 @@ public:
ItemInstance* getSelectedItem();
int getQuickSlotItemId(int slotNo);
int getSelectedItemId();
void selectItem(int slotNo); // selects an item by slot number and puts it in the quick slots if needed
void selectItem(int slotNo, int maxHotBarSlot); // selects an item by slot number and puts it in the quick slots if needed
void selectSlot(int slotNo);
void setQuickSlotIndexByItemId(int slotNo, int itemID);
void selectItemById(int itemID);
void selectItemById(int itemID, int maxHotBarSlot);
int getAttackDamage(Entity*);

View File

@@ -1507,359 +1507,108 @@ void Level::tickEntities()
delete pEnt;
}
}
/*
HitResult Level::clip(Vec3 vec1, Vec3 vec2, bool flag)
HitResult Level::clip(Vec3 v1, Vec3 v2, bool flag)
{
// @NOTE: Using a version from Minecraft Java Edition Beta 1.6, decompiled courtesy of the Mod Coder Pack.
// The name there is "rayTraceBlocks", but I'm convinced that it's also called "Level.clip" in Notch's original code.
// They look pretty alike though, so I believe that this is going to work
int v2x = Mth::floor(vec2.x);
int v2y = Mth::floor(vec2.y);
int v2z = Mth::floor(vec2.z);
int v1x = Mth::floor(vec1.x);
int v1y = Mth::floor(vec1.y);
int v1z = Mth::floor(vec1.z);
TileID tile = getTile(v1x, v1y, v1z);
int data = getData(v1x, v1y, v1z);
Tile *pTile = Tile::tiles[tile];
/ *
if (//(!flag || !pTile || !pTile->getAABB(this, v1x, v1y, v1z)) &&
tile > 0 && pTile->mayPick(data, flag))
int v2xf = Mth::floor(v2.x);
int v2yf = Mth::floor(v2.y);
int v2zf = Mth::floor(v2.z);
int v1xf = Mth::floor(v1.x);
int v1yf = Mth::floor(v1.y);
int v1zf = Mth::floor(v1.z);
int counter = 200;
while (counter-- >= 0)
{
HitResult hr = pTile->clip(this, v1x, v1y, v1z, vec1, vec2);
if (hr.m_hitType != HitResult::NONE)
return hr;
}
* /
if (v1xf == v2xf && v1yf == v2yf && v1zf == v2zf)
break;
for (int i = 200; i >= 0; i--)
{
if (v1x == v2x && v1y == v2y && v1z == v2z)
return HitResult();
float f0 = 999.0f, f1 = 999.0f, f2 = 999.0f;
bool flag2 = true, flag3 = true, flag4 = true;
if (v2x > v1x)
f0 = float(v1x) + 1.0f;
else if (v2x < v1x)
f0 = float(v1x) + 0.0f;
else
flag2 = false;
if (v2y > v1y)
f1 = float(v1y) + 1.0f;
else if (v2y < v1y)
f1 = float(v1y) + 0.0f;
else
flag3 = false;
if (v2z > v1z)
f2 = float(v1z) + 1.0f;
else if (v2z < v1z)
f2 = float(v1z) + 0.0f;
else
flag4 = false;
float f3 = 999.0f, f4 = 999.0f, f5 = 999.0f;
float f6 = vec2.x - vec1.z, f7 = vec2.y - vec1.y, f8 = vec2.z - vec1.z;
if (flag2) f3 = (f0 - vec1.x) / f6;
if (flag3) f4 = (f1 - vec1.y) / f7;
if (flag4) f5 = (f2 - vec1.z) / f8;
HitResult::eHitSide hitSide = HitResult::MINY;
if (f3 < f4 && f3 < f5)
float xd = 999.0f;
float yd = 999.0f;
float zd = 999.0f;
if (v2xf > v1xf) xd = (float)v1xf + 1.0f;
if (v2xf < v1xf) xd = (float)v1xf + 0.0f;
if (v2yf > v1yf) yd = (float)v1yf + 1.0f;
if (v2yf < v1yf) yd = (float)v1yf + 0.0f;
if (v2zf > v1zf) zd = (float)v1zf + 1.0f;
if (v2zf < v1zf) zd = (float)v1zf + 0.0f;
float xe = 999.0f;
float ye = 999.0f;
float ze = 999.0f;
float xl = v2.x - v1.x;
float yl = v2.y - v1.y;
float zl = v2.z - v1.z;
if (xd != 999.0f) xe = (float)(xd - v1.x) / xl;
if (yd != 999.0f) ye = (float)(yd - v1.y) / yl;
if (zd != 999.0f) ze = (float)(zd - v1.z) / zl;
int hitSide = 0;
if (xe >= ye || xe >= ze)
{
if (v2x > v1x) hitSide = HitResult::MINX;
else hitSide = HitResult::MAXX;
vec1.x = f0;
vec1.y += f7 * f3;
vec1.z += f8 * f3;
}
else if (f4 < f5)
{
if (v2y > v1y) hitSide = HitResult::MINY;
else hitSide = HitResult::MAXY;
vec1.x += f6 * f4;
vec1.y = f1;
vec1.z += f8 * f4;
if (ye >= ze)
{
hitSide = v2zf <= v1zf ? HitResult::MAXZ : HitResult::MINZ;
v1.x = v1.x + (float)(xl * ze);
v1.y = v1.y + (float)(yl * ze);
v1.z = zd;
}
else
{
hitSide = (v2yf <= v1yf) ? HitResult::MAXY : HitResult::MINY;
v1.x = v1.x + (float)(xl * ye);
v1.y = yd;
v1.z = v1.z + (float)(zl * ye);
}
}
else
{
if (v2z > v1z) hitSide = HitResult::MINZ;
else hitSide = HitResult::MAXZ;
vec1.x += f6 * f5;
vec1.y += f7 * f5;
vec1.z = f2;
hitSide = v2xf <= v1xf ? HitResult::MAXX : HitResult::MINX;
v1.x = xd;
v1.y = v1.y + (float)(yl * xe);
v1.z = v1.z + (float)(zl * xe);
}
Vec3 vec = vec1;
Vec3 hitVec(v1.x, v1.y, v1.z);
v1x = int(vec.x = float(Mth::floor(vec1.x)));
// Correct the hit positions for each vector
hitVec.x = (float)Mth::floor(v1.x);
v1xf = (int)hitVec.x;
if (hitSide == HitResult::MAXX)
{
v1x--;
vec.x -= 1.0f;
v1xf--;
hitVec.x += 1.0;
}
v1y = int(vec.y = float(Mth::floor(vec1.y)));
hitVec.y = (float)Mth::floor(v1.y);
v1yf = (int)hitVec.y;
if (hitSide == HitResult::MAXY)
{
v1y--;
vec.y -= 1.0f;
v1yf--;
hitVec.y += 1.0;
}
v1z = int(vec.z = float(Mth::floor(vec1.z)));
hitVec.z = (float)Mth::floor(v1.z);
v1zf = (int)hitVec.z;
if (hitSide == HitResult::MAXZ)
{
v1z--;
vec.z -= 1.0f;
v1zf--;
hitVec.z += 1.0;
}
TileID tile = getTile(v1x, v1y, v1z);
int data = getData(v1x, v1y, v1z);
TileID tile = getTile(v1xf, v1yf, v1zf);
int data = getData(v1xf, v1yf, v1zf);
Tile* pTile = Tile::tiles[tile];
if (//(!flag || !pTile || !pTile->getAABB(this, v1x, v1y, v1z)) &&
tile > 0 && pTile->mayPick(data, flag))
if (tile > 0 && pTile->mayPick(data, false))
{
HitResult hr = pTile->clip(this, v1x, v1y, v1z, vec1, vec2);
if (hr.m_hitType != HitResult::NONE)
HitResult hr = pTile->clip(this, v1xf, v1yf, v1zf, v1, v2);
if (hr.isHit())
return hr;
}
}
return HitResult();
}
*/
HitResult Level::clip(Vec3 vecA, Vec3 vecB, bool b)
{
float v5; // s14
int v6; // s15
float v7; // s18
float v10; // s16
bool v11; // r8
float v12; // s17
float v13; // s19
float v14; // s20
float v15; // s21
int v17; // r11
int v18; // r4
int v19; // r5
int v20; // r10
bool v21; // r3
float v22; // s10
float v23; // s11
float v24; // s12
float v25; // s9
float v26; // s15
float v27; // s8
float v28; // s7
float v29; // s13
int v30; // r7
TileID v31; // r9
int v32; // r1
Tile* v33; // r8
Vec3 v50; // [sp+8h] [bp-C8h] BYREF
Vec3 v51; // [sp+14h] [bp-BCh] BYREF
int v52; // [sp+24h] [bp-ACh]
int v53; // [sp+28h] [bp-A8h]
int v54; // [sp+2Ch] [bp-A4h]
Vec3* v56; // [sp+3Ch] [bp-94h]
Vec3* v57; // [sp+40h] [bp-90h]
bool v58; // [sp+44h] [bp-8Ch]
HitResult result; // [sp+50h] [bp-80h] BYREF
v7 = vecA.z;
v10 = vecA.x;
v11 = b;
v12 = vecA.y;
v13 = vecB.x;
v14 = vecB.y;
v15 = vecB.z;
v54 = Mth::floor(vecB.x);
v52 = Mth::floor(v14);
v53 = Mth::floor(v15);
v17 = Mth::floor(vecA.x);
v18 = Mth::floor(vecA.y);
v56 = &v51;
v57 = &vecB;
v58 = v11;
v19 = Mth::floor(vecA.z);
v20 = 199;
while (1)
{
if (v18 == v52)
v21 = v17 == v54;
else
v21 = 0;
if (v21)
{
if (v19 == v53)
goto LABEL_43;
LABEL_8:
v22 = 999.0f;
goto LABEL_9;
}
if (v54 <= v17)
{
if (v54 >= v17)
goto LABEL_8;
v6 = v17;
v22 = float(v17) + 0.0f;
}
else
{
v6 = v17;
v22 = float(v17) + 1.0f;
}
LABEL_9:
if (v52 <= v18)
{
if (v52 >= v18)
{
v23 = 999.0f;
}
else
{
v6 = v18;
v23 = float(v18);
}
if (v52 < v18)
v23 = v23 + 0.0f;
}
else
{
v6 = v18;
v23 = float(v18) + 1.0f;
}
if (v53 <= v19)
{
if (v53 >= v19)
{
v24 = 999.0f;
}
else
{
v6 = v19;
v24 = float(v19);
}
if (v53 < v19)
v24 = v24 + 0.0f;
}
else
{
v6 = v19;
v24 = float(v19) + 1.0f;
}
float v6_2;
v25 = v13 - v10;
if (v22 == 999.0f)
v5 = 999.0f;
else
v6_2 = v22 - v10;
if (v22 != 999.0f)
v5 = v6_2 / v25;
if (v23 == 999.0f)
v26 = 999.0f;
else
v26 = v23 - v12;
v27 = v14 - v12;
if (v23 != 999.0f)
v26 = v26 / v27;
v28 = v15 - v7;
if (v24 == 999.0f)
v29 = 999.0f;
else
v29 = v24 - v7;
if (v24 != 999.0f)
v29 = v29 / v28;
if (v5 >= v26 || v5 >= v29)
{
if (v26 >= v29)
{
v10 = v10 + float(v25 * v29);
if (v53 <= v19)
v30 = 3;
else
v30 = 2;
v12 = v12 + float(v27 * v29);
v7 = v24;
}
else
{
v10 = v10 + float(v25 * v26);
v30 = v18 >= v52;
v7 = v7 + float(v28 * v26);
v12 = v23;
}
}
else
{
v12 = v12 + float(v27 * v5);
if (v54 <= v17)
v30 = 5;
else
v30 = 4;
v7 = v7 + float(v28 * v5);
v10 = v22;
}
v17 = Mth::floor(v10);
if (v30 == 5)
{
--v17;
v18 = Mth::floor(v12);
goto LABEL_65;
}
v18 = Mth::floor(v12);
if (v30 == 1)
{
--v18;
LABEL_65:
v6 = Mth::floor(v7);
v19 = v6;
goto LABEL_38;
}
v6 = Mth::floor(v7);
v19 = v6;
if (v30 == 3)
v19 = v6 - 1;
LABEL_38:
v31 = getTile(v17, v18, v19);
v32 = getData(v17, v18, v19);
v33 = Tile::tiles[v31];
if (v31 > 0)
{
if (v33->mayPick(v32, v58))
{
//v34 = v33->m_vtable->clip;
vecA.x = v10;
vecA.y = v12;
vecA.z = v7;
result = v33->clip(this, v17, v18, v19, vecA, *v57);
if (result.m_hitType != HitResult::NONE)
break;
}
}
if (v20 == -1)
{
LABEL_43:
result.m_hitPos = Vec3();
result.m_hitType = HitResult::NONE;
return result;
}
--v20;
}
return result;
}
HitResult Level::clip(const Vec3& a, const Vec3& b)
{

View File

@@ -40,6 +40,9 @@ public:
HitResult() { _init(); }
HitResult(Entity*);
HitResult(int x, int y, int z, eHitSide hitSide, const Vec3&);
bool isHit() const {
return m_hitType != NONE;
}
public:
eHitResultType m_hitType;

View File

@@ -12,6 +12,10 @@
// Needed for when we're missing nullptr in multiple files
#include "common/Utils.hpp"
// NOTE: I don't think that Vec3 was implemented like that - it was
// probably implemented just like in Java. However, I think it looks
// nicer this way :)
class Vec3
{
public:
@@ -75,5 +79,20 @@ public:
{
return Vec3(x + tx, y + ty, z + tz);
}
float lengthSqr() const
{
return x * x + y * y + z * z;
}
float length() const
{
return sqrt(lengthSqr());
}
Vec3 scale(float scale) const
{
return Vec3(x * scale, y * scale, z * scale);
}
};