add dedicated server and readme

This commit is contained in:
murdle 2026-01-19 20:18:08 +02:00
parent bb00b43b3c
commit 5867993997
39 changed files with 1277 additions and 83 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.vscode
.idea/
assets/
data/

View File

@ -13,9 +13,6 @@ link_directories(/usr/lib32)
include_directories(/usr/include)
set(X11_X11_LIB /usr/lib32/libX11.so)
#SET(CMAKE_CXX_COMPILER "g++-4.9")
#SET(CMAKE_C_COMPILER "gcc-4.9")
find_package(Threads REQUIRED)
find_package(ZLIB REQUIRED)
find_package(X11 REQUIRED)
@ -27,11 +24,19 @@ include_directories(${EGL_INCLUDE_DIRS})
include_directories(eglut)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0")
set(HYBRIS_DEFINES PRIVATE ANDROID_X86_LINKER _GNU_SOURCE LINKER_TEXT_BASE=0xB0000100 LINKER_AREA_SIZE=0x01000000 LINKER_DEBUG=1)
set(HYBRIS_SOURCES hybris/src/cache.c hybris/src/dlfcn.c hybris/src/hooks.c hybris/src/hooks_shm.c hybris/src/logging.c hybris/src/properties.c hybris/src/strlcpy.c hybris/src/sysconf.c hybris/src/jb/dlfcn.c hybris/src/jb/linker.c hybris/src/jb/linker_environ.c hybris/src/jb/linker_format.c hybris/src/jb/rt.c)
set(EGLUT_SOURCES eglut/eglut.c eglut/eglut_x11.c)
set(SOURCE_FILES src/main.cpp src/common.cpp src/hook.cpp src/amdfix.s src/LinuxAppPlatform.cpp mcpe/types.cpp mcpe/ImagePickingCallback.h mcpe/FilePickerSettings.h)
add_executable(mcpelauncher ${HYBRIS_SOURCES} ${EGLUT_SOURCES} ${SOURCE_FILES})
set(COMMON_SOURCE_FILES src/common.cpp src/hook.cpp src/linux_app_platform.cpp mcpe/types.cpp mcpe/string.cpp)
set(CLIENT_SOURCE_FILES src/main.cpp src/amdfix.s)
set(SERVER_SOURCE_FILES src/server.cpp src/server_properties.cpp)
add_executable(mcpelauncher ${HYBRIS_SOURCES} ${EGLUT_SOURCES} ${COMMON_SOURCE_FILES} ${CLIENT_SOURCE_FILES})
target_link_libraries(mcpelauncher ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} rt libEGL.so libGLESv2.so ${X11_X11_LIB} uuid)
target_compile_definitions(mcpelauncher PRIVATE ANDROID_X86_LINKER _GNU_SOURCE LINKER_TEXT_BASE=0xB0000100 LINKER_AREA_SIZE=0x01000000 LINKER_DEBUG=1)
target_compile_definitions(mcpelauncher ${HYBRIS_DEFINES})
set_target_properties(mcpelauncher PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
add_executable(server ${HYBRIS_SOURCES} ${COMMON_SOURCE_FILES} ${SERVER_SOURCE_FILES})
target_link_libraries(server ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} ${X11_X11_LIB} rt uuid z zip)
target_compile_definitions(server ${HYBRIS_DEFINES} SERVER)

53
FindEGL.cmake Normal file
View File

@ -0,0 +1,53 @@
# - Try to Find EGL
# Once done, this will define
#
# EGL_FOUND - system has EGL installed.
# EGL_INCLUDE_DIRS - directories which contain the EGL headers.
# EGL_LIBRARIES - libraries required to link against EGL.
# EGL_DEFINITIONS - Compiler switches required for using EGL.
#
# Copyright (C) 2012 Intel Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
find_package(PkgConfig)
pkg_check_modules(PC_EGL egl)
if (PC_EGL_FOUND)
set(EGL_DEFINITIONS ${PC_EGL_CFLAGS_OTHER})
endif ()
find_path(EGL_INCLUDE_DIRS NAMES EGL/egl.h
HINTS ${PC_EGL_INCLUDEDIR} ${PC_EGL_INCLUDE_DIRS}
)
set(EGL_NAMES ${EGL_NAMES} egl EGL)
find_library(EGL_LIBRARIES NAMES ${EGL_NAMES}
HINTS ${PC_EGL_LIBDIR} ${PC_EGL_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(EGL DEFAULT_MSG EGL_INCLUDE_DIRS EGL_LIBRARIES)
mark_as_advanced(EGL_INCLUDE_DIRS EGL_LIBRARIES)

View File

@ -1,42 +1,62 @@
MCPE Linux Launcher
===================
## Required packages
A fork of [mcpelauncher-linux](https://github.com/MCMrARM/mcpelauncher-linux) (commit from 2017, MCPE 1.1) with additional features and improvements
```
sudo apt-get install cmake zlib1g-dev:i386 libncurses5-dev:i386 libgles2-mesa-dev gcc-multilib g++-multilib zlib1g-dev:i386 libx11-dev:i386 linux-libc-dev:i386 uuid-dev:i386 libpng-dev:i386 libx11-dev:i386 libxext6:i386
## Features
- Dedicated server support
- Compatibility fixes for building with the latest GCC
- Other quality-of-life improvements
## Required Packages
### Ubuntu / Debian
Install the necessary dependencies with:
```bash
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install cmake zlib1g-dev:i386 libncurses5-dev:i386 \
libgles2-mesa-dev libegl1-mesa-dev:i386 gcc-multilib g++-multilib \
libx11-dev:i386 linux-libc-dev:i386 uuid-dev:i386 libpng-dev:i386 \
libxext6:i386
```
If g++-4.9 fails to install and you're using Ubuntu 14.04 you may need to add the repository ppa:ubuntu-toolchain-r/test.
### Arch Linux
Install the necessary dependencies with:
You'll also need to install 32-bit version of the graphic drivers (nvidia drivers ask you about that at installation, so
you may need to reinstall/reconfigure them; if you use mesa you'll need to install the libgles2-mesa-dev:i386 and
libegl1-mesa-dev:i386 packages)
```bash
sudo pacman -Syu base-devel cmake zlib libpng libx11 libxext libglvnd \
libxrandr libxi mesa lib32-gcc-libs lib32-glibc lib32-mesa lib32-libx11 \
lib32-libxext lib32-libxrandr lib32-libxi
```
You may also need to do `sudo dpkg --add-architecture i386` if you have never installed i386 packages before.
Make sure the multilib repo is enabled in `/etc/pacman.conf`.
## Compiling
This app uses cmake so it is enough to do:
```
cmake .
mkdir build
cmake ..
make
```
## Running
1. Clone this repository
2. Compile the launcher
3. You'll need to obtain a x86 MCPE .apk. The easiest way to do so is to use the
[Google Play downloader tool](https://github.com/MCMrARM/Google-Play-API) (it is an console app; remember that
you need to type 'y' when you are asked if you want to use x86 as the architecture, and you must have purchased MCPE
on the Google account you are logging in with; the package name of MCPE is `com.mojang.minecraftpe`)
3. Obtain a x86 MCPE 1.1 apk file
4. After you have downloaded MCPE, place it in the directory where you'll be running this app, and run ./extract.sh _filename_
5. Run the launcher!
If the extract script fails with an error about the .apk not being x86, it means that you have provided it a bad .apk.
You'll need to purchase MCPE on Google Play and use the downloader tool.
## Using the Dedicated Server
1. Create a server.properties file and fill in your settings. An example is located in the root of this repository.
2. Run the server binary that you built earlier
## License and thanks
Most of the code in this repo is licensed under BSD. This project uses libc, libstdc++, libz and libm - libraries
- Credit goes to [MCMrARM](https://github.com/MCMrARM) for the original source code
- Most of the code in this repo is licensed under BSD. This project uses libc, libstdc++, libz and libm - libraries
extracted from the Android OS. A modified version of libhybris is also included, which is licensed under GPL. This project
also uses the EGLUT library and FMOD library (for sound).

19
mcpe/Api.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
namespace minecraft {
namespace api {
class Api {
public:
void** vtable;
mcpe::string envPath;
void** playerIfaceVtable;
void** entityIfaceVtable;
void** networkIfaceVtable;
void** playerInteractionsIfaceVtable;
};
}
}

19
mcpe/AppResourceLoader.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "string.h"
#include <functional>
#include "Resource.h"
class AppResourceLoader : public ResourceLoader {
private:
char filler[0x14];
public:
static void (*AppResourceLoader_construct)(AppResourceLoader*, std::function<mcpe::string ()>);
AppResourceLoader(std::function<mcpe::string ()> f) {
AppResourceLoader_construct(this, f);
}
};

22
mcpe/AutomationClient.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "IMinecraftApp.h"
namespace Automation {
class AutomationClient {
public:
static void (*AutomationClient_construct)(AutomationClient*, IMinecraftApp&);
char filler[0x300];
AutomationClient(IMinecraftApp& a) {
AutomationClient_construct(this, a);
}
};
}

16
mcpe/EntitlementManager.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <string>
namespace Social { class UserManager; }
class MinecraftEventing;
class EntitlementManager {
public:
char filler[0x100];
static void (*EntitlementManager_construct)(EntitlementManager*, MinecraftEventing&, Social::UserManager&);
EntitlementManager(MinecraftEventing &evt, Social::UserManager &um) {
EntitlementManager_construct(this, evt, um);
}
};

70
mcpe/FilePathManager.h Normal file
View File

@ -0,0 +1,70 @@
#pragma once
#include <string>
#include "string.h"
class FilePathManager {
public:
char filler[0x20];
static void (*FilePathManager_construct)(
FilePathManager*,
mcpe::string,
bool
);
static mcpe::string (*FilePathManager_getRootPath)(
FilePathManager const*
);
static mcpe::string (*FilePathManager_getUserDataPath)(
FilePathManager const*
);
static void (*FilePathManager_setPackagePath)(
FilePathManager*,
mcpe::string
);
static mcpe::string (*FilePathManager_getPackagePath)(
FilePathManager const*
);
static void (*FilePathManager_setSettingsPath)(
FilePathManager*,
mcpe::string
);
static mcpe::string (*FilePathManager_getSettingsPath)(
FilePathManager const*
);
FilePathManager(mcpe::string str, bool b) {
FilePathManager_construct(this, std::move(str), b);
}
mcpe::string getRootPath() const {
return FilePathManager_getRootPath(this);
}
mcpe::string getUserDataPath() const {
return FilePathManager_getUserDataPath(this);
}
void setPackagePath(mcpe::string s) {
FilePathManager_setPackagePath(this, std::move(s));
}
mcpe::string getPackagePath() const {
return FilePathManager_getPackagePath(this);
}
void setSettingsPath(mcpe::string s) {
FilePathManager_setSettingsPath(this, std::move(s));
}
mcpe::string getSettingsPath() const {
return FilePathManager_getSettingsPath(this);
}
};

View File

@ -1,6 +1,6 @@
#pragma once
#include <string>
#include "string.h"
#include <vector>
#include <functional>
@ -10,15 +10,15 @@ struct FilePickerSettings {
NONE, OPEN, SAVE
};
struct FileDescription {
std::string ext, desc;
mcpe::string ext, desc;
};
char filler [0x20]; // 20
std::function<void (FilePickerSettings&, std::string)> pickedCallback; // 30
std::vector<FileDescription> fileDescriptions; // 3c
int filler3; // 40
PickerType type; // 44
std::string defaultFileName; // 48
std::string pickerTitle; // 52
char filler [0x20];
std::function<void (FilePickerSettings&, mcpe::string)> pickedCallback;
std::vector<FileDescription> fileDescriptions;
int filler3;
PickerType type;
mcpe::string defaultFileName;
mcpe::string pickerTitle;
};

21
mcpe/IMinecraftApp.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
class Minecraft;
namespace Automation {
class AutomationClient;
}
class IMinecraftApp {
public:
virtual ~IMinecraftApp() { }
virtual Minecraft* getPrimaryMinecraft() = 0;
virtual Automation::AutomationClient* getAutomationClient() = 0;
virtual bool isEduMode() = 0;
virtual bool isDedicatedServer() = 0;
virtual int getDefaultNetworkMaxPlayers() = 0;
virtual void onNetworkMaxPlayersChanged(unsigned int) = 0;
};

View File

@ -6,7 +6,7 @@ class ImagePickingCallback {
public:
virtual ~ImagePickingCallback();
virtual void onImagePickingSuccess(const std::string&);
virtual void onImagePickingSuccess(const mcpe::string&);
virtual void onImagePickingCanceled();
};

View File

@ -9,7 +9,7 @@ class Keyboard {
public:
static void (*Keyboard_feedText)(const std::string&, bool, unsigned char);
static void (*Keyboard_feedText)(const mcpe::string&, bool, unsigned char);
static std::vector<KeyboardAction>* inputs;
static int* states;

25
mcpe/LevelSettings.h Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <cstdint>
#include <cstring>
class LevelSettings {
public:
static void (*LevelSettings_construct)(LevelSettings*);
int seed; // 4
int gametype; // 8
int difficulty; // c
int forceGameType; // 10
int generator; // 14
bool hasAchievementsDisabled; // 18
int dimension; // 1c
int time; // 20
bool edu; // 21
float rainLevel, lightningLevel; // 28, 2c
bool mpGame, lanBroadcast, xblBroadcast, commandsEnabled, texturepacksRequired, overrideSavedSettings; // 2d, 2e, 2f, 30, 31, 32~34
char filler[0x300];
LevelSettings() {
LevelSettings_construct(this);
}
};

12
mcpe/MinecraftEventing.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
class MinecraftEventing {
public:
char filler[0x200];
static void (*MinecraftEventing_construct)(MinecraftEventing*, mcpe::string const&);
MinecraftEventing(mcpe::string const& str) {
MinecraftEventing_construct(this, str);
}
};

View File

@ -3,6 +3,9 @@
#include "App.h"
class Options;
class MinecraftEventing;
class ResourcePackRepository;
class ResourcePackManager;
class MinecraftGame : public App {

12
mcpe/OpsList.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
struct OpsList {
struct Entry {
char filler[0x10];
};
bool b;
std::vector<Entry> entries;
};

18
mcpe/Resource.h Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <memory>
enum class ResourceFileSystem;
class ResourceLoader {
};
class Resource {
public:
static void (*Resource_registerLoader)(ResourceFileSystem, std::unique_ptr<ResourceLoader>);
static void registerLoader(ResourceFileSystem fs, std::unique_ptr<ResourceLoader> loader) {
Resource_registerLoader(fs, std::move(loader));
}
};

59
mcpe/ResourcePack.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include <string>
#include <functional>
class MinecraftEventing;
class FilePathManager;
class ResourcePack;
class ResourcePackStack;
class ResourceLoader;
enum class ResourcePackStackType;
class PackManifestFactory {
public:
char filler[4];
static void (*PackManifestFactory_construct)(PackManifestFactory*, MinecraftEventing&);
PackManifestFactory(MinecraftEventing& ev) {
PackManifestFactory_construct(this, ev);
}
};
class ResourcePackRepository {
public:
char filler[0x1C];
ResourcePack* vanillaPack;
char filler2[0x200];
static void (*ResourcePackRepository_construct)(ResourcePackRepository*, MinecraftEventing&, PackManifestFactory&, EntitlementManager*, FilePathManager*);
ResourcePackRepository(MinecraftEventing& ev, PackManifestFactory& factory, EntitlementManager* em, FilePathManager* fpm) {
ResourcePackRepository_construct(this, ev, factory, em, fpm);
}
};
class ResourcePackManager: public ResourceLoader {
public:
char filler[0x200];
static void (*ResourcePackManager_construct)(ResourcePackManager*, std::function<mcpe::string ()> const);
static void (*ResourcePackManager_setStack)(ResourcePackManager*, std::unique_ptr<ResourcePackStack>, ResourcePackStackType, bool);
ResourcePackManager(std::function<mcpe::string ()> const& f) {
ResourcePackManager_construct(this, f);
}
void setStack(std::unique_ptr<ResourcePackStack>&& stackPtr, ResourcePackStackType stackType, bool b) {
ResourcePackManager_setStack(this, std::move(stackPtr), stackType, b);
}
};

24
mcpe/ResourcePackStack.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <cstring>
class ResourcePack;
class ResourcePackRepository;
struct ResourcePackStack {
static void** vtable_sym;
static void (*ResourcePackStack_add)(ResourcePackStack*, ResourcePack*, ResourcePackRepository const&, bool);
void** vtable;
char filler[0x30];
ResourcePackStack() {
vtable = vtable_sym + 2;
memset(filler, 0, sizeof(filler));
}
void add(ResourcePack* resPack, ResourcePackRepository const& repo, bool b) {
ResourcePackStack_add(this, resPack, repo, b);
}
};

17
mcpe/Scheduler.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <chrono>
struct Scheduler {
public:
static Scheduler* (*singleton)();
static void (*Scheduler_processCoroutines)(Scheduler*, std::chrono::duration<long long>);
void processCoroutines(std::chrono::duration<long long> d) {
Scheduler_processCoroutines(this, d);
}
};

64
mcpe/ServerInstance.h Normal file
View File

@ -0,0 +1,64 @@
#pragma once
#include <chrono>
#include <vector>
#include <string>
#include <functional>
#include "string.h"
class IMinecraftApp;
class Minecraft;
class Whitelist;
class OpsList;
class LevelSettings;
class FilePathManager;
namespace minecraft { namespace api { class Api; } }
namespace mce { class UUID; }
class MinecraftEventing;
class ResourcePackRepository;
class ResourcePackManager;
class ServerInstance {
public:
char filler[0x300];
static void (*ServerInstance_construct)(
ServerInstance*,
IMinecraftApp&,
Whitelist const&,
OpsList const&,
FilePathManager*,
std::chrono::duration<long long>,
mcpe::string,
mcpe::string,
mcpe::string,
mcpe::string,
mcpe::string,
LevelSettings*,
minecraft::api::Api&,
int,
bool,
int,
int,
int,
bool,
std::vector<mcpe::string> const&,
mcpe::string,
bool,
mce::UUID const&,
MinecraftEventing&,
ResourcePackRepository&,
ResourcePackManager&,
ResourcePackManager*
);
static void (*ServerInstance_update)(ServerInstance*);
void update() {
ServerInstance_update(this);
}
};

37
mcpe/Social.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <memory>
#include <cstring>
class ScreenStack;
namespace Social {
class XboxLiveUserManager {
public:
char filler[0x100];
static void (*XboxLiveUserManager_construct)(XboxLiveUserManager*, ScreenStack*);
XboxLiveUserManager() {
XboxLiveUserManager_construct(this, nullptr);
}
};
class UserManager {
public:
char filler[0x100];
static void (*UserManager_construct)(UserManager*);
static void (*UserManager_addUser)(UserManager*, std::unique_ptr<Social::XboxLiveUserManager>, bool);
UserManager() {
UserManager_construct(this);
}
void addUser(std::unique_ptr<Social::XboxLiveUserManager> manager) {
UserManager_addUser(this, std::move(manager), false);
}
};
}

14
mcpe/UUID.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
namespace mce {
class UUID {
public:
static UUID* EMPTY;
char filler[0x14];
};
}

11
mcpe/Whitelist.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
struct Whitelist {
struct Entry {
char filler[0x20];
};
std::vector<Entry> entries;
};

View File

@ -1,10 +1,11 @@
#pragma once
#include "string.h"
struct gl {
static std::string (*getOpenGLVendor)();
static std::string (*getOpenGLRenderer)();
static std::string (*getOpenGLVersion)();
static std::string (*getOpenGLExtensions)();
static mcpe::string (*getOpenGLVendor)();
static mcpe::string (*getOpenGLRenderer)();
static mcpe::string (*getOpenGLVersion)();
static mcpe::string (*getOpenGLExtensions)();
};
namespace mce {

79
mcpe/string.cpp Normal file
View File

@ -0,0 +1,79 @@
#define _GLIBCXX_USE_CXX11_ABI 0
#include "string.h"
mcpe::string* mcpe::string::empty;
mcpe::string::string() {
ptr = empty->ptr;
}
mcpe::string::string(const char *str) {
if (str[0] == '\0') {
ptr = empty->ptr;
} else {
new (this) std::string(str);
}
}
mcpe::string::string(const char *str, size_t len) {
if (len == 0) {
ptr = empty->ptr;
} else {
new (this) std::string(str, len);
}
}
mcpe::string::string(const string &str) {
if (str.ptr == empty->ptr) {
ptr = empty->ptr;
} else {
new (this) std::string(*((const std::string *) &str));
}
}
mcpe::string::~string() {
if (ptr == empty->ptr)
return;
((std::string*) this)->~basic_string<char>();
}
size_t mcpe::string::length() const {
if (ptr == empty->ptr)
return 0;
return ((std::string*) this)->length();
}
mcpe::string mcpe::string::operator+(const string &str) {
return *((std::string*) this) + *((std::string*) &str);
}
mcpe::string& mcpe::string::operator=(const mcpe::string &str) {
if (this == &str)
return *this;
if (ptr != empty->ptr) {
if (str.ptr == empty->ptr) {
((std::string*) this)->~basic_string<char>();
ptr = empty->ptr;
} else {
*((std::string*) this) = *((const std::string*) &str);
}
} else {
if (str.ptr != empty->ptr) {
new (this) std::string(*((const std::string*)&str));
}
}
return *this;
}
const char *mcpe::string::c_str() const {
if (ptr == empty->ptr)
return "";
return ((std::string*) this)->c_str();
}
std::ostream& operator<< (std::ostream& os, const mcpe::string& obj) {
os << *((std::string const*) &obj);
return os;
}

53
mcpe/string.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include <string>
#include <cstring>
namespace mcpe {
struct string {
private:
void* ptr;
public:
static mcpe::string* empty;
string();
string(const char *str);
string(const char *str, size_t len);
string(const string &str);
inline string(const std::string &str) : string(str.c_str(), str.length()) {}
~string();
string &operator=(const string &str);
size_t length() const;
const char *c_str() const;
string operator+(const string &str);
bool operator==(const string &s) const {
if (s.ptr == ptr)
return true;
if (s.length() != length())
return false;
return (memcmp(c_str(), s.c_str(), length()) == 0);
}
bool operator<(const string& s) const {
int d = memcmp(c_str(), s.c_str(), std::min(length(), s.length()));
if (d < 0) return true;
if (d == 0) return length() < s.length();
return false;
}
inline std::string std() const {
return std::string(c_str(), length());
}
};
}
std::ostream& operator<<(std::ostream&, const mcpe::string&);

View File

@ -28,10 +28,10 @@ void (*Options::Options_setFullscreen)(Options*, bool);
#include "gl.h"
std::string (*gl::getOpenGLVendor)();
std::string (*gl::getOpenGLRenderer)();
std::string (*gl::getOpenGLVersion)();
std::string (*gl::getOpenGLExtensions)();
mcpe::string (*gl::getOpenGLVendor)();
mcpe::string (*gl::getOpenGLRenderer)();
mcpe::string (*gl::getOpenGLVersion)();
mcpe::string (*gl::getOpenGLExtensions)();
void (*mce::Platform::OGL::OGL_initBindings)();
#include "Mouse.h"
@ -40,6 +40,100 @@ void (*Mouse::feed)(char, char, short, short, short, short);
#include "Keyboard.h"
void (*Keyboard::Keyboard_feedText)(const std::string&, bool, unsigned char);
void (*Keyboard::Keyboard_feedText)(const mcpe::string&, bool, unsigned char);
std::vector<KeyboardAction>* Keyboard::inputs;
int* Keyboard::states;
#include "FilePathManager.h"
void (*FilePathManager::FilePathManager_construct)(FilePathManager*, mcpe::string, bool);
mcpe::string (*FilePathManager::FilePathManager_getRootPath)(FilePathManager const*);
mcpe::string (*FilePathManager::FilePathManager_getUserDataPath)(FilePathManager const*);
void (*FilePathManager::FilePathManager_setPackagePath)(FilePathManager*, mcpe::string);
mcpe::string (*FilePathManager::FilePathManager_getPackagePath)(FilePathManager const*);
void (*FilePathManager::FilePathManager_setSettingsPath)(FilePathManager*, mcpe::string);
mcpe::string (*FilePathManager::FilePathManager_getSettingsPath)(FilePathManager const*);
#include "LevelSettings.h"
void (*LevelSettings::LevelSettings_construct)(LevelSettings*);
#include "Social.h"
void (*Social::UserManager::UserManager_construct)(Social::UserManager*);
void (*Social::UserManager::UserManager_addUser)(UserManager*, std::unique_ptr<Social::XboxLiveUserManager>, bool);
void (*Social::XboxLiveUserManager::XboxLiveUserManager_construct)(Social::XboxLiveUserManager*, ScreenStack*);
#include "MinecraftEventing.h"
void (*MinecraftEventing::MinecraftEventing_construct)(MinecraftEventing*, mcpe::string const&);
#include "EntitlementManager.h"
void (*EntitlementManager::EntitlementManager_construct)(EntitlementManager*, MinecraftEventing&, Social::UserManager&);
#include "Resource.h"
void (*Resource::Resource_registerLoader)(ResourceFileSystem, std::unique_ptr<ResourceLoader>);
#include "AppResourceLoader.h"
void (*AppResourceLoader::AppResourceLoader_construct)(AppResourceLoader*, std::function<mcpe::string ()>);
#include "ResourcePack.h"
void (*PackManifestFactory::PackManifestFactory_construct)(PackManifestFactory*, MinecraftEventing&);
void (*ResourcePackRepository::ResourcePackRepository_construct)(ResourcePackRepository*, MinecraftEventing&, PackManifestFactory&, EntitlementManager*, FilePathManager*);
void (*ResourcePackManager::ResourcePackManager_construct)(ResourcePackManager*, std::function<mcpe::string ()> const);
void (*ResourcePackManager::ResourcePackManager_setStack)(ResourcePackManager*, std::unique_ptr<ResourcePackStack>, ResourcePackStackType, bool);
#include "AutomationClient.h"
void (*Automation::AutomationClient::AutomationClient_construct)(Automation::AutomationClient*, IMinecraftApp&);
#include "ServerInstance.h"
void (*ServerInstance::ServerInstance_construct)(
ServerInstance*,
IMinecraftApp&,
Whitelist const&,
OpsList const&,
FilePathManager*,
std::chrono::duration<long long>,
mcpe::string,
mcpe::string,
mcpe::string,
mcpe::string,
mcpe::string,
LevelSettings*,
minecraft::api::Api&,
int,
bool,
int,
int,
int,
bool,
std::vector<mcpe::string> const&,
mcpe::string,
bool,
mce::UUID const&,
MinecraftEventing&,
ResourcePackRepository&,
ResourcePackManager&,
ResourcePackManager*
);
void (*ServerInstance::ServerInstance_update)(ServerInstance*);
#include "UUID.h"
mce::UUID* mce::UUID::EMPTY;
#include "ResourcePackStack.h"
void (*ResourcePackStack::ResourcePackStack_add)(ResourcePackStack*, ResourcePack*, ResourcePackRepository const&, bool);
void** ResourcePackStack::vtable_sym;
#include "Scheduler.h"
Scheduler* (*Scheduler::singleton)();
void (*Scheduler::Scheduler_processCoroutines)(Scheduler*, std::chrono::duration<long long>);

12
server.properties Normal file
View File

@ -0,0 +1,12 @@
motd=Test
view-distance=22
server-port=19132
server-port-v6=19133
max-players=20
online-mode=false
difficulty=1
gamemode=0
level-dir=oI8CAKp7BQA=
level-name=My World
level-seed=3986400852
level-type=1

View File

@ -1,5 +1,6 @@
#include "common.h"
#include <filesystem>
#include <cstdio>
#include <cstdarg>
#include <cstring>
@ -14,14 +15,25 @@ extern "C" {
#include "../hybris/include/hybris/dlfcn.h"
}
std::string getCWD() {
char _cwd[MAXPATHLEN];
getcwd(_cwd, MAXPATHLEN);
return std::string(_cwd) + "/";
std::string rootPath = "";
std::string getRootPath() {
char resolved[PATH_MAX];
const char* input = rootPath.empty() ? "." : rootPath.c_str();
if (realpath(input, resolved) == nullptr) {
getcwd(resolved, PATH_MAX);
}
std::string result(resolved);
if (!result.empty() && result.back() != '/')
result += '/';
return result;
}
bool loadLibrary(std::string path) {
void* handle = hybris_dlopen((getCWD() + "libs/" + path).c_str(), RTLD_LAZY);
void* handle = hybris_dlopen((getRootPath() + "libs/" + path).c_str(), RTLD_LAZY);
if (handle == nullptr) {
printf("failed to load library %s: %s\n", path.c_str(), hybris_dlerror());
return false;
@ -49,7 +61,7 @@ void* loadLibraryOS(std::string path, const char** symbols) {
}
void* loadMod(std::string path) {
void* handle = hybris_dlopen((getCWD() + "mods/" + path).c_str(), RTLD_LAZY);
void* handle = hybris_dlopen((getRootPath() + "mods/" + path).c_str(), RTLD_LAZY);
if (handle == nullptr) {
printf("failed to load mod: %s\n", path.c_str());
return nullptr;

View File

@ -2,7 +2,9 @@
#include <string>
std::string getCWD();
extern std::string rootPath;
std::string getRootPath();
bool loadLibrary(std::string path);
void* loadLibraryOS(std::string path, const char** symbols);
void* loadMod(std::string path);

View File

@ -1,4 +1,4 @@
#include "LinuxAppPlatform.h"
#include "linux_app_platform.h"
#include <cstring>
#include <iostream>
#include <fstream>
@ -14,24 +14,25 @@
#include "../hybris/src/jb/linker.h"
extern "C" {
#ifndef SERVER
#include <eglut.h>
#endif
#include "../hybris/include/hybris/dlfcn.h"
}
void** LinuxAppPlatform::myVtable = nullptr;
bool LinuxAppPlatform::mousePointerHidden = false;
bool enablePocketGuis = false;
bool serverMode = false;
LinuxAppPlatform::LinuxAppPlatform() : AppPlatform() {
this->vtable = myVtable;
internalStorage = "data/private/";
externalStorage = "data/public/";
currentStorage = "data/current/";
userdata = "data/user/";
userdataPathForLevels = "data/user/";
internalStorage = getRootPath() + "data/private/";
externalStorage = getRootPath() + "data/public/";
currentStorage = getRootPath() + "data/current/";
userdata = getRootPath() + "data/user/";
userdataPathForLevels = getRootPath() + "data/user/";
region = "0xdeadbeef";
tmpPath = "tmp/";
tmpPath = getRootPath() + "tmp/";
}
#include <execinfo.h>
@ -99,12 +100,16 @@ void LinuxAppPlatform::initVtable(void* lib) {
void LinuxAppPlatform::hideMousePointer() {
mousePointerHidden = true;
#ifndef SERVER
moveMouseToCenter = true;
eglutSetMousePointerVisiblity(EGLUT_POINTER_INVISIBLE);
#endif
}
void LinuxAppPlatform::showMousePointer() {
mousePointerHidden = false;
#ifndef SERVER
eglutSetMousePointerVisiblity(EGLUT_POINTER_VISIBLE);
#endif
}
std::string LinuxAppPlatform::_pickFile(std::string commandLine) {
@ -149,7 +154,7 @@ void LinuxAppPlatform::pickFile(FilePickerSettings &settings) {
std::cout << " - " << d.ext << " " << d.desc << "\n";
}
std::stringstream ss;
ss << "zenity --file-selection --title '" << replaceAll(settings.pickerTitle, "'", "\\'") << "'";
//ss << "zenity --file-selection --title '" << replaceAll(settings.pickerTitle, "'", "\\'") << "'";
if (settings.type == FilePickerSettings::PickerType::SAVE)
ss << " --save";
if (settings.fileDescriptions.size() > 0) {
@ -170,9 +175,11 @@ void LinuxAppPlatform::pickFile(FilePickerSettings &settings) {
void LinuxAppPlatform::setFullscreenMode(int mode) {
std::cout << "set fullscreen mode: " << mode << "\n";
#ifndef SERVER
int newMode = mode == 1 ? EGLUT_FULLSCREEN : EGLUT_WINDOWED;
if (eglutGet(EGLUT_FULLSCREEN_MODE) != newMode)
eglutToggleFullscreen();
#endif
}
std::string LinuxAppPlatform::createUUID() {

View File

@ -6,6 +6,7 @@
#include "../mcpe/gl.h"
#include "../mcpe/AppPlatform.h"
#include "../mcpe/ImagePickingCallback.h"
#include "common.h"
class ImageData;
class ImagePickingCallback;
@ -13,7 +14,6 @@ class FilePickerSettings;
extern bool enablePocketGuis;
extern bool moveMouseToCenter;
extern bool serverMode;
class LinuxAppPlatform : public AppPlatform {
@ -35,15 +35,15 @@ public:
std::string getDataUrl() { // this is used only for sounds
printf("get data url: assets/\n");
return "assets/";
return getRootPath() + "assets/";
}
std::string getUserDataUrl() { // this is used only for sounds
printf("get user data url: data/user/\n");
return "data/user/";
return getRootPath() + "data/user/";
}
std::string getPackagePath() {
return "assets/";
return getRootPath() + "assets/";
}
void hideMousePointer();
@ -88,7 +88,7 @@ public:
}
std::string getAssetFileFullPath(std::string const& s) {
printf("get assert full path: %s\n", s.c_str());
return "assets/" + s;
return getRootPath() + "assets/" + s;
}
int getScreenType() {
if (enablePocketGuis)

View File

@ -13,16 +13,23 @@
#include "android_symbols.h"
#include "egl_symbols.h"
#include "fmod_symbols.h"
#include "linux_app_platform.h"
#include "LinuxStore.h"
#include "common.h"
#include "hook.h"
#include "../mcpe/gl.h"
#include "../mcpe/AppPlatform.h"
#include "../mcpe/MinecraftGame.h"
#include "LinuxAppPlatform.h"
#include "LinuxStore.h"
#include "../mcpe/Mouse.h"
#include "../mcpe/Keyboard.h"
#include "../mcpe/Options.h"
#include "common.h"
#include "hook.h"
#include "../mcpe/Whitelist.h"
#include "../mcpe/OpsList.h"
#include "../mcpe/LevelSettings.h"
#include "../mcpe/UUID.h"
#include "../mcpe/ServerInstance.h"
#include "../mcpe/FilePathManager.h"
extern "C" {
@ -33,8 +40,6 @@ extern "C" {
}
void commonStub() {}
void androidStub() {
std::cout << "warn: android call\n";
}
@ -218,28 +223,29 @@ int main(int argc, char *argv[]) {
} else if (strcmp(argv[i], "-sw") == 0 || strcmp(argv[i], "--width") == 0) {
i++;
windowWidth = std::stoi(argv[i]);
} else if (strcmp(argv[i], "-sh") == 0 || strcmp(argv[i], "--height") == 0) {
} else if (strcmp(argv[i], "-sw") == 0 || strcmp(argv[i], "--width") == 0) {
i++;
windowHeight = std::stoi(argv[i]);
windowWidth = std::stoi(argv[i]);
} else if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--root-path") == 0) {
i++;
rootPath = argv[i];
} else if (strcmp(argv[i], "-ns") == 0 || strcmp(argv[i], "--no-stacktrace") == 0) {
enableStackTracePrinting = false;
} else if (strcmp(argv[i], "--pocket-guis") == 0) {
enablePocketGuis = true;
} else if (strcmp(argv[i], "--server") == 0) {
serverMode = true;
} else if (strcmp(argv[i], "--amd-fix") == 0) {
std::cout << "--amd-fix: Enabling AMD Workaround.\n";
workaroundAMD = true;
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
std::cout << "Help\n";
std::cout << "--help Shows this help information\n";
std::cout << "--root-path Sets the root path for game data\n";
std::cout << "--scale <scale> Sets the pixel scale\n";
std::cout << "--width <width> Sets the window width\n";
std::cout << "--height <height> Sets the window height\n";
std::cout << "--pocket-guis Switches to Pocket Edition GUIs\n";
std::cout << "--no-stacktrace Disables stack trace printing\n";
std::cout << "--amd-workaround Fixes crashes on pre-i686 and AMD CPUs\n\n";
std::cout << "--server Enable dedicated server mode\n\n";
std::cout << "EGL Options\n";
std::cout << "-display <display> Sets the display\n";
std::cout << "-info Shows info about the display\n\n";
@ -258,7 +264,7 @@ int main(int argc, char *argv[]) {
std::cout << "loading native libraries\n";
void* glesLib = loadLibraryOS("libGLESv2.so", gles_symbols);
void* fmodLib = loadLibraryOS((getCWD() + "libs/native/libfmod.so.8.2").c_str(), fmod_symbols);
void* fmodLib = loadLibraryOS((getRootPath() + "libs/native/libfmod.so.8.2").c_str(), fmod_symbols);
if (glesLib == nullptr || fmodLib == nullptr)
return -1;
@ -277,7 +283,7 @@ int main(int argc, char *argv[]) {
if (!loadLibrary("libmcpelauncher_mod.so"))
return -1;
std::cout << "loading MCPE\n";
std::string mcpePath = getCWD() + "libs/libminecraftpe.so";
std::string mcpePath = getRootPath() + "libs/libminecraftpe.so";
void* handle = hybris_dlopen(mcpePath.c_str(), RTLD_LAZY);
if (handle == nullptr) {
std::cout << "failed to load MCPE: " << hybris_dlerror() << "\n";
@ -309,6 +315,8 @@ int main(int argc, char *argv[]) {
std::cout << "loaded " << mods.size() << " mods\n";
}
mcpe::string::empty = (mcpe::string*) hybris_dlsym(handle, "_ZN4Util12EMPTY_STRINGE");
std::cout << "apply patches\n";
/*
@ -373,10 +381,10 @@ int main(int argc, char *argv[]) {
std::cout << "patches applied!\n";
// load symbols for gl
gl::getOpenGLVendor = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl15getOpenGLVendorEv");
gl::getOpenGLRenderer = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl17getOpenGLRendererEv");
gl::getOpenGLVersion = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl16getOpenGLVersionEv");
gl::getOpenGLExtensions = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl19getOpenGLExtensionsEv");
gl::getOpenGLVendor = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl15getOpenGLVendorEv");
gl::getOpenGLRenderer = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl17getOpenGLRendererEv");
gl::getOpenGLVersion = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl16getOpenGLVersionEv");
gl::getOpenGLExtensions = (mcpe::string (*)()) hybris_dlsym(handle, "_ZN2gl19getOpenGLExtensionsEv");
mce::Platform::OGL::OGL_initBindings = (void (*)()) hybris_dlsym(handle, "_ZN3mce8Platform3OGL12InitBindingsEv");
// init linux app platform
@ -399,7 +407,7 @@ int main(int argc, char *argv[]) {
Keyboard::inputs = (std::vector<KeyboardAction>*) hybris_dlsym(handle, "_ZN8Keyboard7_inputsE");
Keyboard::states = (int*) hybris_dlsym(handle, "_ZN8Keyboard7_statesE");
Keyboard::Keyboard_feedText = (void (*)(const std::string&, bool, unsigned char)) hybris_dlsym(handle, "_ZN8Keyboard8feedTextERKSsbh");
Keyboard::Keyboard_feedText = (void (*)(const mcpe::string&, bool, unsigned char)) hybris_dlsym(handle, "_ZN8Keyboard8feedTextERKSsbh");
Options::Options_getFullscreen = (bool (*)(Options*)) hybris_dlsym(handle, "_ZNK7Options13getFullscreenEv");
Options::Options_setFullscreen = (void (*)(Options*, bool)) hybris_dlsym(handle, "_ZN7Options13setFullscreenEb");

View File

@ -0,0 +1,297 @@
#include <iostream>
#include <dlfcn.h>
#include <memory>
#include <string>
#include <chrono>
#include <fstream>
#include "gles_symbols.h"
#include "android_symbols.h"
#include "egl_symbols.h"
#include "fmod_symbols.h"
#include "linux_app_platform.h"
#include "common.h"
#include "hook.h"
#include "server_minecraft_app.h"
#include "server_properties.h"
#include "../mcpe/Api.h"
#include "../mcpe/AppPlatform.h"
#include "../mcpe/FilePathManager.h"
#include "../mcpe/LevelSettings.h"
#include "../mcpe/Social.h"
#include "../mcpe/MinecraftEventing.h"
#include "../mcpe/EntitlementManager.h"
#include "../mcpe/AppResourceLoader.h"
#include "../mcpe/Resource.h"
#include "../mcpe/ResourcePack.h"
#include "../mcpe/AutomationClient.h"
#include "../mcpe/ServerInstance.h"
#include "../mcpe/Whitelist.h"
#include "../mcpe/OpsList.h"
#include "../mcpe/UUID.h"
#include "../mcpe/ResourcePackStack.h"
#include "../mcpe/Scheduler.h"
extern "C" {
#include "../hybris/include/hybris/dlfcn.h"
#include "../hybris/include/hybris/hook.h"
#include "../hybris/src/jb/linker.h"
}
void stubFunc() {}
void detachFromJavaStub() {
std::cout << "detach from java\n";
}
void* getJVMEnvStub() {
std::cout << "getjvmenv\n";
return nullptr;
}
int getDifficultyStub() {
return ServerProperties::instance().getInt("difficulty", 0);
}
int getGameTypeStub() {
return ServerProperties::instance().getInt("gamemode", 0);
}
using namespace std;
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
if ((strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--root-path") == 0) && i + 1 < argc) {
rootPath = argv[i + 1];
i++;
}
}
if (rootPath.empty()) {
std::cout << "[*] No root path set, the current directory will be used to store game data\n";
std::cout << "[*] It is recommended to set one by using the `--root-path` argument\n";
}
// load properties
std::ifstream propertiesFile(getRootPath() + "server.properties");
if (propertiesFile) {
ServerProperties::instance().load(propertiesFile);
} else {
std::cerr << "[!] No server.properties file found, cannot continue\n";
return 1;
}
registerCrashHandler();
setenv("LC_ALL", "C", 1);
std::cout << "loading native libraries\n";
void* glesLib = loadLibraryOS("libGLESv2.so", gles_symbols);
void* fmodLib = loadLibraryOS((getRootPath() + "libs/native/libfmod.so.8.2").c_str(), fmod_symbols);
if (glesLib == nullptr || fmodLib == nullptr)
return -1;
std::cout << "loading hybris libraries\n";
stubSymbols(android_symbols, (void*)stubFunc);
stubSymbols(egl_symbols, (void*)stubFunc);
stubSymbols(gles_symbols, (void*)stubFunc);
stubSymbols(fmod_symbols, (void*)stubFunc);
hybris_hook("eglGetProcAddress", (void*) stubFunc);
hookAndroidLog();
if (!loadLibrary("libc.so") || !loadLibrary("libstdc++.so") || !loadLibrary("libm.so") || !loadLibrary("libz.so"))
return -1;
// load stub libraries
if (!loadLibrary("libandroid.so") || !loadLibrary("liblog.so") || !loadLibrary("libEGL.so") || !loadLibrary("libGLESv2.so") || !loadLibrary("libOpenSLES.so") || !loadLibrary("libfmod.so") || !loadLibrary("libGLESv1_CM.so"))
return -1;
if (!loadLibrary("libmcpelauncher_mod.so"))
return -1;
std::cout << "loading MCPE\n";
std::string mcpePath = getRootPath() + "libs/libminecraftpe.so";
void* handle = hybris_dlopen(mcpePath.c_str(), RTLD_LAZY);
if (handle == nullptr) {
std::cout << "failed to load MCPE: " << hybris_dlerror() << "\n";
return -1;
}
addHookLibrary(handle, mcpePath);
unsigned int libBase = ((soinfo*) handle)->base;
std::cout << "loaded MCPE (at " << libBase << ")\n";
std::cout << "apply patches\n";
unsigned int patchOff = (unsigned int) hybris_dlsym(handle, "_ZN9crossplat10threadpool16detach_from_javaEPv");
patchCallInstruction((void*) patchOff, (void*) &detachFromJavaStub, true);
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN9crossplat11get_jvm_envEv");
patchCallInstruction((void*) patchOff, (void*) &getJVMEnvStub, true);
// murdle: these functions seem to be returning garbage data and fucking stuff up so i will just stub them
// it's probably something related to levelsettings but it is 4 am and i want to sleep
// at this point it's easier to just do this than spend 3 more days debugging
patchOff = (unsigned int) hybris_dlsym(handle, "_ZNK5Level13getDifficultyEv");
patchCallInstruction((void*) patchOff, (void*) &getDifficultyStub, true);
patchOff = (unsigned int) hybris_dlsym(handle, "_ZNK9LevelData11getGameTypeEv");
patchCallInstruction((void*) patchOff, (void*) &getGameTypeStub, true);
mcpe::string::empty = (mcpe::string*) hybris_dlsym(handle, "_ZN4Util12EMPTY_STRINGE");
std::cout << "patches applied!\n";
// init linux app platform
AppPlatform::myVtable = (void**) hybris_dlsym(handle, "_ZTV11AppPlatform");
AppPlatform::_singleton = (AppPlatform**) hybris_dlsym(handle, "_ZN11AppPlatform10mSingletonE");
AppPlatform::AppPlatform_construct = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatformC2Ev");
AppPlatform::AppPlatform_initialize = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform10initializeEv");
AppPlatform::AppPlatform__fireAppFocusGained = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform19_fireAppFocusGainedEv");
void** ptr = (void**) hybris_dlsym(handle, "_ZN9crossplat3JVME");
*ptr = (void*) 1; // this just needs not to be null
// server functions
((void*&) mce::UUID::EMPTY) = hybris_dlsym(handle, "_ZN3mce4UUID5EMPTYE");
((void*&) FilePathManager::FilePathManager_construct) = hybris_dlsym(handle, "_ZN15FilePathManagerC2ESsb");
((void*&) FilePathManager::FilePathManager_getRootPath) = hybris_dlsym(handle, "_ZNK15FilePathManager11getRootPathEv");
((void*&) FilePathManager::FilePathManager_getUserDataPath) = hybris_dlsym(handle, "_ZNK15FilePathManager15getUserDataPathEv");
((void*&) FilePathManager::FilePathManager_setSettingsPath) = hybris_dlsym(handle, "_ZN15FilePathManager15setSettingsPathESs");
((void*&) FilePathManager::FilePathManager_getSettingsPath) = hybris_dlsym(handle, "_ZNK15FilePathManager15getSettingsPathEv");
((void*&) FilePathManager::FilePathManager_setPackagePath) = hybris_dlsym(handle, "_ZN15FilePathManager14setPackagePathESs");
((void*&) FilePathManager::FilePathManager_getPackagePath) = hybris_dlsym(handle, "_ZNK15FilePathManager14getPackagePathEv");
((void*&) Social::XboxLiveUserManager::XboxLiveUserManager_construct) = hybris_dlsym(handle, "_ZN6Social19XboxLiveUserManagerC2ER11ScreenStack");
((void*&) Social::UserManager::UserManager_construct) = hybris_dlsym(handle, "_ZN6Social11UserManagerC2Ev");
((void*&) Social::UserManager::UserManager_addUser) = hybris_dlsym(handle, "_ZN6Social11UserManager7addUserESt10unique_ptrINS_19XboxLiveUserManagerESt14default_deleteIS2_EEi");
((void*&) MinecraftEventing::MinecraftEventing_construct) = hybris_dlsym(handle, "_ZN17MinecraftEventingC2ERKSs");
((void*&) EntitlementManager::EntitlementManager_construct) = hybris_dlsym(handle, "_ZN18EntitlementManagerC2ER17MinecraftEventingRN6Social11UserManagerE");
((void*&) Automation::AutomationClient::AutomationClient_construct) = hybris_dlsym(handle, "_ZN10Automation16AutomationClientC2ER13IMinecraftApp");
((void*&) LevelSettings::LevelSettings_construct) = hybris_dlsym(handle, "_ZN13LevelSettingsC2Ev");
((void*&) Resource::Resource_registerLoader) = hybris_dlsym(handle, "_ZN8Resource14registerLoaderE18ResourceFileSystemSt10unique_ptrI14ResourceLoaderSt14default_deleteIS2_EE");
((void*&) AppResourceLoader::AppResourceLoader_construct) = hybris_dlsym(handle, "_ZN17AppResourceLoaderC2ESt8functionIFSsvEE");
((void*&) PackManifestFactory::PackManifestFactory_construct) = hybris_dlsym(handle, "_ZN19PackManifestFactoryC2ER17MinecraftEventing");
((void*&) ResourcePackManager::ResourcePackManager_construct) = hybris_dlsym(handle, "_ZN19ResourcePackManagerC2ESt8functionIFSsvEE");
((void*&) ResourcePackManager::ResourcePackManager_setStack) = hybris_dlsym(handle, "_ZN19ResourcePackManager8setStackESt10unique_ptrI17ResourcePackStackSt14default_deleteIS1_EE21ResourcePackStackTypeb");
((void*&) ResourcePackStack::vtable_sym) = hybris_dlsym(handle, "_ZTV17ResourcePackStack");
((void*&) ResourcePackStack::ResourcePackStack_add) = hybris_dlsym(handle, "_ZN17ResourcePackStack3addEP12ResourcePackRK22ResourcePackRepositoryb");
((void*&) ResourcePackRepository::ResourcePackRepository_construct) = hybris_dlsym(handle, "_ZN22ResourcePackRepositoryC2ER17MinecraftEventingR19PackManifestFactoryP18EntitlementManagerP15FilePathManager");
((void*&) ServerInstance::ServerInstance_construct) = hybris_dlsym(handle, "_ZN14ServerInstanceC2ER13IMinecraftAppRK9WhitelistRK7OpsListP15FilePathManagerNSt6chrono8durationIxSt5ratioILx1ELx1EEEESsSsSsSsSs13LevelSettingsRN9minecraft3api3ApiEibiiibRKSt6vectorISsSaISsEESsbRKN3mce4UUIDER17MinecraftEventingR22ResourcePackRepositoryR19ResourcePackManagerPSX_");
((void*&) ServerInstance::ServerInstance_update) = hybris_dlsym(handle, "_ZN14ServerInstance6updateEv");
((void*&) Scheduler::singleton) = hybris_dlsym(handle, "_ZN9Scheduler9singletonEv");
((void*&) Scheduler::Scheduler_processCoroutines) = hybris_dlsym(handle, "_ZN9Scheduler17processCoroutinesEd");
std::cout << "init app platform vtable\n";
LinuxAppPlatform::initVtable(handle);
std::cout << "init app platform\n";
LinuxAppPlatform* platform = new LinuxAppPlatform();
std::cout << "app platform initialized\n";
platform->initialize();
Whitelist whitelist;
OpsList ops;
minecraft::api::Api api;
api.vtable = (void**)hybris_dlsym(handle, "_ZTVN9minecraft3api3ApiE") + 2;
api.envPath = getRootPath();
api.playerIfaceVtable = (void**) hybris_dlsym(handle, "_ZTVN9minecraft3api15PlayerInterfaceE") + 2;
api.entityIfaceVtable = (void**) hybris_dlsym(handle, "_ZTVN9minecraft3api15EntityInterfaceE") + 2;
api.networkIfaceVtable = (void**) hybris_dlsym(handle, "_ZTVN9minecraft3api16NetworkInterfaceE") + 2;
api.playerInteractionsIfaceVtable = (void**) hybris_dlsym(handle, "_ZTVN9minecraft3api26PlayerInteractionInterfaceE") + 2;
FilePathManager pathmgr (platform->getCurrentStoragePath(), false);
pathmgr.setPackagePath(platform->getPackagePath());
pathmgr.setSettingsPath(pathmgr.getRootPath());
LevelSettings levelSettings;
levelSettings.seed = ServerProperties::instance().getLong("level-seed", 0);
levelSettings.gametype = ServerProperties::instance().getInt("gamemode", 0);
levelSettings.forceGameType = ServerProperties::instance().getBool("force-gamemode", false);
levelSettings.difficulty = ServerProperties::instance().getInt("difficulty", 0);
levelSettings.dimension = 0;
levelSettings.generator = ServerProperties::instance().getInt("level-type", 1);
levelSettings.edu = false;
levelSettings.mpGame = true;
levelSettings.lanBroadcast = true;
levelSettings.commandsEnabled = true;
levelSettings.texturepacksRequired = false;
std::unique_ptr<Social::XboxLiveUserManager> xboxUserManager(
new Social::XboxLiveUserManager()
);
Social::UserManager userManager;
userManager.addUser(std::move(xboxUserManager));
MinecraftEventing eventing(pathmgr.getRootPath());
EntitlementManager entManager(eventing, userManager);
Resource::registerLoader((ResourceFileSystem) 1, std::unique_ptr<ResourceLoader>(new AppResourceLoader([&pathmgr] { return pathmgr.getPackagePath(); })));
Resource::registerLoader((ResourceFileSystem) 8, std::unique_ptr<ResourceLoader>(new AppResourceLoader([&pathmgr] { return pathmgr.getUserDataPath(); })));
Resource::registerLoader((ResourceFileSystem) 4, std::unique_ptr<ResourceLoader>(new AppResourceLoader([&pathmgr] { return pathmgr.getSettingsPath(); })));
std::function<std::string()> rootPathFn =
[&pathmgr]() -> std::string {
return pathmgr.getRootPath().c_str();
};
ResourcePackManager* resourcePackManager = new ResourcePackManager(rootPathFn);
Resource::registerLoader((ResourceFileSystem) 0, std::unique_ptr<ResourceLoader>(resourcePackManager));
PackManifestFactory packManifestFactory(eventing);
ResourcePackRepository resourcePackRepo(eventing, packManifestFactory, &entManager, &pathmgr);
std::unique_ptr<ResourcePackStack> stack(new ResourcePackStack());
stack->add(resourcePackRepo.vanillaPack, resourcePackRepo, false);
resourcePackManager->setStack(std::move(stack), (ResourcePackStackType) 3, false);
DedicatedServerMinecraftApp app;
Automation::AutomationClient aclient (app);
app.automationClient = &aclient;
ServerInstance server;
ServerInstance::ServerInstance_construct(
&server,
app,
whitelist,
ops,
&pathmgr,
std::chrono::duration<long long>(0),
ServerProperties::instance().getString("level-dir"),
ServerProperties::instance().getString("level-name"),
ServerProperties::instance().getString("motd"),
"",
"",
&levelSettings,
api,
ServerProperties::instance().getInt("view-distance", 22),
true,
ServerProperties::instance().getInt("server-port", 19132),
ServerProperties::instance().getInt("server-port-v6", 19133),
ServerProperties::instance().getInt("max-players", 20),
ServerProperties::instance().getBool("online-mode", false),
{},
"normal",
false,
*mce::UUID::EMPTY,
eventing,
resourcePackRepo,
*resourcePackManager,
resourcePackManager
);
std::cout << "Server running\n";
while (true) {
server.update();
Scheduler::singleton()->processCoroutines(std::chrono::duration_cast<std::chrono::duration<long long>>(std::chrono::milliseconds(50)));
}
return 0;
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "../mcpe/IMinecraftApp.h"
class DedicatedServerMinecraftApp : public IMinecraftApp {
public:
Automation::AutomationClient* automationClient;
virtual Minecraft* getPrimaryMinecraft() { return nullptr; }
virtual Automation::AutomationClient* getAutomationClient() { return automationClient; }
virtual bool isEduMode() { return false; }
virtual bool isDedicatedServer() { return true; }
virtual int getDefaultNetworkMaxPlayers() { return 20; }
virtual void onNetworkMaxPlayersChanged(unsigned int max) {}
};

41
src/server_properties.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "server_properties.h"
void ServerProperties::load(std::istream& stream) {
std::string line;
while (std::getline(stream, line)) {
if (!line.empty() && line[0] == '#')
continue;
size_t i = line.find('=');
if (i == std::string::npos)
continue;
properties[line.substr(0, i)] = line.substr(i + 1);
}
}
std::string ServerProperties::getString(const std::string& name, const std::string& def) {
return properties.count(name) ? properties.at(name) : def;
}
int ServerProperties::getInt(const std::string& name, int def) {
return properties.count(name) ? std::stoi(properties.at(name)) : def;
}
long long ServerProperties::getLong(const std::string& name, long long def) {
auto it = properties.find(name);
if (it == properties.end() || it->second.empty()) return def;
return std::stoll(it->second);
}
float ServerProperties::getFloat(const std::string& name, float def) {
return properties.count(name) ? std::stof(properties.at(name)) : def;
}
bool ServerProperties::getBool(const std::string& name, bool def) {
if (properties.count(name)) {
const std::string& val = properties.at(name);
return val == "true" || val == "yes" || val == "1";
}
return def;
}

29
src/server_properties.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <string>
#include <istream>
#include <map>
class ServerProperties {
private:
std::map<std::string, std::string> properties;
ServerProperties() = default;
public:
ServerProperties(const ServerProperties&) = delete;
ServerProperties& operator=(const ServerProperties&) = delete;
static ServerProperties& instance() {
static ServerProperties instance;
return instance;
}
void load(std::istream& stream);
std::string getString(const std::string& name, const std::string& def = "");
int getInt(const std::string& name, int def = 0);
long long getLong(const std::string& name, long long def = 0);
float getFloat(const std::string& name, float def = 0.f);
bool getBool(const std::string& name, bool def = false);
};