Files
mcpe/platforms/android/AppPlatform_android.cpp
f f83ead9f8d WIP Android Port (#79)
* WIP Android Port

Android port. Still needs touch controls and mouse turning (if that's even possible on android) and file saving and SoundSystemSL
You control the camera and movement with your controller for now. You can navigate the gui using touch.
Options.cpp,LocalPlayer.cpp,Minecraft.cpp is configured to use controller.
Blocked out some code in ControllerTurnInput.cpp,Controller.cpp that didn't make sense.

* Fix glClear

glClear is supossed to use GL_DEPTH_BUFFER_BIT (thx TheBrokenRail)

* * Fix build.

* * Ignore assets.

* * More stuff

* * Fix more build errors.

* * It finally built

What I needed to do is rebuild the debug keystore because apparently android studio created it with sha1 digest alg which isn't supported by ant

* * Clean up filters.

* * Add cramped mode to the pause screen.

* * Fix a bug with the hotbar

* * In NinecraftApp::handleBack, pause the game if there is no screen.

* * AppPlatform_android: Add placeholder SoundSystem instance till we get SoundSystemSL working

* * Add properly working touch code.

* * Oh, remove some testing things

* * Fix state resetting when going in background and back in foreground
* Fix bug where the sky isn't being regenerated on graphics reset
* Fix bug where the m_currBoundTex isn't reset in Textures::clear potentially leaving a texture with that ID unassigned and corrupted
* Fix bug in CThread where the thread is detached and then also joined.
* Don't log anything if the program isn't in debug mode.

* * Add virtual keyboard support.

The screen instance slides so that the focused text box is kept visible.

* Rename from com.minecraftcpp to com.reminecraftpe

---------

Co-authored-by: iProgramInCpp <iprogramincpp@gmail.com>
2023-11-03 12:54:39 +02:00

331 lines
8.0 KiB
C++

/********************************************************************
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
********************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <fstream>
#include <sstream>
#include "AppPlatform_android.hpp"
#include "client/player/input/Mouse.hpp"
#include "thirdparty/stb_image.h"
#include "thirdparty/stb_image_write.h"
AppPlatform_android::AppPlatform_android()
{
m_UserInputStatus = -1;
m_bIsFocused = false;
m_bGrabbedMouse = false;
m_bActuallyGrabbedMouse = false;
m_bWasUnfocused = false;
m_bShiftPressed = false;
m_bIsKeyboardShown = false;
m_MouseDiffX = 0, m_MouseDiffY = 0;
m_pSoundSystem = nullptr;
}
AppPlatform_android::~AppPlatform_android()
{
SAFE_DELETE(m_pSoundSystem);
}
void AppPlatform_android::initConsts()
{
// just assume an 854x480 window for now:
m_ScreenWidth = C_DEFAULT_SCREEN_WIDTH;
m_ScreenHeight = C_DEFAULT_SCREEN_HEIGHT;
}
int AppPlatform_android::checkLicense()
{
// we own the game!!
return 1;
}
void AppPlatform_android::buyGame()
{
}
void AppPlatform_android::saveScreenshot(const std::string& fileName, int width, int height)
{
}
int AppPlatform_android::getScreenWidth() const
{
return m_ScreenWidth;
}
int AppPlatform_android::getScreenHeight() const
{
return m_ScreenHeight;
}
std::vector<std::string> AppPlatform_android::getUserInput()
{
return m_UserInput;
}
int AppPlatform_android::getUserInputStatus()
{
return m_UserInputStatus;
}
void AppPlatform_android::createUserInput()
{
m_UserInput.clear();
m_UserInputStatus = -1;
switch (m_DialogType)
{
case DLG_CREATE_WORLD:
{
// some placeholder for now
m_UserInput.push_back("New World");
m_UserInput.push_back("123456");
m_UserInputStatus = 1;
break;
}
}
}
void AppPlatform_android::showDialog(eDialogType type)
{
m_DialogType = type;
}
std::string AppPlatform_android::getDateString(int time)
{
const time_t t = time_t(time);
struct tm tf;
struct tm* tp = gmtime_r(&t, &tf);
char buffer[128];
strftime(buffer, sizeof buffer, "%d/%m/%y %H:%M", tp);
return std::string(buffer);
}
Texture AppPlatform_android::loadTexture(const std::string& str, bool b)
{
std::string realPath = str;
if (realPath.size() && realPath[0] == '/')
// trim it off
realPath = realPath.substr(1);
AAsset* asset = AAssetManager_open(m_app->activity->assetManager, str.c_str(), AASSET_MODE_BUFFER);
if (!asset) {
LOG_E("File %s couldn't be opened", realPath.c_str());
}
size_t cnt = AAsset_getLength(asset);
unsigned char* buffer = (unsigned char*)calloc(cnt, sizeof(unsigned char));
AAsset_read(asset, (void*)buffer, cnt);
AAsset_close(asset);
int width = 0, height = 0, channels = 0;
stbi_uc* img = stbi_load_from_memory(buffer, cnt, &width, &height, &channels, STBI_rgb_alpha);
if (!img)
{
LOG_E("File %s couldn't be loaded via stb_image", realPath.c_str());
}
free(buffer);
return Texture(width, height, (uint32_t*)img, 1, 0);
}
SoundSystem* const AppPlatform_android::getSoundSystem() const
{
return m_pSoundSystem;
}
void AppPlatform_android::initSoundSystem()
{
// TODO: SoundSystemSL!
if (!m_pSoundSystem)
m_pSoundSystem = new SoundSystem();
else
LOG_E("Trying to initialize SoundSystem more than once!");
}
bool AppPlatform_android::isTouchscreen()
{
return true;
}
/*
std::vector<std::string> AppPlatform_android::getOptionStrings()
{
std::vector<std::string> o;
//o.push_back("mp_username");
//o.push_back("iProgramInCpp");
std::ifstream ifs("options.txt");
if (!ifs.is_open())
return o;
std::string str;
while (true)
{
if (!std::getline(ifs, str, '\n'))
break;
if (str.empty() || str[0] == '#')
continue;
std::stringstream ss;
ss << str;
std::string key, value;
if (std::getline(ss, key, '|') && std::getline(ss, value))
{
o.push_back(key);
o.push_back(value);
}
}
return o;
}
void AppPlatform_android::setOptionStrings(const std::vector<std::string>& str)
{
assert(str.size() % 2 == 0);
std::ofstream os("options.txt");
os << "#Config file for Minecraft PE. The # at the start denotes a comment, removing it makes it a command.\n\n";
for (int i = 0; i < int(str.size()); i += 2)
os << str[i] << '|' << str[i + 1] << '\n';
}
*/
void AppPlatform_android::setScreenSize(int width, int height)
{
m_ScreenWidth = width;
m_ScreenHeight = height;
}
void AppPlatform_android::initAndroidApp(android_app* ptr)
{
m_app = ptr;
}
void AppPlatform_android::recenterMouse()
{
}
void AppPlatform_android::setMouseGrabbed(bool b)
{
m_bGrabbedMouse = b;
if (m_bActuallyGrabbedMouse == (b && m_bIsFocused))
return;
}
void AppPlatform_android::getMouseDiff(int& x, int& y)
{
x = m_MouseDiffX;
y = m_MouseDiffY;
}
void AppPlatform_android::clearDiff()
{
m_MouseDiffX = m_MouseDiffY = 0;
}
void AppPlatform_android::updateFocused(bool focused)
{
m_bIsFocused = focused;
setMouseGrabbed(m_bGrabbedMouse);
}
bool AppPlatform_android::shiftPressed()
{
return m_bShiftPressed;
}
void AppPlatform_android::setShiftPressed(bool b)
{
m_bShiftPressed = b;
}
void AppPlatform_android::showKeyboard(bool bShown)
{
JavaVM* pVM = m_app->activity->vm;
JNIEnv* pEnv = m_app->activity->env;
// This is horrible. However, I refuse to introduce J*va into my code.
// Stolen from https://stackoverflow.com/questions/5864790/how-to-show-the-soft-keyboard-on-native-activity
pVM->AttachCurrentThread(&pEnv, NULL);
jint flags = 0;
// Retrieves NativeActivity.
jobject lNativeActivity = m_app->activity->clazz;
jclass ClassNativeActivity = pEnv->GetObjectClass(lNativeActivity);
// Retrieves Context.INPUT_METHOD_SERVICE.
jclass ClassContext = pEnv->FindClass("android/content/Context");
jfieldID FieldINPUT_METHOD_SERVICE = pEnv->GetStaticFieldID(ClassContext, "INPUT_METHOD_SERVICE", "Ljava/lang/String;");
jobject INPUT_METHOD_SERVICE = pEnv->GetStaticObjectField(ClassContext, FieldINPUT_METHOD_SERVICE);
// Runs getSystemService(Context.INPUT_METHOD_SERVICE).
jclass ClassInputMethodManager = pEnv->FindClass("android/view/inputmethod/InputMethodManager");
jmethodID MethodGetSystemService = pEnv->GetMethodID(ClassNativeActivity, "getSystemService","(Ljava/lang/String;)Ljava/lang/Object;");
jobject lInputMethodManager = pEnv->CallObjectMethod(lNativeActivity, MethodGetSystemService,INPUT_METHOD_SERVICE);
// Runs getWindow().getDecorView().
jmethodID MethodGetWindow = pEnv->GetMethodID(ClassNativeActivity, "getWindow","()Landroid/view/Window;");
jobject lWindow = pEnv->CallObjectMethod(lNativeActivity,MethodGetWindow);
jclass ClassWindow = pEnv->FindClass("android/view/Window");
jmethodID MethodGetDecorView = pEnv->GetMethodID(ClassWindow, "getDecorView", "()Landroid/view/View;");
jobject lDecorView = pEnv->CallObjectMethod(lWindow,MethodGetDecorView);
if (bShown)
{
// Runs lInputMethodManager.showSoftInput(...).
jmethodID MethodShowSoftInput = pEnv->GetMethodID(ClassInputMethodManager, "showSoftInput","(Landroid/view/View;I)Z");
jboolean lResult = pEnv->CallBooleanMethod(lInputMethodManager, MethodShowSoftInput,lDecorView, flags);
m_bIsKeyboardShown = lResult;
}
else
{
// Runs lWindow.getViewToken()
jclass ClassView = pEnv->FindClass("android/view/View");
jmethodID MethodGetWindowToken = pEnv->GetMethodID(ClassView, "getWindowToken", "()Landroid/os/IBinder;");
jobject lBinder = pEnv->CallObjectMethod(lDecorView,MethodGetWindowToken);
// lInputMethodManager.hideSoftInput(...).
jmethodID MethodHideSoftInput = pEnv->GetMethodID(ClassInputMethodManager, "hideSoftInputFromWindow","(Landroid/os/IBinder;I)Z");
jboolean lResult = pEnv->CallBooleanMethod(lInputMethodManager, MethodHideSoftInput,lBinder, flags);
m_bIsKeyboardShown = false; // just treat it as hidden anyways why not
}
pVM->DetachCurrentThread();
}
void AppPlatform_android::onHideKeyboard()
{
m_bIsKeyboardShown = false;
}
int AppPlatform_android::getKeyboardUpOffset()
{
// @TODO
// For now we'll just return 1/2 of the screen height. That ought to cover most cases.
return m_ScreenHeight / 2;
}