Merge branch 'main' of https://gitea.sffempire.ru/Kolyah35/minecraft-pe-0.6.1
This commit is contained in:
81
.github/workflows/build.yml
vendored
81
.github/workflows/build.yml
vendored
@@ -19,7 +19,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
build-windows:
|
build-windows:
|
||||||
name: Windows Build
|
name: Windows Build
|
||||||
runs-on: windows-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -29,21 +29,74 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
host: win
|
host: win
|
||||||
target: win
|
target: win
|
||||||
|
|
||||||
|
- name: Download xwin
|
||||||
|
uses: robinraju/release-downloader@v1.10
|
||||||
|
with:
|
||||||
|
repository: Jake-Shadle/xwin
|
||||||
|
latest: true
|
||||||
|
fileName: 'xwin-*-x86_64-unknown-linux-musl.tar.gz'
|
||||||
|
tarBall: false
|
||||||
|
zipBall: false
|
||||||
|
out-file-path: "epic-xwin"
|
||||||
|
|
||||||
|
- name: Prepare xwin
|
||||||
|
run: |
|
||||||
|
tar -xzf epic-xwin/xwin-*-x86_64-unknown-linux-musl.tar.gz -C epic-xwin
|
||||||
|
mv epic-xwin/xwin-*-x86_64-unknown-linux-musl/xwin ./xwin
|
||||||
|
./xwin --arch x86_64 --sdk-version 10.0.22621 --accept-license list
|
||||||
|
|
||||||
|
# this caches '.xwin-cache/**/*' but that's actually only gonna
|
||||||
|
# contain the manifest cuz we only ran `xwin list` so far
|
||||||
|
- name: Setup xwin Cache
|
||||||
|
id: xwin-cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .xwin-cache
|
||||||
|
key: xwin-win-v1-${{ hashFiles('.xwin-cache/**/*') }}
|
||||||
|
|
||||||
|
- name: Download clang-msvc-sdk toolchain
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
repository: 'Nemirtingas/clang-msvc-sdk'
|
||||||
|
path: toolchain
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Install Clang
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y wget lsb-release software-properties-common gnupg
|
||||||
|
|
||||||
|
wget https://apt.llvm.org/llvm.sh
|
||||||
|
chmod +x llvm.sh
|
||||||
|
sudo ./llvm.sh 21 all
|
||||||
|
|
||||||
|
- name: Add LLVM 21 to path
|
||||||
|
run: echo "/usr/lib/llvm-21/bin" >> $GITHUB_PATH
|
||||||
|
|
||||||
|
- name: Verify LLVM
|
||||||
|
run: |
|
||||||
|
which clang-cl
|
||||||
|
which lld-link
|
||||||
|
clang-cl --version
|
||||||
|
lld-link --version
|
||||||
|
|
||||||
- name: Create Build Environment
|
- name: Create Build Environment
|
||||||
# Some projects don't allow in-source building, so create a separate build directory
|
# Some projects don't allow in-source building, so create a separate build directory
|
||||||
# We'll use this as our working directory for all subsequent commands
|
# We'll use this as our working directory for all subsequent commands
|
||||||
run: cmake -E make_directory ${{github.workspace}}/build
|
run: cmake -E make_directory ${{github.workspace}}/build
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Configure CMake
|
||||||
shell: powershell
|
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
run: cmake $env:GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$env:BUILD_TYPE
|
run: cmake $env:GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$env:BUILD_TYPE -DCMAKE_TOOLCHAIN_FILE=$TOOLCHAIN -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||||
|
env:
|
||||||
|
SPLAT_DIR: ${{ github.workspace }}/.xwin-cache/splat
|
||||||
|
TOOLCHAIN: ${{ github.workspace }}/toolchain/clang-cl-msvc.cmake
|
||||||
|
HOST_ARCH: x86_64
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: powershell
|
run: cmake --build . --config $env:BUILD_TYPE --target MinecraftPE --parallel
|
||||||
run: cmake --build . --config $env:BUILD_TYPE --target MinecraftPE
|
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -91,8 +144,8 @@ jobs:
|
|||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
cmake --build . --config $BUILD_TYPE --target MinecraftPE
|
cmake --build . --config $BUILD_TYPE --target MinecraftPE --parallel
|
||||||
cmake --build . --config $BUILD_TYPE --target MinecraftPE-server
|
cmake --build . --config $BUILD_TYPE --target MinecraftPE-server --parallel
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -219,21 +272,13 @@ jobs:
|
|||||||
- name: Zip Windows Artifacts
|
- name: Zip Windows Artifacts
|
||||||
uses: vimtor/action-zip@v1.2
|
uses: vimtor/action-zip@v1.2
|
||||||
with:
|
with:
|
||||||
files: |
|
files: data mcpe-windows/MinecraftPE.exe mcpe-windows/glfw3.dll mcpe-windows/libpng16.dll mcpe-windows/OpenAL32.dll mcpe-windows/z.dll
|
||||||
${{github.workspace}}/data/
|
|
||||||
mcpe-windows/MinecraftPE.exe
|
|
||||||
mcpe-windows/glfw3.dll
|
|
||||||
mcpe-windows/libpng16.dll
|
|
||||||
mcpe-windows/OpenAL32.dll
|
|
||||||
mcpe-windows/z.dll
|
|
||||||
dest: minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip
|
dest: minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip
|
||||||
|
|
||||||
- name: Zip Linux Artifacts
|
- name: Zip Linux Artifacts
|
||||||
uses: vimtor/action-zip@v1.2
|
uses: vimtor/action-zip@v1.2
|
||||||
with:
|
with:
|
||||||
files: |
|
files: data mcpe-linux/MinecraftPE
|
||||||
${{github.workspace}}/data/
|
|
||||||
mcpe-linux/MinecraftPE # ye, you should install libraries by urself :trollface:
|
|
||||||
dest: minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip
|
dest: minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip
|
||||||
|
|
||||||
- name: Zip Linux Server Artifacts
|
- name: Zip Linux Server Artifacts
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ public class MainActivity extends Activity {
|
|||||||
private static final int PERMISSION_REQUEST_CODE = 123;
|
private static final int PERMISSION_REQUEST_CODE = 123;
|
||||||
|
|
||||||
private GLView _glView;
|
private GLView _glView;
|
||||||
|
private boolean _nativeInitialized = false;
|
||||||
public float invScale = 1.0f;// / 1.5f;
|
public float invScale = 1.0f;// / 1.5f;
|
||||||
private int _screenWidth = 0;
|
private int _screenWidth = 0;
|
||||||
private int _screenHeight = 0;
|
private int _screenHeight = 0;
|
||||||
@@ -77,63 +78,48 @@ public class MainActivity extends Activity {
|
|||||||
_screenWidth = Math.max(_dm.widthPixels, _dm.heightPixels);
|
_screenWidth = Math.max(_dm.widthPixels, _dm.heightPixels);
|
||||||
_screenHeight = Math.min(_dm.widthPixels, _dm.heightPixels);
|
_screenHeight = Math.min(_dm.widthPixels, _dm.heightPixels);
|
||||||
|
|
||||||
nativeOnCreate(_screenWidth, _screenHeight);
|
|
||||||
|
|
||||||
_glView = new GLView(getApplication(), this);
|
_glView = new GLView(getApplication(), this);
|
||||||
//_glView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
|
//_glView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
|
||||||
|
|
||||||
_glView.setEGLConfigChooser(true);
|
_glView.setEGLConfigChooser(true);
|
||||||
//_glView
|
//_glView
|
||||||
|
|
||||||
// _glView.setEGLConfigChooser(
|
|
||||||
// new GLSurfaceView.EGLConfigChooser() {
|
|
||||||
//
|
|
||||||
// @Override
|
|
||||||
// public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
|
|
||||||
// // TODO Auto-generated method stub
|
|
||||||
//
|
|
||||||
// // Specify a configuration for our opengl session
|
|
||||||
// // and grab the first configuration that matches is
|
|
||||||
// int[] configSpec = {
|
|
||||||
// EGL10.EGL_DEPTH_SIZE, 24,
|
|
||||||
// EGL10.EGL_NONE
|
|
||||||
// };
|
|
||||||
// EGLConfig[] configs = new EGLConfig[1];
|
|
||||||
// int[] num_config = new int[1];
|
|
||||||
// egl.eglChooseConfig(display, configSpec, configs, 1, num_config);
|
|
||||||
// EGLConfig config = configs[0];
|
|
||||||
// return config;
|
|
||||||
//
|
|
||||||
// //return null;
|
|
||||||
// }
|
|
||||||
// } );
|
|
||||||
|
|
||||||
_glView.commit();
|
_glView.commit();
|
||||||
setContentView(_glView);
|
setContentView(_glView);
|
||||||
|
|
||||||
_soundPlayer = new SoundPlayer(this, AudioManager.STREAM_MUSIC);
|
_soundPlayer = new SoundPlayer(this, AudioManager.STREAM_MUSIC);
|
||||||
|
|
||||||
// request dangerous permissions at runtime if necessary
|
|
||||||
checkAndRequestPermissions();
|
checkAndRequestPermissions();
|
||||||
|
initNative();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAndRequestPermissions() {
|
private void initNative() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (_nativeInitialized) {
|
||||||
boolean needRequest = false;
|
return;
|
||||||
if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
|
||||||
needRequest = true;
|
|
||||||
}
|
|
||||||
if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE)
|
|
||||||
!= PackageManager.PERMISSION_GRANTED) {
|
|
||||||
needRequest = true;
|
|
||||||
}
|
|
||||||
if (needRequest) {
|
|
||||||
requestPermissions(new String[] {
|
|
||||||
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
|
||||||
android.Manifest.permission.READ_EXTERNAL_STORAGE
|
|
||||||
}, PERMISSION_REQUEST_CODE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_nativeInitialized = true;
|
||||||
|
nativeOnCreate(_screenWidth, _screenHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// request dangerous permissions at runtime if necessary
|
||||||
|
private boolean checkAndRequestPermissions() {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean writeGranted = checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
boolean readGranted = checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
|
||||||
|
if (writeGranted && readGranted) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestPermissions(new String[] {
|
||||||
|
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
|
android.Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
|
}, PERMISSION_REQUEST_CODE);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -146,8 +132,18 @@ public class MainActivity extends Activity {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!granted) {
|
if (granted) {
|
||||||
// user denied; you might want to warn or close the app
|
initNative();
|
||||||
|
} else {
|
||||||
|
// We can still run using app-specific external files in scoped-storage,
|
||||||
|
// so allow startup while warning the user.
|
||||||
|
initNative();
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle("Storage permission recommended")
|
||||||
|
.setMessage("MinecraftPE can still run with app-private storage, but public external save/load may require permission.")
|
||||||
|
.setPositiveButton("OK", null)
|
||||||
|
.setCancelable(true)
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
|||||||
@@ -73,50 +73,20 @@ public:
|
|||||||
: filename_;
|
: filename_;
|
||||||
std::ifstream source(filename.c_str(), std::ios::binary);
|
std::ifstream source(filename.c_str(), std::ios::binary);
|
||||||
|
|
||||||
if (source) {
|
if (!source) {
|
||||||
png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
if (!pngPtr)
|
|
||||||
return out;
|
|
||||||
|
|
||||||
png_infop infoPtr = png_create_info_struct(pngPtr);
|
|
||||||
|
|
||||||
if (!infoPtr) {
|
|
||||||
png_destroy_read_struct(&pngPtr, NULL, NULL);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hack to get around the broken libpng for windows
|
|
||||||
png_set_read_fn(pngPtr,(void*)&source, png_funcReadFile);
|
|
||||||
|
|
||||||
png_read_info(pngPtr, infoPtr);
|
|
||||||
|
|
||||||
// Set up the texdata properties
|
|
||||||
out.w = png_get_image_width(pngPtr, infoPtr);
|
|
||||||
out.h = png_get_image_height(pngPtr, infoPtr);
|
|
||||||
|
|
||||||
png_bytep* rowPtrs = new png_bytep[out.h];
|
|
||||||
out.data = new unsigned char[4 * out.w * out.h];
|
|
||||||
out.memoryHandledExternally = false;
|
|
||||||
|
|
||||||
int rowStrideBytes = 4 * out.w;
|
|
||||||
for (int i = 0; i < out.h; i++) {
|
|
||||||
rowPtrs[i] = (png_bytep)&out.data[i*rowStrideBytes];
|
|
||||||
}
|
|
||||||
png_read_image(pngPtr, rowPtrs);
|
|
||||||
|
|
||||||
// Teardown and return
|
|
||||||
png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);
|
|
||||||
delete[] (png_bytep)rowPtrs;
|
|
||||||
source.close();
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LOGI("Couldn't find file: %s\n", filename.c_str());
|
LOGI("Couldn't find file: %s\n", filename.c_str());
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> fileData((std::istreambuf_iterator<char>(source)), std::istreambuf_iterator<char>());
|
||||||
|
source.close();
|
||||||
|
|
||||||
|
if (fileData.empty()) {
|
||||||
|
LOGI("Couldn't read file: %s\n", filename.c_str());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadTextureFromMemory(fileData.data(), fileData.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override {
|
TextureData loadTextureFromMemory(const unsigned char* data, size_t size) override {
|
||||||
|
|||||||
@@ -99,6 +99,9 @@ void NinecraftApp::init()
|
|||||||
I18n::loadLanguage(platform(), "en_US");
|
I18n::loadLanguage(platform(), "en_US");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (!externalStoragePath.empty()) {
|
||||||
|
options.setOptionsFilePath(externalStoragePath);
|
||||||
|
}
|
||||||
Minecraft::init();
|
Minecraft::init();
|
||||||
|
|
||||||
#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) && !defined(NO_STORAGE)
|
#if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) && !defined(NO_STORAGE)
|
||||||
|
|||||||
@@ -1143,6 +1143,8 @@ void Minecraft::init()
|
|||||||
checkGlError("Init complete");
|
checkGlError("Init complete");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
options.load();
|
||||||
|
|
||||||
setIsCreativeMode(false); // false means it's Survival Mode
|
setIsCreativeMode(false); // false means it's Survival Mode
|
||||||
reloadOptions();
|
reloadOptions();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,6 +285,10 @@ void Options::save() {
|
|||||||
optionsFile.save(stringVec);
|
optionsFile.save(stringVec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Options::setOptionsFilePath(const std::string& path) {
|
||||||
|
optionsFile.setOptionsPath(path + "/options.txt");
|
||||||
|
}
|
||||||
|
|
||||||
void Options::notifyOptionUpdate(OptionId key, bool value) {
|
void Options::notifyOptionUpdate(OptionId key, bool value) {
|
||||||
minecraft->optionUpdated(key, value);
|
minecraft->optionUpdated(key, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,15 +101,10 @@ public:
|
|||||||
// elements werent initialized so i was getting a garbage pointer and a crash
|
// elements werent initialized so i was getting a garbage pointer and a crash
|
||||||
m_options.fill(nullptr);
|
m_options.fill(nullptr);
|
||||||
initTable();
|
initTable();
|
||||||
load();
|
// load() is deferred to init() where path is configured correctly
|
||||||
}
|
}
|
||||||
|
|
||||||
void initTable();
|
void initTable();
|
||||||
|
|
||||||
void set(OptionId key, int value);
|
|
||||||
void set(OptionId key, float value);
|
|
||||||
void set(OptionId key, const std::string& value);
|
|
||||||
void toggle(OptionId key);
|
|
||||||
|
|
||||||
int getIntValue(OptionId key) {
|
int getIntValue(OptionId key) {
|
||||||
auto option = opt<OptionInt>(key);
|
auto option = opt<OptionInt>(key);
|
||||||
@@ -145,6 +140,11 @@ public:
|
|||||||
|
|
||||||
void load();
|
void load();
|
||||||
void save();
|
void save();
|
||||||
|
void set(OptionId key, int value);
|
||||||
|
void set(OptionId key, float value);
|
||||||
|
void set(OptionId key, const std::string& value);
|
||||||
|
void setOptionsFilePath(const std::string& path);
|
||||||
|
void toggle(OptionId key);
|
||||||
|
|
||||||
void notifyOptionUpdate(OptionId key, bool value);
|
void notifyOptionUpdate(OptionId key, bool value);
|
||||||
void notifyOptionUpdate(OptionId key, float value);
|
void notifyOptionUpdate(OptionId key, float value);
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <platform/log.h>
|
#include <platform/log.h>
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
OptionsFile::OptionsFile() {
|
OptionsFile::OptionsFile() {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
settingsPath = "./Documents/options.txt";
|
settingsPath = "./Documents/options.txt";
|
||||||
@@ -14,6 +20,14 @@ OptionsFile::OptionsFile() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OptionsFile::setOptionsPath(const std::string& path) {
|
||||||
|
settingsPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OptionsFile::getOptionsPath() const {
|
||||||
|
return settingsPath;
|
||||||
|
}
|
||||||
|
|
||||||
void OptionsFile::save(const StringVector& settings) {
|
void OptionsFile::save(const StringVector& settings) {
|
||||||
FILE* pFile = fopen(settingsPath.c_str(), "w");
|
FILE* pFile = fopen(settingsPath.c_str(), "w");
|
||||||
if(pFile != NULL) {
|
if(pFile != NULL) {
|
||||||
@@ -22,10 +36,33 @@ void OptionsFile::save(const StringVector& settings) {
|
|||||||
}
|
}
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
} else {
|
} else {
|
||||||
LOGI("OptionsFile::save failed to open '%s' for writing: %s", settingsPath.c_str(), strerror(errno));
|
if (errno != ENOENT)
|
||||||
|
LOGI("OptionsFile::save failed to open '%s' for writing: %s", settingsPath.c_str(), strerror(errno));
|
||||||
|
|
||||||
|
// Ensure parent directory exists for safekeeping if path contains directories
|
||||||
|
std::string dir = settingsPath;
|
||||||
|
size_t fpos = dir.find_last_of("/\\");
|
||||||
|
if (fpos != std::string::npos) {
|
||||||
|
dir.resize(fpos);
|
||||||
|
struct stat st;
|
||||||
|
if (stat(dir.c_str(), &st) != 0) {
|
||||||
|
// attempt recursive mkdir
|
||||||
|
std::string toCreate;
|
||||||
|
for (size_t i = 0; i <= dir.size(); ++i) {
|
||||||
|
if (i == dir.size() || dir[i] == '/' || dir[i] == '\\') {
|
||||||
|
if (!toCreate.empty()) {
|
||||||
|
mkdir(toCreate.c_str(), 0755);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < dir.size())
|
||||||
|
toCreate.push_back(dir[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StringVector OptionsFile::getOptionStrings() {
|
StringVector OptionsFile::getOptionStrings() {
|
||||||
StringVector returnVector;
|
StringVector returnVector;
|
||||||
FILE* pFile = fopen(settingsPath.c_str(), "r");
|
FILE* pFile = fopen(settingsPath.c_str(), "r");
|
||||||
@@ -46,7 +83,8 @@ StringVector OptionsFile::getOptionStrings() {
|
|||||||
}
|
}
|
||||||
fclose(pFile);
|
fclose(pFile);
|
||||||
} else {
|
} else {
|
||||||
LOGI("OptionsFile::getOptionStrings failed to open '%s' for reading: %s", settingsPath.c_str(), strerror(errno));
|
if (errno != ENOENT)
|
||||||
|
LOGI("OptionsFile::getOptionStrings failed to open '%s' for reading: %s", settingsPath.c_str(), strerror(errno));
|
||||||
}
|
}
|
||||||
return returnVector;
|
return returnVector;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ public:
|
|||||||
OptionsFile();
|
OptionsFile();
|
||||||
void save(const StringVector& settings);
|
void save(const StringVector& settings);
|
||||||
StringVector getOptionStrings();
|
StringVector getOptionStrings();
|
||||||
|
void setOptionsPath(const std::string& path);
|
||||||
|
std::string getOptionsPath() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string settingsPath;
|
std::string settingsPath;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -187,6 +187,33 @@ static bool ensureDirectoryExists(const std::string& path) {
|
|||||||
return _mkdir(path.c_str()) == 0 || errno == EEXIST;
|
return _mkdir(path.c_str()) == 0 || errno == EEXIST;
|
||||||
#else
|
#else
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
std::string subPath;
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < path.length()) {
|
||||||
|
i = path.find_first_of("/\\", i);
|
||||||
|
if (i == std::string::npos) {
|
||||||
|
subPath = path;
|
||||||
|
} else {
|
||||||
|
subPath = path.substr(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!subPath.empty()) {
|
||||||
|
if (stat(subPath.c_str(), &st) != 0) {
|
||||||
|
if (mkdir(subPath.c_str(), 0755) != 0 && errno != EEXIST)
|
||||||
|
return false;
|
||||||
|
} else if (!S_ISDIR(st.st_mode)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == std::string::npos)
|
||||||
|
break;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode))
|
if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode))
|
||||||
return true;
|
return true;
|
||||||
return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST;
|
return mkdir(path.c_str(), 0755) == 0 || errno == EEXIST;
|
||||||
@@ -236,7 +263,8 @@ static void* fetchSkinForPlayer(void* param) {
|
|||||||
std::vector<unsigned char> skinData;
|
std::vector<unsigned char> skinData;
|
||||||
if (!HttpClient::download(skinUrl, skinData) || skinData.empty()) {
|
if (!HttpClient::download(skinUrl, skinData) || skinData.empty()) {
|
||||||
LOGW("[Skin] download failed for %s\n", skinUrl.c_str());
|
LOGW("[Skin] download failed for %s\n", skinUrl.c_str());
|
||||||
return NULL;
|
player->setTextureName("mob/char.png");
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to cache
|
// Save to cache
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void additionalRendering(Mob* mob, float a);
|
void additionalRendering(Mob* mob, float a);
|
||||||
|
|
||||||
private:
|
|
||||||
HumanoidModel* humanoidModel;
|
HumanoidModel* humanoidModel;
|
||||||
|
|
||||||
// Last rotation values for cape smoothing (reduces jitter)
|
// Last rotation values for cape smoothing (reduces jitter)
|
||||||
float lastCapeXRot;
|
float lastCapeXRot;
|
||||||
float lastCapeZRot;
|
float lastCapeZRot;
|
||||||
|
private:
|
||||||
|
// i guess ill keep this just in case seomthing breaks
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/
|
#endif /*NET_MINECRAFT_CLIENT_RENDERER_ENTITY__HumanoidMobRenderer_H__*/
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void setArmor(Model* armor);
|
void setArmor(Model* armor);
|
||||||
Model* getArmor();
|
Model* getArmor();
|
||||||
|
Model* model; // allows derived renderers to swap models dynamically for skin formats
|
||||||
private:
|
private:
|
||||||
Model* model;
|
|
||||||
Model* armor;
|
Model* armor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "PlayerRenderer.h"
|
#include "PlayerRenderer.h"
|
||||||
#include "EntityRenderDispatcher.h"
|
#include "EntityRenderDispatcher.h"
|
||||||
|
#include "../Textures.h"
|
||||||
#include "../../../world/entity/player/Player.h"
|
#include "../../../world/entity/player/Player.h"
|
||||||
#include "../../../world/level/Level.h"
|
#include "../../../world/level/Level.h"
|
||||||
#include "../../../world/item/ArmorItem.h"
|
#include "../../../world/item/ArmorItem.h"
|
||||||
@@ -14,12 +15,22 @@ static const std::string armorFilenames[10] = {
|
|||||||
|
|
||||||
PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow )
|
PlayerRenderer::PlayerRenderer( HumanoidModel* humanoidModel, float shadow )
|
||||||
: super(humanoidModel, shadow),
|
: super(humanoidModel, shadow),
|
||||||
|
playerModel64(humanoidModel),
|
||||||
|
playerModel32(new HumanoidModel(0, 0, 64, 32)),
|
||||||
armorParts1(new HumanoidModel(1.0f, 0, 64, 64)),
|
armorParts1(new HumanoidModel(1.0f, 0, 64, 64)),
|
||||||
armorParts2(new HumanoidModel(0.5f, 0, 64, 64))
|
armorParts2(new HumanoidModel(0.5f, 0, 64, 64))
|
||||||
{
|
{
|
||||||
|
// default to legacy skin path until we know the exact texture size
|
||||||
|
model = playerModel32;
|
||||||
|
humanoidModel = playerModel32;
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerRenderer::~PlayerRenderer() {
|
PlayerRenderer::~PlayerRenderer() {
|
||||||
|
// prevent MobRenderer destructor from deleting model pointers we manage manually
|
||||||
|
model = nullptr;
|
||||||
|
|
||||||
|
delete playerModel32;
|
||||||
|
delete playerModel64;
|
||||||
delete armorParts1;
|
delete armorParts1;
|
||||||
delete armorParts2;
|
delete armorParts2;
|
||||||
}
|
}
|
||||||
@@ -43,6 +54,15 @@ void PlayerRenderer::setupRotations( Entity* mob, float bob, float bodyRot, floa
|
|||||||
super::setupRotations(mob, bob, bodyRot, a);
|
super::setupRotations(mob, bob, bodyRot, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PlayerRenderer::isModernPlayerSkin(Mob* mob) {
|
||||||
|
const std::string texName = mob->getTexture();
|
||||||
|
TextureId texId = entityRenderDispatcher->textures->loadTexture(texName);
|
||||||
|
if (!Textures::isTextureIdValid(texId))
|
||||||
|
return false;
|
||||||
|
const TextureData* texData = entityRenderDispatcher->textures->getTemporaryTextureData(texId);
|
||||||
|
return texData && texData->w == 64 && texData->h == 64;
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){
|
void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){
|
||||||
//@todo: figure out how to handle HideGUI
|
//@todo: figure out how to handle HideGUI
|
||||||
if (mob != entityRenderDispatcher->cameraEntity && mob->level->adventureSettings.showNameTags) {
|
if (mob != entityRenderDispatcher->cameraEntity && mob->level->adventureSettings.showNameTags) {
|
||||||
@@ -50,6 +70,20 @@ void PlayerRenderer::renderName( Mob* mob, float x, float y, float z ){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerRenderer::render(Entity* mob_, float x, float y, float z, float rot, float a) {
|
||||||
|
Mob* mob = (Mob*) mob_;
|
||||||
|
HumanoidModel* desired = isModernPlayerSkin(mob) ? playerModel64 : playerModel32;
|
||||||
|
if (model != desired || humanoidModel != desired) {
|
||||||
|
model = desired;
|
||||||
|
humanoidModel = desired;
|
||||||
|
}
|
||||||
|
// LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n",
|
||||||
|
// ((Player*)mob)->name.c_str(), mob->getTexture().c_str(),
|
||||||
|
// humanoidModel->texWidth, humanoidModel->texHeight,
|
||||||
|
// (desired == playerModel64 ? "64" : "32"));
|
||||||
|
HumanoidMobRenderer::render(mob_, x, y, z, rot, a);
|
||||||
|
}
|
||||||
|
|
||||||
int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) {
|
int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) {
|
||||||
Player* player = (Player*) mob;
|
Player* player = (Player*) mob;
|
||||||
|
|
||||||
@@ -80,8 +114,11 @@ int PlayerRenderer::prepareArmor(Mob* mob, int layer, float a) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PlayerRenderer::onGraphicsReset() {
|
void PlayerRenderer::onGraphicsReset() {
|
||||||
super::onGraphicsReset();
|
if (playerModel32) playerModel32->onGraphicsReset();
|
||||||
|
if (playerModel64) playerModel64->onGraphicsReset();
|
||||||
|
|
||||||
if (armorParts1) armorParts1->onGraphicsReset();
|
if (armorParts1) armorParts1->onGraphicsReset();
|
||||||
if (armorParts2) armorParts2->onGraphicsReset();
|
if (armorParts2) armorParts2->onGraphicsReset();
|
||||||
|
|
||||||
|
super::onGraphicsReset();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ public:
|
|||||||
~PlayerRenderer();
|
~PlayerRenderer();
|
||||||
|
|
||||||
virtual int prepareArmor(Mob* mob, int layer, float a);
|
virtual int prepareArmor(Mob* mob, int layer, float a);
|
||||||
|
bool isModernPlayerSkin(Mob* mob);
|
||||||
|
virtual void render(Entity* mob, float x, float y, float z, float rot, float a);
|
||||||
|
|
||||||
virtual void setupPosition(Entity* mob, float x, float y, float z);
|
virtual void setupPosition(Entity* mob, float x, float y, float z);
|
||||||
virtual void setupRotations(Entity* mob, float bob, float bodyRot, float a);
|
virtual void setupRotations(Entity* mob, float bob, float bodyRot, float a);
|
||||||
@@ -18,6 +20,8 @@ public:
|
|||||||
virtual void renderName(Mob* mob, float x, float y, float z);
|
virtual void renderName(Mob* mob, float x, float y, float z);
|
||||||
virtual void onGraphicsReset();
|
virtual void onGraphicsReset();
|
||||||
private:
|
private:
|
||||||
|
HumanoidModel* playerModel32;
|
||||||
|
HumanoidModel* playerModel64;
|
||||||
HumanoidModel* armorParts1;
|
HumanoidModel* armorParts1;
|
||||||
HumanoidModel* armorParts2;
|
HumanoidModel* armorParts2;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,12 +25,33 @@ static void setupExternalPath(struct android_app* state, MAIN_CLASS* app)
|
|||||||
{
|
{
|
||||||
LOGI("Environment exists");
|
LOGI("Environment exists");
|
||||||
}
|
}
|
||||||
jclass clazz = env->FindClass("android/os/Environment");
|
// try appspecific external directory first
|
||||||
jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;");
|
jobject activity = state->activity->clazz;
|
||||||
if (env->ExceptionOccurred()) {
|
jclass activityClass = env->GetObjectClass(activity);
|
||||||
env->ExceptionDescribe();
|
jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
|
||||||
|
|
||||||
|
jobject file = NULL;
|
||||||
|
if (getExternalFilesDir != NULL) {
|
||||||
|
file = env->CallObjectMethod(activity, getExternalFilesDir, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
// Fallback to the legacy shared storage directory
|
||||||
|
jclass clazz = env->FindClass("android/os/Environment");
|
||||||
|
jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;");
|
||||||
|
if (env->ExceptionOccurred()) {
|
||||||
|
env->ExceptionDescribe();
|
||||||
|
env->ExceptionClear();
|
||||||
|
}
|
||||||
|
file = env->CallStaticObjectMethod(clazz, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
LOGI("Failed to get external storage file object, using current working dir");
|
||||||
|
app->externalStoragePath = ".";
|
||||||
|
app->externalCacheStoragePath = ".";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
jobject file = env->CallStaticObjectMethod(clazz, method);
|
|
||||||
|
|
||||||
jclass fileClass = env->GetObjectClass(file);
|
jclass fileClass = env->GetObjectClass(file);
|
||||||
jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
|
jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
|
||||||
@@ -38,7 +59,7 @@ static void setupExternalPath(struct android_app* state, MAIN_CLASS* app)
|
|||||||
|
|
||||||
const char* str = env->GetStringUTFChars((jstring) pathString, NULL);
|
const char* str = env->GetStringUTFChars((jstring) pathString, NULL);
|
||||||
app->externalStoragePath = str;
|
app->externalStoragePath = str;
|
||||||
app->externalCacheStoragePath = str;
|
app->externalCacheStoragePath = str;
|
||||||
LOGI("%s", str);
|
LOGI("%s", str);
|
||||||
|
|
||||||
// ensure the process working directory is set to a writable location
|
// ensure the process working directory is set to a writable location
|
||||||
|
|||||||
@@ -30,12 +30,33 @@ static void setupExternalPath(JNIEnv* env, MAIN_CLASS* app)
|
|||||||
{
|
{
|
||||||
LOGI("Environment exists");
|
LOGI("Environment exists");
|
||||||
}
|
}
|
||||||
jclass clazz = env->FindClass("android/os/Environment");
|
// try appspecific external directory first
|
||||||
jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;");
|
jobject activity = g_pActivity;
|
||||||
if (env->ExceptionOccurred()) {
|
jclass activityClass = env->GetObjectClass(activity);
|
||||||
env->ExceptionDescribe();
|
jmethodID getExternalFilesDir = env->GetMethodID(activityClass, "getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
|
||||||
|
|
||||||
|
jobject file = NULL;
|
||||||
|
if (getExternalFilesDir != NULL) {
|
||||||
|
file = env->CallObjectMethod(activity, getExternalFilesDir, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
// Fallback to the legacy shared storage directory
|
||||||
|
jclass clazz = env->FindClass("android/os/Environment");
|
||||||
|
jmethodID method = env->GetStaticMethodID(clazz, "getExternalStorageDirectory", "()Ljava/io/File;");
|
||||||
|
if (env->ExceptionOccurred()) {
|
||||||
|
env->ExceptionDescribe();
|
||||||
|
env->ExceptionClear();
|
||||||
|
}
|
||||||
|
file = env->CallStaticObjectMethod(clazz, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
LOGI("Failed to get external storage file object, using current working dir");
|
||||||
|
app->externalStoragePath = ".";
|
||||||
|
app->externalCacheStoragePath = ".";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
jobject file = env->CallStaticObjectMethod(clazz, method);
|
|
||||||
|
|
||||||
jclass fileClass = env->GetObjectClass(file);
|
jclass fileClass = env->GetObjectClass(file);
|
||||||
jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
|
jmethodID fileMethod = env->GetMethodID(fileClass, "getAbsolutePath", "()Ljava/lang/String;");
|
||||||
@@ -43,7 +64,7 @@ static void setupExternalPath(JNIEnv* env, MAIN_CLASS* app)
|
|||||||
|
|
||||||
const char* str = env->GetStringUTFChars((jstring) pathString, NULL);
|
const char* str = env->GetStringUTFChars((jstring) pathString, NULL);
|
||||||
app->externalStoragePath = str;
|
app->externalStoragePath = str;
|
||||||
app->externalCacheStoragePath = str;
|
app->externalCacheStoragePath = str;
|
||||||
LOGI("%s", str);
|
LOGI("%s", str);
|
||||||
|
|
||||||
// same fix as the native entry point: make sure cwd is writable
|
// same fix as the native entry point: make sure cwd is writable
|
||||||
|
|||||||
Reference in New Issue
Block a user