SDL/WASM Port

This commit is contained in:
TheBrokenRail
2023-08-05 01:58:24 -04:00
committed by iProgramInCpp
parent 0b16b2843a
commit 0fbe90752d
37 changed files with 1704 additions and 40 deletions

2
.gitignore vendored
View File

@@ -379,3 +379,5 @@ FodyWeavers.xsd
/windows_vs/games/com.mojang
/windows_vs/assets
/windows_vs/assetsO
/wasm

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "thirdparty/coi-serviceworker"]
path = thirdparty/coi-serviceworker
url = https://github.com/gzuidhof/coi-serviceworker
[submodule "thirdparty/gles-compatibility-layer"]
path = thirdparty/gles-compatibility-layer
url = https://gitea.thebrokenrail.com/minecraft-pi-reborn/gles-compatibility-layer.git

42
build-wasm.sh Executable file
View File

@@ -0,0 +1,42 @@
#!/bin/bash
set -e
# Working Directory
mkdir -p wasm
cd wasm
# Clone Emscripten SDK
if [ ! -d emsdk ]; then
git clone https://github.com/emscripten-core/emsdk.git
fi
cd emsdk
# Update Emscripten SDK
git pull
./emsdk install 3.1.42 # https://github.com/emscripten-core/emscripten/issues/19921
./emsdk activate 3.1.42 > /dev/null
# Use Emscripten SDK
export EMSDK_QUIET=1
source ./emsdk_env.sh
# Create Output Directory
cd ../
rm -rf dist
mkdir dist
# Create Build Directory
mkdir -p build
cd build
# Configure Build
emcmake cmake -GNinja "$@" ../../platforms/sdl
# Build
cmake --build .
# Bundle
cp reminecraftpe.* ../dist
cp ../../platforms/sdl/wasm_shell.html ../dist/reminecraftpe.html
cp ../../thirdparty/coi-serviceworker/coi-serviceworker.min.js ../dist

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -55,6 +55,7 @@ enum
AKEYCODE_APOSTROPHE = VK_OEM_7, // ''"'
AKEYCODE_SPACE = VK_SPACE,
AKEYCODE_1 = '1',
AKEYCODE_0 = '0',
//...
AKEYCODE_9 = '9',
@@ -73,6 +74,109 @@ enum
#define AKEYCODE_ARROW_LEFT VK_LEFT
#define AKEYCODE_ARROW_RIGHT VK_RIGHT
#elif defined(USE_SDL)
#include <SDL2/SDL.h>
enum
{
AKEYCODE_UNKNOWN = 0,
AKEYCODE_MENU,
AKEYCODE_SEARCH,
AKEYCODE_BACK,
AKEYCODE_BUTTON_X,
AKEYCODE_BUTTON_Y,
AKEYCODE_DPAD_UP,
AKEYCODE_DPAD_DOWN,
AKEYCODE_DPAD_LEFT,
AKEYCODE_DPAD_RIGHT,
AKEYCODE_DPAD_CENTER,
AKEYCODE_BUTTON_L1,
AKEYCODE_BUTTON_R1,
AKEYCODE_SHIFT_LEFT,
AKEYCODE_SHIFT_RIGHT,
AKEYCODE_DEL,
AKEYCODE_FORWARD_DEL,
AKEYCODE_COMMA,
AKEYCODE_PERIOD,
AKEYCODE_PLUS,
AKEYCODE_MINUS,
AKEYCODE_SEMICOLON,
AKEYCODE_SLASH,
AKEYCODE_GRAVE,
AKEYCODE_LEFT_BRACKET,
AKEYCODE_BACKSLASH,
AKEYCODE_RIGHT_BRACKET,
AKEYCODE_APOSTROPHE,
AKEYCODE_SPACE,
AKEYCODE_0,
AKEYCODE_1,
AKEYCODE_2,
AKEYCODE_3,
AKEYCODE_4,
AKEYCODE_5,
AKEYCODE_6,
AKEYCODE_7,
AKEYCODE_8,
AKEYCODE_9,
AKEYCODE_A,
AKEYCODE_Q,
AKEYCODE_T,
AKEYCODE_Z,
AKEYCODE_F4,
AKEYCODE_ARROW_LEFT,
AKEYCODE_ARROW_RIGHT
};
static inline int translate_sdl_key_to_mcpe(int key) {
switch (key) {
case SDLK_ESCAPE: return AKEYCODE_MENU;
case SDLK_F5: return AKEYCODE_SEARCH;
case SDLK_y: return AKEYCODE_BACK;
case SDLK_u: return AKEYCODE_BUTTON_X;
case SDLK_e: return AKEYCODE_BUTTON_Y;
case SDLK_w: return AKEYCODE_DPAD_UP;
case SDLK_s: return AKEYCODE_DPAD_DOWN;
case SDLK_a: return AKEYCODE_DPAD_LEFT;
case SDLK_d: return AKEYCODE_DPAD_RIGHT;
case SDLK_SPACE: return AKEYCODE_DPAD_CENTER;
case SDLK_x: return AKEYCODE_BUTTON_L1;
case SDLK_c: return AKEYCODE_BUTTON_R1;
case SDLK_LSHIFT: return AKEYCODE_SHIFT_LEFT;
case SDLK_RSHIFT: return AKEYCODE_SHIFT_RIGHT;
case SDLK_BACKSPACE: return AKEYCODE_DEL;
case SDLK_DELETE: return AKEYCODE_FORWARD_DEL;
case SDLK_COMMA: return AKEYCODE_COMMA;
case SDLK_PERIOD: return AKEYCODE_PERIOD;
case SDLK_PLUS: return AKEYCODE_PLUS;
case SDLK_MINUS: return AKEYCODE_MINUS;
case SDLK_SEMICOLON: return AKEYCODE_SEMICOLON;
case SDLK_SLASH: return AKEYCODE_SLASH;
case SDLK_BACKQUOTE: return AKEYCODE_GRAVE;
case SDLK_LEFTBRACKET: return AKEYCODE_LEFT_BRACKET;
case SDLK_BACKSLASH: return AKEYCODE_BACKSLASH;
case SDLK_RIGHTBRACKET: return AKEYCODE_RIGHT_BRACKET;
case SDLK_QUOTE: return AKEYCODE_APOSTROPHE;
case SDLK_1: return AKEYCODE_1;
case SDLK_2: return AKEYCODE_2;
case SDLK_3: return AKEYCODE_3;
case SDLK_4: return AKEYCODE_4;
case SDLK_5: return AKEYCODE_5;
case SDLK_6: return AKEYCODE_6;
case SDLK_7: return AKEYCODE_7;
case SDLK_8: return AKEYCODE_8;
case SDLK_0: return AKEYCODE_0;
case SDLK_9: return AKEYCODE_9;
case SDLK_q: return AKEYCODE_Q;
case SDLK_t: return AKEYCODE_T;
case SDLK_z: return AKEYCODE_Z;
case SDLK_F4: return AKEYCODE_F4;
case SDLK_LEFT: return AKEYCODE_ARROW_LEFT;
case SDLK_RIGHT: return AKEYCODE_ARROW_RIGHT;
default: return AKEYCODE_UNKNOWN;
}
}
#else
#error "Add AKEYCODEs for your platform!"
#endif

View File

@@ -8,6 +8,65 @@
#pragma once
#ifdef USE_SDL
#ifdef USE_GLES1_COMPATIBILITY_LAYER
#include <GLES/gl.h>
#define GL_QUADS 0x7
#include <cmath>
// https://cgit.freedesktop.org/mesa/glu/tree/src/libutil/project.c
static inline void __gluMakeIdentityf(GLfloat m[16]) {
m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
}
static inline void gluPerspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar) {
GLfloat m[4][4];
float sine, cotangent, deltaZ;
float radians = fovy / 2 * M_PI / 180;
deltaZ = zFar - zNear;
sine = sin(radians);
if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
return;
}
cotangent = cosf(radians) / sine;
__gluMakeIdentityf(&m[0][0]);
m[0][0] = cotangent / aspect;
m[1][1] = cotangent;
m[2][2] = -(zFar + zNear) / deltaZ;
m[2][3] = -1;
m[3][2] = -2 * zNear * zFar / deltaZ;
m[3][3] = 0;
glMultMatrixf(&m[0][0]);
}
#else
#define GL_GLEXT_PROTOTYPES
#include <SDL2/SDL_opengl.h>
#include <SDL2/SDL_opengl_glext.h>
#include <GL/glu.h>
#endif
#define xglBindBuffer glBindBuffer
#define xglBufferData glBufferData
#define xglGenBuffers glGenBuffers
#define xglDeleteBuffers glDeleteBuffers
#ifdef USE_GLES1_COMPATIBILITY_LAYER
#define xglOrthof glOrthof
#else
#define xglOrthof(left, right, bottom, top, nearpl, farpl) glOrtho((GLdouble) (left), (GLdouble) (right), (GLdouble) (bottom), (GLdouble) (top), (GLdouble) (nearpl), (GLdouble) (farpl))
#endif
// @TODO: not the right place, but er, it's ok
void drawArrayVT(GLuint buffer, int count, int stride);
void drawArrayVTC(GLuint buffer, int count, int stride);
#else
#ifdef USE_OPENGL_2
#define xglBindBuffer glBindBuffer
@@ -36,3 +95,5 @@ void drawArrayVT(GLuint buffer, int count, int stride);
void drawArrayVTC(GLuint buffer, int count, int stride);
#endif
#endif

1
platforms/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build*

View File

@@ -15,6 +15,12 @@
// Add sound system overrides here
#elif defined(USE_SDL)
// -- OpenAL based sound system for SDL
#include "sdl/SoundSystemAL.hpp"
#define SOUND_SYSTEM_TYPE SoundSystemAL
#elif defined(_WIN32)
// -- DirectSound based sound system for Windows

2
platforms/sdl/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/build
/assets

View File

@@ -0,0 +1,308 @@
#include "AppPlatform_sdl.hpp"
#include <sstream>
#include <fstream>
#include <sys/stat.h>
#ifndef __EMSCRIPTEN__
#include <png.h>
#include "compat/GL.hpp"
#else
#include <emscripten.h>
#endif
#include "client/common/Utils.hpp"
AppPlatform_sdl::AppPlatform_sdl(std::string storageDir, SDL_Window *window) {
_storageDir = storageDir;
_window = window;
}
int AppPlatform_sdl::checkLicense() {
// we own the game!!
return 1;
}
// Ensure Screenshots Folder Exists
void ensure_screenshots_folder(const char *screenshots) {
// Check Screenshots Folder
struct stat obj;
if (stat(screenshots, &obj) != 0 || !S_ISDIR(obj.st_mode)) {
// Create Screenshots Folder
#ifdef _WIN32
int ret = mkdir(screenshots);
#else
int ret = mkdir(screenshots, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
if (ret != 0) {
// Unable To Create Folder
LogMsg("Error Creating Directory: %s: %s", screenshots, strerror(errno));
exit(EXIT_FAILURE);
}
}
}
#ifndef __EMSCRIPTEN__
// 4 (Year) + 1 (Hyphen) + 2 (Month) + 1 (Hyphen) + 2 (Day) + 1 (Underscore) + 2 (Hour) + 1 (Period) + 2 (Minute) + 1 (Period) + 2 (Second) + 1 (Null Terminator)
#define TIME_SIZE 20
// Take Screenshot
static int save_png(const char *filename, unsigned char *pixels, int line_size, int width, int height) {
// Return value
int ret = 0;
// Variables
png_structp png = NULL;
png_infop info = NULL;
FILE *file = NULL;
png_colorp palette = NULL;
png_bytep rows[height];
for (int i = 0; i < height; ++i) {
rows[height - i - 1] = (png_bytep)(&pixels[i * line_size]);
}
// Init
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) {
ret = 1;
goto ret;
}
info = png_create_info_struct(png);
if (!info) {
ret = 1;
goto ret;
}
// Open File
file = fopen(filename, "wb");
if (!file) {
ret = 1;
goto ret;
}
// Prepare To Write
png_init_io(png, file);
png_set_IHDR(png, info, width, height, 8 /* Depth */, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
palette = (png_colorp) png_malloc(png, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
if (!palette) {
ret = 1;
goto ret;
}
png_set_PLTE(png, info, palette, PNG_MAX_PALETTE_LENGTH);
png_write_info(png, info);
png_set_packing(png);
// Write
png_write_image(png, rows);
png_write_end(png, info);
ret:
// Free
if (palette != NULL) {
png_free(png, palette);
}
if (file != NULL) {
fclose(file);
}
if (png != NULL) {
png_destroy_write_struct(&png, &info);
}
// Return
return ret;
}
void AppPlatform_sdl::saveScreenshot(const std::string &filename, int glWidth, int glHeight) {
// Get Directory
std::string screenshots = _storageDir + "/screenshots";
// Get Timestamp
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
char time[TIME_SIZE];
strftime(time, TIME_SIZE, "%Y-%m-%d_%H.%M.%S", timeinfo);
// Ensure Screenshots Folder Exists
ensure_screenshots_folder(screenshots.c_str());
// Prevent Overwriting Screenshots
int num = 1;
std::string file = screenshots + '/' + time + ".png";
while (access(file.c_str(), F_OK) != -1) {
file = screenshots + '/' + time + '-' + std::to_string(num) + ".png";
num++;
}
// Get Image Size
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
int x = viewport[0];
int y = viewport[1];
int width = viewport[2];
int height = viewport[3];
// Get Line Size
int line_size = width * 4;
{
// Handle Alignment
int alignment;
glGetIntegerv(GL_PACK_ALIGNMENT, &alignment);
// Round
int diff = line_size % alignment;
if (diff > 0) {
line_size = line_size + (alignment - diff);
}
}
int size = height * line_size;
// Read Pixels
bool fail = false;
unsigned char *pixels = (unsigned char *) malloc(size);
if (pixels == NULL) {
fail = true;
} else {
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
}
// Save Image
if (fail || save_png(file.c_str(), pixels, line_size, width, height)) {
LogMsg("Screenshot Failed: %s", file.c_str());
} else {
LogMsg("Screenshot Saved: %s", file.c_str());
}
// Free
if (pixels != NULL) {
free(pixels);
}
}
#endif
int AppPlatform_sdl::getScreenWidth() const {
int width;
SDL_GL_GetDrawableSize(_window, &width, nullptr);
return width;
}
int AppPlatform_sdl::getScreenHeight() const {
int height;
SDL_GL_GetDrawableSize(_window, nullptr, &height);
return height;
}
#ifndef __EMSCRIPTEN__
static void png_read_sdl(png_structp png_ptr, png_bytep data, png_size_t length) {
SDL_RWread((SDL_RWops *) png_get_io_ptr(png_ptr), (char *) data, length, 1);
}
static void nop_png_warning(png_structp png_ptr, png_const_charp warning_message) {
// Do Nothing
}
#endif
Texture AppPlatform_sdl::loadTexture(const std::string& str, bool b) {
Texture out;
out.field_C = 0;
out.field_D = 0;
std::string realPath = str;
if (realPath.size() && realPath[0] == '/') {
// trim it off
realPath = realPath.substr(1);
}
realPath = "assets/" + realPath;
#ifndef __EMSCRIPTEN__
SDL_RWops *io = SDL_RWFromFile(realPath.c_str(), "rb");
if (io != NULL) {
png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, nop_png_warning);
if (!pngPtr) {
return out;
}
png_infop infoPtr = png_create_info_struct(pngPtr);
if (!infoPtr) {
png_destroy_read_struct(&pngPtr, NULL, NULL);
return out;
}
png_set_read_fn(pngPtr, (png_voidp) io, png_read_sdl);
png_read_info(pngPtr, infoPtr);
png_set_expand(pngPtr);
png_set_strip_16(pngPtr);
png_set_gray_to_rgb(pngPtr);
png_read_update_info(pngPtr, infoPtr);
out.m_width = png_get_image_width(pngPtr, infoPtr);
out.m_height = png_get_image_height(pngPtr, infoPtr);
bool opaque = png_get_color_type(pngPtr, infoPtr) != PNG_COLOR_TYPE_RGBA;
if (!opaque) {
out.field_C = 1;
}
int pixelSize = opaque ? 3 : 4;
png_bytep *rowPtrs = new png_bytep[out.m_height];
unsigned char *pixels = new unsigned char[pixelSize * out.m_width * out.m_height];
int rowStrideBytes = pixelSize * out.m_width;
for (int i = 0; i < out.m_height; i++) {
rowPtrs[i] = (png_bytep) &pixels[i * rowStrideBytes];
}
png_read_image(pngPtr, rowPtrs);
out.m_pixels = (uint32_t *) pixels;
png_destroy_read_struct(&pngPtr, &infoPtr, (png_infopp) 0);
delete[](png_bytep) rowPtrs;
SDL_RWclose(io);
}
#else
char *data = emscripten_get_preloaded_image_data(("/" + realPath).c_str(), &out.m_width, &out.m_height);
if (data != NULL) {
size_t data_size = out.m_width * out.m_height * 4;
out.m_pixels = (uint32_t *) new unsigned char[data_size];
out.field_C = 1;
memcpy(out.m_pixels, data, data_size);
free(data);
return out;
}
#endif
LogMsg("Couldn't find file: %s", str.c_str());
return out;
}
void AppPlatform_sdl::setMouseGrabbed(bool b) {
SDL_SetWindowGrab(_window, b ? SDL_TRUE : SDL_FALSE);
SDL_SetRelativeMouseMode(b ? SDL_TRUE : SDL_FALSE);
}
void AppPlatform_sdl::setMouseDiff(int x, int y) {
xrel = x;
yrel = y;
}
void AppPlatform_sdl::getMouseDiff(int& x, int& y) {
x = xrel;
y = yrel;
}
void AppPlatform_sdl::clearDiff() {
xrel = 0;
yrel = 0;
}
bool AppPlatform_sdl::shiftPressed() {
return m_bShiftPressed[0] || m_bShiftPressed[1];
}
void AppPlatform_sdl::setShiftPressed(bool b, bool isLeft) {
m_bShiftPressed[isLeft ? 0 : 1] = b;
}
int AppPlatform_sdl::getUserInputStatus() {
return -1;
}

View File

@@ -0,0 +1,45 @@
#pragma once
#include <string>
#include <SDL2/SDL.h>
#include "AppPlatform.hpp"
#ifdef ORIGINAL_CODE
#error "This isn't original code. You probably shouldn't try to compile this"
#endif
void ensure_screenshots_folder(const char *screenshots);
class AppPlatform_sdl : public AppPlatform {
public:
AppPlatform_sdl(std::string storageDir, SDL_Window *window);
#ifndef __EMSCRIPTEN__
void saveScreenshot(const std::string& fileName, int width, int height) override;
#endif
int checkLicense() override;
int getScreenWidth() const override;
int getScreenHeight() const override;
Texture loadTexture(const std::string& str, bool b) override;
int getUserInputStatus() override;
// Also add these to allow proper turning within the game.
void setMouseGrabbed(bool b) override;
void setMouseDiff(int x, int y);
void getMouseDiff(int& x, int& y) override;
void clearDiff() override;
// Also add these to allow proper text input within the game.
bool shiftPressed() override;
void setShiftPressed(bool b, bool isLeft);
private:
std::string _storageDir;
SDL_Window *_window;
bool m_bShiftPressed[2] = {false, false};
int xrel;
int yrel;
};

View File

@@ -0,0 +1,64 @@
cmake_minimum_required(VERSION 3.16.0)
project(reminecraftpe)
# SDL Build
add_compile_definitions(USE_SDL HANDLE_CHARS_SEPARATELY)
# WASM
if(EMSCRIPTEN)
function(add_compile_and_link_options)
add_compile_options(${ARGV})
add_link_options(${ARGV})
endfunction()
set(CMAKE_EXECUTABLE_SUFFIX ".js")
endif()
# Clang
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Wno-inconsistent-missing-override -Wno-enum-compare-switch -Wno-register)
endif()
# Threads
if(EMSCRIPTEN)
add_compile_and_link_options(-pthread)
else()
find_package(Threads)
link_libraries(Threads::Threads)
endif()
# Build
add_executable(reminecraftpe
main.cpp
AppPlatform_sdl.cpp
SoundSystemAL.cpp
)
# Core
add_subdirectory(../../source source)
target_link_libraries(reminecraftpe reminecraftpe-core)
# LibPNG
if(NOT EMSCRIPTEN)
find_package(PNG REQUIRED)
target_link_libraries(reminecraftpe PNG::PNG)
endif()
# SDL
if(TARGET SDL2::SDL2main)
target_link_libraries(reminecraftpe SDL2::SDL2main)
endif()
# WASM
if(EMSCRIPTEN)
target_link_options(reminecraftpe PRIVATE -Wno-pthreads-mem-growth)
target_link_options(reminecraftpe PRIVATE -sALLOW_MEMORY_GROWTH=1)
# Export Resize Function
target_link_options(reminecraftpe PRIVATE -sEXPORTED_FUNCTIONS=_main,_resize_from_js -sEXPORTED_RUNTIME_METHODS=ccall)
endif()
# Assets
if(EMSCRIPTEN)
target_link_options(reminecraftpe PRIVATE --use-preload-plugins --preload-file "${CMAKE_CURRENT_SOURCE_DIR}/assets@/assets")
elseif(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/assets")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/assets" "${CMAKE_CURRENT_BINARY_DIR}/assets" SYMBOLIC)
endif()

View File

@@ -0,0 +1,245 @@
#include "SoundSystemAL.hpp"
#include "client/common/Utils.hpp"
SoundSystemAL::SoundSystemAL() {
device = alcOpenDevice(NULL);
if (!device) {
LogMsg("Unable To Load Audio Engine");
return;
}
// Create Context
context = alcCreateContext(device, NULL);
ALCenum err = alcGetError(device);
if (err != ALC_NO_ERROR) {
LogMsg("Unable To Open Audio Context: %s", alcGetString(device, err));
return;
}
// Select Context
alcMakeContextCurrent(context);
err = alcGetError(device);
if (err != ALC_NO_ERROR) {
LogMsg("Unable To Select Audio Context: %s", alcGetString(device, err));
return;
}
// Set Distance Model
alDistanceModel(AL_LINEAR_DISTANCE_CLAMPED);
// Mark As Loaded
loaded = true;
}
SoundSystemAL::~SoundSystemAL() {
if (loaded) {
// Delete Audio Sources
delete_sources();
// Delete Audio Buffers
delete_buffers();
// Deselect Context
alcMakeContextCurrent(NULL);
ALCenum err = alcGetError(device);
if (err != ALC_NO_ERROR) {
LogMsg("Unable To Deselect Audio Context: %s", alcGetString(device, err));
}
// Destroy Context
alcDestroyContext(context);
err = alcGetError(device);
if (err != ALC_NO_ERROR) {
LogMsg("Unable To Destroy Audio Context: %s", alcGetString(device, err));
}
// Close Device
alcCloseDevice(device);
err = alcGetError(device);
if (err != ALC_NO_ERROR) {
LogMsg("Unable To Close Audio Device: %s", alcGetString(device, err));
}
}
}
// Error Checking
#define AL_ERROR_CHECK() AL_ERROR_CHECK_MANUAL(alGetError())
#define AL_ERROR_CHECK_MANUAL(val) \
{ \
ALenum __err = val; \
if (__err != AL_NO_ERROR) { \
LogMsg("(%s:%i) OpenAL Error: %s", __FILE__, __LINE__, alGetString(__err)); \
exit(EXIT_FAILURE); \
} \
}
// Delete Sources
void SoundSystemAL::delete_sources() {
if (loaded) {
for (ALuint source : idle_sources) {
alDeleteSources(1, &source);
AL_ERROR_CHECK();
}
for (ALuint source : sources) {
alDeleteSources(1, &source);
AL_ERROR_CHECK();
}
}
idle_sources.clear();
sources.clear();
}
// Delete Buffers
void SoundSystemAL::delete_buffers() {
if (loaded) {
for (auto &it : buffers) {
if (it.second && alIsBuffer(it.second)) {
alDeleteBuffers(1, &it.second);
AL_ERROR_CHECK();
}
}
}
buffers.clear();
}
// Get Buffer
ALuint SoundSystemAL::get_buffer(const SoundDesc &sound) {
if (buffers.count(sound.m_pData) > 0) {
return buffers[sound.m_pData];
} else {
// Sound Format
ALenum format = AL_NONE;
if (sound.m_header.m_channels == 1) {
format = sound.m_header.m_bytes_per_sample == 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8;
} else if (sound.m_header.m_channels == 2) {
format = sound.m_header.m_bytes_per_sample == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8;
}
// Sound Data Size
int size = sound.m_header.m_length * sound.m_header.m_bytes_per_sample;
// Create Buffer
ALuint buffer;
alGenBuffers(1, &buffer);
AL_ERROR_CHECK();
alBufferData(buffer, format, sound.m_pData, size, sound.m_header.m_sample_rate);
AL_ERROR_CHECK();
// Store
buffers[sound.m_pData] = buffer;
return buffer;
}
}
void SoundSystemAL::update(float x, float y, float z, float yaw) {
// Check
if (loaded) {
// Update Listener Volume
float volume = 1;
alListenerf(AL_GAIN, volume);
AL_ERROR_CHECK();
// Update Listener Position
alListener3f(AL_POSITION, x, y, z);
AL_ERROR_CHECK();
// Update Listener Orientation
float radian_yaw = yaw * (M_PI / 180);
ALfloat orientation[] = {-sinf(radian_yaw), 0.0f, cosf(radian_yaw), 0.0f, 1.0f, 0.0f};
alListenerfv(AL_ORIENTATION, orientation);
AL_ERROR_CHECK();
// Clear Finished Sources
std::vector<ALuint>::iterator it = sources.begin();
while (it != sources.end()) {
ALuint source = *it;
bool remove = false;
// Check
if (source && alIsSource(source)) {
// Is Valid Source
ALint source_state;
alGetSourcei(source, AL_SOURCE_STATE, &source_state);
AL_ERROR_CHECK();
if (source_state != AL_PLAYING) {
// Finished Playing
remove = true;
if (idle_sources.size() < MAX_IDLE_SOURCES) {
idle_sources.push_back(source);
} else {
alDeleteSources(1, &source);
AL_ERROR_CHECK();
}
}
} else {
// Not A Source
remove = true;
}
// Remove If Needed
if (remove) {
it = sources.erase(it);
} else {
++it;
}
}
}
}
void SoundSystemAL::play(const SoundDesc &sound, float x, float y, float z, float volume, float pitch, bool is_ui) {
if (loaded) {
// Load Sound
ALuint buffer = get_buffer(sound);
if (volume > 0.0f && buffer) {
// Get Source
ALuint al_source;
if (idle_sources.size() > 0) {
// Use Idle Source
al_source = idle_sources.back();
idle_sources.pop_back();
} else {
// Create Source
alGenSources(1, &al_source);
// Special Out-Of-Memory Handling
{
ALenum err = alGetError();
if (err == AL_OUT_OF_MEMORY) {
return;
} else {
AL_ERROR_CHECK_MANUAL(err);
}
}
}
// Set Properties
alSourcef(al_source, AL_PITCH, pitch);
AL_ERROR_CHECK();
alSourcef(al_source, AL_GAIN, volume);
AL_ERROR_CHECK();
alSource3f(al_source, AL_POSITION, x, y, z);
AL_ERROR_CHECK();
alSource3f(al_source, AL_VELOCITY, 0, 0, 0);
AL_ERROR_CHECK();
alSourcei(al_source, AL_LOOPING, AL_FALSE);
AL_ERROR_CHECK();
alSourcei(al_source, AL_SOURCE_RELATIVE, is_ui ? AL_TRUE : AL_FALSE);
AL_ERROR_CHECK();
// Set Attenuation
alSourcef(al_source, AL_MAX_DISTANCE, 16.0f);
AL_ERROR_CHECK();
alSourcef(al_source, AL_ROLLOFF_FACTOR, 6.0f);
AL_ERROR_CHECK();
alSourcef(al_source, AL_REFERENCE_DISTANCE, 5.0f);
AL_ERROR_CHECK();
// Set Buffer
alSourcei(al_source, AL_BUFFER, buffer);
AL_ERROR_CHECK();
// Play
alSourcePlay(al_source);
AL_ERROR_CHECK();
sources.push_back(al_source);
}
}
}

View File

@@ -0,0 +1,31 @@
#pragma once
#include <AL/al.h>
#include <AL/alc.h>
#include <string>
#include <vector>
#include <unordered_map>
#include "client/sound/SoundData.hpp"
#define MAX_IDLE_SOURCES 50
class SoundSystemAL {
public:
SoundSystemAL();
~SoundSystemAL();
void update(float x, float y, float z, float yaw);
void play(const SoundDesc &sound, float x, float y, float z, float volume, float pitch, bool is_ui);
private:
void delete_sources();
void delete_buffers();
ALuint get_buffer(const SoundDesc &sound);
ALCdevice *device = NULL;
ALCcontext *context = NULL;
bool loaded = false;
std::vector<ALuint> sources;
std::vector<ALuint> idle_sources;
std::unordered_map<void *, ALuint> buffers;
};

258
platforms/sdl/main.cpp Normal file
View File

@@ -0,0 +1,258 @@
#include <cstdarg>
#include <SDL2/SDL.h>
#include "compat/GL.hpp"
#include "compat/AKeyCodes.hpp"
#include "App.hpp"
#include "AppPlatform_sdl.hpp"
#include "NinecraftApp.hpp"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
void LogMsg(const char* fmt, ...) {
va_list lst;
va_start(lst, fmt);
vprintf(fmt, lst);
printf("\n");
va_end(lst);
}
// I hate duplicating code, but yeah
void LogMsgNoCR(const char* fmt, ...) {
va_list lst;
va_start(lst, fmt);
vprintf(fmt, lst);
va_end(lst);
}
AppPlatform_sdl *g_AppPlatform;
NinecraftApp *g_pApp;
SDL_Window *window = NULL;
SDL_GLContext context = NULL;
static void teardown() {
if (window != NULL) {
SDL_GL_DeleteContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
window = NULL;
}
}
// Resize From JS
#ifdef __EMSCRIPTEN__
extern "C" void resize_from_js(int new_width, int new_height) {
SDL_SetWindowSize(window, new_width, new_height);
}
#endif
// Handle Events
static bool window_resized = false;
static void handle_events() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
case SDL_KEYUP: {
Keyboard::feed(event.key.state == SDL_PRESSED ? 1 : 0, translate_sdl_key_to_mcpe(event.key.keysym.sym));
if (event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT) {
g_AppPlatform->setShiftPressed(event.key.state == SDL_PRESSED, event.key.keysym.sym == SDLK_LSHIFT);
}
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: {
Mouse::feed(event.button.button == SDL_BUTTON_LEFT ? 1 : 2, event.button.state == SDL_PRESSED ? 1 : 0, event.button.x, event.button.y);
break;
}
case SDL_MOUSEMOTION: {
Mouse::_x = event.motion.x;
Mouse::_y = event.motion.y;
Mouse::feed(0, 0, event.motion.x, event.motion.y);
g_AppPlatform->setMouseDiff(event.motion.xrel, event.motion.yrel);
break;
}
case SDL_MOUSEWHEEL: {
Mouse::feed(3, event.wheel.y, Mouse::_x, Mouse::_y);
break;
}
case SDL_TEXTINPUT: {
if (g_pApp != nullptr) {
char x = event.text.text[0];
if (x >= ' ' && x <= '~') {
g_pApp->handleCharInput(x);
}
}
break;
}
case SDL_WINDOWEVENT: {
if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
window_resized = true;
}
break;
}
case SDL_QUIT: {
g_pApp->quit();
break;
}
}
}
}
// GUI Scale
static void calulate_gui_scale() {
int width = Minecraft::width;
// Modified Version Of https://github.com/MCPI-Revival/Ninecraft/blob/3f71638a10b581f6a50669edb24bc1ef1a92fbea/ninecraft/src/main.c#L243-L255
if (width < 1000) {
if (width < 400) {
Gui::InvGuiScale = 1.0;
} else {
Gui::InvGuiScale = 0.5;
}
} else {
Gui::InvGuiScale = 0.25;
}
}
// Resizing
static void resize() {
SDL_GL_GetDrawableSize(window, &Minecraft::width, &Minecraft::height);
calulate_gui_scale();
if (g_pApp != nullptr && g_pApp->m_pScreen != nullptr) {
g_pApp->m_pScreen->setSize(Minecraft::width * Gui::InvGuiScale, Minecraft::height * Gui::InvGuiScale);
}
}
// Main Loop
#ifndef __EMSCRIPTEN__
#define EM_BOOL bool
#define EM_TRUE true
#define EM_FALSE false
#endif
static bool is_first_window_resize = true;
static EM_BOOL main_loop(double time, void *user_data) {
// Handle Events
handle_events();
// Screen Size
if (window_resized) {
window_resized = false;
resize();
}
// Update MCPE
g_pApp->update();
// Swap Buffers
SDL_GL_SwapWindow(window);
if (g_pApp->wantToQuit()) {
delete g_pApp;
delete g_AppPlatform;
teardown();
// Stop Looping
return EM_FALSE;
} else {
// Keep Looping
return EM_TRUE;
}
}
// Main
int main(int argc, char *argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
LOGE("Unable To Initialize SDL: %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
// Configure OpenGL ES Context
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
#ifdef USE_GLES1_COMPATIBILITY_LAYER
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#else
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
#endif
// Double-Buffering
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// Window Size
#ifdef __EMSCRIPTEN__
Minecraft::width = std::stoi(argv[1]);
Minecraft::height = std::stoi(argv[2]);
#endif
// Create Window
window = SDL_CreateWindow("ReMinecraftPE", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, Minecraft::width, Minecraft::height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
if (!window) {
LOGE("Unable To Create SDL Window\n");
exit(EXIT_FAILURE);
}
// Enable Text Input
SDL_StartTextInput();
// Create OpenGL ES Context
context = SDL_GL_CreateContext(window);
if (!context) {
LOGE("Unable To Create OpenGL Context\n");
exit(EXIT_FAILURE);
}
// Setup Compatibility Layer If Needed
#ifdef USE_GLES1_COMPATIBILITY_LAYER
init_gles_compatibility_layer();
#endif
// Setup Teardown
#ifndef __EMSCRIPTEN__
atexit(teardown);
#endif
// Set Size
resize();
// Storage Directory
#ifdef _WIN32
std::string storagePath = getenv("APPDATA");
#elif defined(__EMSCRIPTEN__)
std::string storagePath = "";
#else
std::string storagePath = getenv("HOME");
#endif
storagePath += "/.reminecraftpe";
ensure_screenshots_folder(storagePath.c_str());
// Start MCPE
g_pApp = new NinecraftApp;
g_pApp->m_externalStorageDir = storagePath;
g_AppPlatform = new AppPlatform_sdl(g_pApp->m_externalStorageDir, window);
g_pApp->m_pPlatform = g_AppPlatform;
g_pApp->init();
// Loop
#ifndef __EMSCRIPTEN__
while (true) {
EM_BOOL result = main_loop(0, nullptr);
if (result == EM_FALSE) {
break;
}
}
#else
emscripten_request_animation_frame_loop(main_loop, nullptr);
#endif
return 0;
}

View File

@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>ReMinecraftPE</title>
<style>
html, body {
background-color: black;
width: 100%;
height: 100%;
margin: 0;
}
canvas {
display: block;
border: 0px none;
}
</style>
</head>
<body>
<canvas id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
<script type="text/javascript" src="coi-serviceworker.min.js"></script>
<script type='text/javascript'>
var Module = {
print: function (text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
},
printErr: function (text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function () {
var canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
// application robust, you may want to override this behavior before shipping!
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
// Handle Resize
function setCanvasSize() {
Module.ccall('resize_from_js', null, ['number', 'number'], [window.innerWidth, window.innerHeight]);
}
window.addEventListener("resize", setCanvasSize);
return canvas;
})(),
arguments: [String(window.innerWidth), String(window.innerHeight)]
};
</script>
<script async type="text/javascript" src="reminecraftpe.js"></script>
</body>
</html>

254
source/CMakeLists.txt Normal file
View File

@@ -0,0 +1,254 @@
cmake_minimum_required(VERSION 3.16.0)
project(reminecraftpe-core)
# Build
add_library(reminecraftpe-core STATIC
NinecraftApp.cpp
client/renderer/LevelRenderer.cpp
client/renderer/Culler.cpp
client/renderer/entity/HumanoidMobRenderer.cpp
client/renderer/entity/TntRenderer.cpp
client/renderer/entity/MobRenderer.cpp
client/renderer/entity/FallingTileRenderer.cpp
client/renderer/entity/EntityRenderer.cpp
client/renderer/entity/ItemRenderer.cpp
client/renderer/entity/TripodCameraRenderer.cpp
client/renderer/entity/ItemSpriteRenderer.cpp
client/renderer/entity/EntityRenderDispatcher.cpp
client/renderer/RenderList.cpp
client/renderer/Chunk.cpp
client/renderer/RenderChunk.cpp
client/renderer/Frustum.cpp
client/renderer/ItemInHandRenderer.cpp
client/renderer/DynamicTexture.cpp
client/renderer/GameRenderer.cpp
client/renderer/Textures.cpp
client/renderer/FrustumCuller.cpp
client/renderer/LightUpdate.cpp
client/renderer/Font.cpp
client/renderer/WaterSideTexture.cpp
client/renderer/Tesselator.cpp
client/renderer/TileRenderer.cpp
client/renderer/LightLayer.cpp
client/renderer/WaterTexture.cpp
client/network/Packets/UpdateBlockPacket.cpp
client/network/Packets/RequestChunkPacket.cpp
client/network/Packets/PlayerEquipmentPacket.cpp
client/network/Packets/ChunkDataPacket.cpp
client/network/Packets/PlaceBlockPacket.cpp
client/network/Packets/LoginPacket.cpp
client/network/Packets/StartGamePacket.cpp
client/network/Packets/RemoveEntityPacket.cpp
client/network/Packets/AddPlayerPacket.cpp
client/network/Packets/RemoveBlockPacket.cpp
client/network/Packets/MovePlayerPacket.cpp
client/network/Packets/MessagePacket.cpp
client/network/ServerSideNetworkHandler.cpp
client/network/RakNetInstance.cpp
client/network/ClientSideNetworkHandler.cpp
client/network/MinecraftPackets.cpp
client/network/NetEventCallback.cpp
client/sound/SoundData.cpp
client/sound/SoundSystem.cpp
client/sound/SoundRepository.cpp
client/sound/SoundEngine.cpp
client/gui/Screen.cpp
client/gui/screens/OptionsScreen.cpp
client/gui/screens/StartMenuScreen.cpp
client/gui/screens/CreateWorldScreen.cpp
client/gui/screens/SelectWorldScreen.cpp
client/gui/screens/SavingWorldScreen.cpp
client/gui/screens/InvalidLicenseScreen.cpp
client/gui/screens/ConfirmScreen.cpp
client/gui/screens/DeleteWorldScreen.cpp
client/gui/screens/ChatScreen.cpp
client/gui/screens/RenameMPLevelScreen.cpp
client/gui/screens/ProgressScreen.cpp
client/gui/screens/JoinGameScreen.cpp
client/gui/screens/IngameBlockSelectionScreen.cpp
client/gui/screens/PauseScreen.cpp
client/gui/components/ScrolledSelectionList.cpp
client/gui/components/AvailableGamesList.cpp
client/gui/components/RolledSelectionList.cpp
client/gui/components/Button.cpp
client/gui/components/TextInputBox.cpp
client/gui/components/SmallButton.cpp
client/gui/components/WorldSelectionList.cpp
client/gui/Gui.cpp
client/gui/GuiComponent.cpp
client/model/PolygonQuad.cpp
client/model/Model.cpp
client/model/HumanoidModel.cpp
client/model/Cube.cpp
client/common/Random.cpp
client/common/HitResult.cpp
client/common/Utils.cpp
client/common/PerlinNoise.cpp
client/common/ImprovedNoise.cpp
client/common/Matrix.cpp
client/common/Mth.cpp
client/common/Options.cpp
client/common/Timer.cpp
client/common/Synth.cpp
client/common/CThread.cpp
client/common/Util.cpp
client/common/Vec3.cpp
client/common/AABB.cpp
client/player/input/ControllerTurnInput.cpp
client/player/input/Controller.cpp
client/player/input/Mouse.cpp
client/player/input/Keyboard.cpp
client/player/input/MouseTurnInput.cpp
client/player/input/KeyboardInput.cpp
client/player/input/ITurnInput.cpp
Minecraft.cpp
world/gamemode/SurvivalMode.cpp
world/gamemode/GameMode.cpp
world/gamemode/CreativeMode.cpp
world/entity/Mob.cpp
world/entity/LocalPlayer.cpp
world/entity/Player.cpp
world/entity/PrimedTnt.cpp
world/entity/Entity.cpp
world/entity/FallingTile.cpp
world/entity/TripodCamera.cpp
world/entity/ItemEntity.cpp
world/level/Dimension.cpp
world/level/Material.cpp
world/level/LevelListener.cpp
world/level/TickNextTickData.cpp
world/level/Explosion.cpp
world/level/storage/LevelStorageSource.cpp
world/level/storage/MemoryLevelStorageSource.cpp
world/level/storage/LevelData.cpp
world/level/storage/ExternalFileLevelStorage.cpp
world/level/storage/RegionFile.cpp
world/level/storage/LevelStorage.cpp
world/level/storage/MemoryLevelStorage.cpp
world/level/storage/ChunkStorage.cpp
world/level/storage/LevelSource.cpp
world/level/storage/MemoryChunkStorage.cpp
world/level/storage/ExternalFileLevelStorageSource.cpp
world/level/levelgen/feature/BirchFeature.cpp
world/level/levelgen/feature/LargeFeature.cpp
world/level/levelgen/feature/Feature.cpp
world/level/levelgen/feature/LargeCaveFeature.cpp
world/level/levelgen/feature/SpringFeature.cpp
world/level/levelgen/feature/TreeFeature.cpp
world/level/levelgen/feature/PineFeature.cpp
world/level/levelgen/feature/ReedsFeature.cpp
world/level/levelgen/feature/OreFeature.cpp
world/level/levelgen/feature/ClayFeature.cpp
world/level/levelgen/feature/FlowerFeature.cpp
world/level/levelgen/feature/SpruceFeature.cpp
world/level/levelgen/biome/Biome.cpp
world/level/levelgen/biome/BiomeSource.cpp
world/level/levelgen/chunk/RandomLevelSource.cpp
world/level/levelgen/chunk/LevelChunk.cpp
world/level/levelgen/chunk/ChunkCache.cpp
world/level/levelgen/chunk/ChunkSource.cpp
world/level/levelgen/chunk/PerformanceTestChunkSource.cpp
world/level/levelgen/chunk/TestChunkSource.cpp
world/level/Level.cpp
world/level/Region.cpp
world/item/TilePlanterItem.cpp
world/item/CameraItem.cpp
world/item/TileItem.cpp
world/item/Inventory.cpp
world/item/DoorItem.cpp
world/item/ItemInstance.cpp
world/item/Item.cpp
world/particle/RedDustParticle.cpp
world/particle/TerrainParticle.cpp
world/particle/BubbleParticle.cpp
world/particle/ExplodeParticle.cpp
world/particle/ParticleEngine.cpp
world/particle/FlameParticle.cpp
world/particle/SmokeParticle.cpp
world/particle/Particle.cpp
world/particle/LavaParticle.cpp
world/tile/InvisibleTile.cpp
world/tile/Sapling.cpp
world/tile/TreeTile.cpp
world/tile/GrassTile.cpp
world/tile/HalfTransparentTile.cpp
world/tile/ClothTile.cpp
world/tile/TorchTile.cpp
world/tile/MetalTile.cpp
world/tile/SpongeTile.cpp
world/tile/GlassTile.cpp
world/tile/SandTile.cpp
world/tile/Tile.cpp
world/tile/ClayTile.cpp
world/tile/StoneTile.cpp
world/tile/LadderTile.cpp
world/tile/IceTile.cpp
world/tile/TopSnowTile.cpp
world/tile/ReedTile.cpp
world/tile/Bush.cpp
world/tile/RedStoneOreTile.cpp
world/tile/DirtTile.cpp
world/tile/LiquidTileStatic.cpp
world/tile/BookshelfTile.cpp
world/tile/TntTile.cpp
world/tile/OreTile.cpp
world/tile/StairTile.cpp
world/tile/SandStoneTile.cpp
world/tile/FireTile.cpp
world/tile/StoneSlabTile.cpp
world/tile/LiquidTile.cpp
world/tile/GravelTile.cpp
world/tile/LiquidTileDynamic.cpp
world/tile/TransparentTile.cpp
world/tile/LeafTile.cpp
world/tile/ObsidianTile.cpp
world/tile/FarmTile.cpp
world/tile/DoorTile.cpp
App.cpp
AppPlatform.cpp
)
target_include_directories(reminecraftpe-core PUBLIC . ..)
# RakNet
add_subdirectory(../thirdparty/raknet raknet)
target_link_libraries(reminecraftpe-core PUBLIC raknet)
# SDL
add_library(SDL INTERFACE)
if(EMSCRIPTEN)
set(SDL_FLAG -sUSE_SDL=2)
target_compile_options(SDL INTERFACE "${SDL_FLAG}")
target_link_options(SDL INTERFACE "${SDL_FLAG}")
else()
find_package(SDL2 REQUIRED)
target_link_libraries(SDL INTERFACE SDL2::SDL2)
endif()
target_link_libraries(reminecraftpe-core PUBLIC SDL)
# OpenGL
if(NOT EMSCRIPTEN)
option(USE_GLES1_COMPATIBILITY_LAYER "Whether To Enable The GLESv1_CM Compatibility Layer" TRUE)
else()
set(USE_GLES1_COMPATIBILITY_LAYER TRUE)
endif()
if(USE_GLES1_COMPATIBILITY_LAYER)
set(GLES_COMPATIBILITY_LAYER_USE_SDL TRUE CACHE BOOL "" FORCE)
set(GLES_COMPATIBILITY_LAYER_DEPENDENCY SDL CACHE STRING "" FORCE)
add_subdirectory(../thirdparty/gles-compatibility-layer gles-compatibility-layer)
target_link_libraries(reminecraftpe-core PUBLIC gles-compatibility-layer)
target_compile_definitions(reminecraftpe-core PUBLIC USE_GLES1_COMPATIBILITY_LAYER)
if(EMSCRIPTEN)
target_link_options(reminecraftpe-core PUBLIC -sMIN_WEBGL_VERSION=2 -sMAX_WEBGL_VERSION=2)
endif()
else()
find_package(OpenGL REQUIRED)
target_link_libraries(reminecraftpe-core PUBLIC OpenGL::OpenGL OpenGL::GLU)
endif()
# OpenAL
if(EMSCRIPTEN)
target_link_libraries(reminecraftpe-core PUBLIC openal)
else()
find_library(OPENAL_LIBRARY NAMES openal REQUIRED)
target_link_libraries(reminecraftpe-core PUBLIC "${OPENAL_LIBRARY}")
endif()

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -48,7 +48,7 @@ Minecraft::Minecraft() : m_gui(this)
#else
m_pTurnInput = new ControllerTurnInput;
#endif
m_pRakNetInstance = new RakNetInstance;
m_pSoundEngine = new SoundEngine;
@@ -59,7 +59,7 @@ int Minecraft::getLicenseId()
{
if (m_licenseID < 0)
m_licenseID = m_pPlatform->checkLicense();
return m_licenseID;
}
@@ -80,7 +80,7 @@ void Minecraft::grabMouse()
{
if (m_bGrabbedMouse)
return;
m_bGrabbedMouse = true;
field_D20 = 0.0f;
field_D24 = 0.0f;
@@ -91,6 +91,12 @@ void Minecraft::grabMouse()
void Minecraft::setScreen(Screen* pScreen)
{
#ifndef ORIGINAL_CODE
if (pScreen == nullptr && !isLevelGenerated()) {
return;
}
#endif
if (m_bUsingScreen)
{
m_bHasQueuedScreen = true;
@@ -396,7 +402,7 @@ void Minecraft::tickInput()
{
m_gui.handleKeyPressed(keyCode);
int index = keyCode - '1';
int index = keyCode - AKEYCODE_1;
if (index <= 8 && index >= 0)
{
m_pLocalPlayer->m_pInventory->selectSlot(index);
@@ -441,7 +447,7 @@ void Minecraft::tickInput()
}
}
// @TODO: fix gotos
// @TODO: fix gotos
bool v12 = false;
if (m_options.field_19)
@@ -484,7 +490,7 @@ void Minecraft::tickMouse()
{
if (!m_bGrabbedMouse)
return;
platform()->recenterMouse();
}
@@ -506,7 +512,7 @@ void Minecraft::tick()
field_DA4--;
tickInput();
m_gui.tick();
// if the level has been prepared, delete the prep thread
@@ -547,8 +553,12 @@ void Minecraft::tick()
#ifndef ORIGINAL_CODE
if (m_pMobPersp)
{
#ifdef USE_SDL
m_pSoundEngine->m_soundSystem.update(m_pMobPersp->m_pos.x, m_pMobPersp->m_pos.y, m_pMobPersp->m_pos.z, m_pMobPersp->m_yaw);
#else
m_pSoundEngine->m_soundSystem.setListenerPos(m_pMobPersp->m_pos.x, m_pMobPersp->m_pos.y, m_pMobPersp->m_pos.z);
m_pSoundEngine->m_soundSystem.setListenerAngle(m_pMobPersp->m_yaw, m_pMobPersp->m_pitch);
#endif
}
#endif
@@ -653,7 +663,7 @@ void Minecraft::prepareLevel(const std::string& unused)
float startTime = getTimeS();
Level* pLevel = m_pLevel;
if (!pLevel->field_B0C)
{
pLevel->setUpdateLights(0);
@@ -769,7 +779,7 @@ void Minecraft::generateLevel(const std::string& unused, Level* pLevel)
if (m_pLevelRenderer)
m_pLevelRenderer->setLevel(pLevel);
if (m_pParticleEngine)
m_pParticleEngine->setLevel(pLevel);
@@ -925,30 +935,38 @@ void Minecraft::leaveGame(bool bCopyMap)
void Minecraft::hostMultiplayer()
{
#ifndef __EMSCRIPTEN__
m_pRakNetInstance->host(m_pUser->field_0, C_DEFAULT_PORT, C_MAX_CONNECTIONS);
m_pNetEventCallback = new ServerSideNetworkHandler(this, m_pRakNetInstance);
#endif
}
void Minecraft::joinMultiplayer(const PingedCompatibleServer& serverInfo)
{
#ifndef __EMSCRIPTEN__
if (field_18 && m_pNetEventCallback)
{
field_18 = false;
m_pRakNetInstance->connect(serverInfo.m_address.ToString(), serverInfo.m_address.GetPort());
}
#endif
}
void Minecraft::cancelLocateMultiplayer()
{
#ifndef __EMSCRIPTEN__
field_18 = false;
m_pRakNetInstance->stopPingForHosts();
delete m_pNetEventCallback;
m_pNetEventCallback = nullptr;
#endif
}
void Minecraft::locateMultiplayer()
{
#ifndef __EMSCRIPTEN__
field_18 = true;
m_pRakNetInstance->pingForHosts(C_DEFAULT_PORT);
m_pNetEventCallback = new ClientSideNetworkHandler(this, m_pRakNetInstance);
#endif
}

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/

View File

@@ -33,6 +33,8 @@
int g_TimeSecondsOnInit = 0;
#ifndef USE_SDL
DIR* opendir(const char* name)
{
size_t len = strlen(name);
@@ -97,6 +99,13 @@ void closedir(DIR* dir)
free(dir);
}
#else
#include <sys/types.h>
#include <dirent.h>
#endif
bool createFolderIfNotExists(const char* pDir)
{
if (!XPL_ACCESS(pDir, 0))

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -21,6 +21,6 @@ public:
void fillGradient(int left, int top, int right, int bottom, int colorUp, int colorDown);
public:
float field_4;
float field_4 = 0;
};

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -30,7 +30,7 @@ void Screen::init(Minecraft* pMinecraft, int a3, int a4)
void Screen::init()
{
}
void Screen::buttonClicked(Button* pButton)
@@ -65,7 +65,7 @@ bool Screen::isInGameScreen()
void Screen::keyPressed(int key)
{
if (key == '\x1B')//escape
if (key == AKEYCODE_MENU)//escape
{
m_pMinecraft->setScreen(nullptr);
}

View File

@@ -128,6 +128,11 @@ void TextInputBox::keyPressed(Minecraft* minecraft, int key)
case AKEYCODE_ARROW_RIGHT:
chr = '\003';
break;
#ifdef USE_SDL
case AKEYCODE_DEL:
chr = '\b';
break;
#endif
}
#endif

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -93,7 +93,7 @@ void StartMenuScreen::init()
m_buyButton.m_yPos = yPos;
m_startButton.m_xPos = (m_width - m_startButton.m_width) / 2;
int x1 = m_width - m_joinButton.m_width;
m_joinButton.m_xPos = x1 / 2;

View File

@@ -8,6 +8,8 @@
#include "Controller.hpp"
#include <cmath>
bool Controller::isTouchedValues[2];
float Controller::stickValuesX[2];
float Controller::stickValuesY[2];

View File

@@ -9,6 +9,8 @@
#include "ControllerTurnInput.hpp"
#include "Controller.hpp"
#include <cmath>
ITurnInput::Delta ControllerTurnInput::getTurnDelta()
{
bool isTouched = Controller::isTouched(m_stickNo);

View File

@@ -1,19 +1,28 @@
/********************************************************************
Minecraft: Pocket Edition - Decompilation Project
Copyright (C) 2023 iProgramInCpp
The following code is licensed under the BSD 1 clause license.
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "Keyboard.hpp"
#include "GameMods.hpp"
std::vector<Keyboard::Input> Keyboard::_inputs;
int Keyboard::_index = -1;
int Keyboard::_states[256];
int Keyboard::_states[KEYBOARD_STATES_SIZE];
void Keyboard::feed(int down, int key)
{
#ifndef ORIGINAL_CODE
// Prevent Crashes
if (key >= KEYBOARD_STATES_SIZE || key < 0) {
return;
}
#endif
Input i;
i.field_0 = down;
i.field_4 = uint8_t(key);

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -9,6 +9,9 @@
#pragma once
#include <vector>
#include <cstdint>
#define KEYBOARD_STATES_SIZE 256
class Keyboard
{
@@ -21,7 +24,7 @@ public:
};
static std::vector<Input> _inputs;
static int _states[256];
static int _states[KEYBOARD_STATES_SIZE];
static int _index;
// likely inlined

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -328,7 +328,7 @@ void GameRenderer::setupFog(int i)
float GameRenderer::getFov(float f)
{
Mob* pMob = m_pMinecraft->m_pMobPersp;
float x1 = 70.0f;
if (pMob->isUnderLiquid(Material::water))

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -459,14 +459,14 @@ void LevelRenderer::render(Mob* pMob, int a, float b)
if (!a)
field_54 = field_58 = field_5C = field_60 = field_64 = 0;
float mobX1 = pMob->m_pos.x;
float mobX2 = pMob->field_98.x + (pMob->m_pos.x - pMob->field_98.x) * b;
float mobY1 = pMob->m_pos.y;
float mobY2 = pMob->field_98.y + (pMob->m_pos.y - pMob->field_98.y) * b;
float mobZ1 = pMob->m_pos.z;
float mobZ2 = pMob->field_98.z + (pMob->m_pos.z - pMob->field_98.z) * b;
float dX = pMob->m_pos.x - field_4, dY = pMob->m_pos.y - field_8, dZ = pMob->m_pos.z - field_C;
if (dX * dX + dY * dY + dZ * dZ > 16.0f)
@@ -567,7 +567,8 @@ void LevelRenderer::render(Mob* pMob, int a, float b)
y3++;
y2++;
pChunk->field_4E++;
//pChunk->field_4E++;
pChunk->field_4E = true;
if (y3 == x3)
goto label_37;
}
@@ -576,7 +577,7 @@ void LevelRenderer::render(Mob* pMob, int a, float b)
label_26:
y3++;
y2++;
if (y3 == x3)
goto label_37;
@@ -663,7 +664,7 @@ void LevelRenderer::tick()
void LevelRenderer::updateDirtyChunks(Mob* pMob, bool b)
{
// @TODO This updates 16 chunks per frame. Not good.
int updated = 0;
for (int i = 0; i < 16 && i < int(field_88.size()); i++)
{
@@ -1021,7 +1022,7 @@ void LevelRenderer::takePicture(TripodCamera* pCamera, Entity* pOwner)
#ifdef ENH_CAMERA_NO_PARTICLES
g_bDisableParticles = false;
#endif
t_keepPic = -1;
static char str[256];
@@ -1100,7 +1101,7 @@ void LevelRenderer::renderSky(float f)
{
if (m_pMinecraft->m_pLevel->m_pDimension->field_C)
return;
glDisable(GL_TEXTURE_2D);
Vec3 skyColor = m_pLevel->getSkyColor(m_pMinecraft->m_pMobPersp, f);

View File

@@ -9,6 +9,8 @@
#include "RenderList.hpp"
#include "Tesselator.hpp"
#include <cstddef>
constexpr int C_MAX_RENDERS = 3072;
RenderList::RenderList()

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -9,6 +9,8 @@
#include "compat/GL.hpp"
#include "Tesselator.hpp"
#include <cstddef>
int dword_2514A4 = 0;
Tesselator Tesselator::instance;

View File

@@ -1,7 +1,7 @@
/********************************************************************
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
********************************************************************/
@@ -69,7 +69,7 @@ int Textures::assignTexture(const std::string& name, Texture& texture)
if (texture.field_C)
internalFormat = GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, texture.m_width, texture.m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture.m_pixels);
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, texture.m_width, texture.m_height, 0, internalFormat, GL_UNSIGNED_BYTE, texture.m_pixels);
m_textures[name] = textureID;

View File

@@ -63,8 +63,13 @@ void SoundEngine::play(const std::string& name)
SoundDesc sd;
if (m_repository.get(name, sd))
if (m_repository.get(name, sd)) {
#ifdef USE_SDL
m_soundSystem.play(sd, 0, 0, 0, 1, 1, true);
#else
m_soundSystem.playAt(sd, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f);
#endif
}
}
void SoundEngine::play(const std::string& name, float a, float b, float c, float d, float e)
@@ -74,6 +79,11 @@ void SoundEngine::play(const std::string& name, float a, float b, float c, float
SoundDesc sd;
if (m_repository.get(name, sd))
if (m_repository.get(name, sd)) {
#ifdef USE_SDL
m_soundSystem.play(sd, a, b, c, d, e, false);
#else
m_soundSystem.playAt(sd, a, b, c, d, e);
#endif
}
}

1
thirdparty/coi-serviceworker vendored Submodule

View File

@@ -1 +1,117 @@
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION 3.16.0)
project(raknet)
# Build
add_library(raknet STATIC
VariadicSQLParser.cpp
SuperFastHash.cpp
VariableListDeltaTracker.cpp
StatisticsHistory.cpp
SendToThread.cpp
SignaledEvent.cpp
ReplicaManager3.cpp
IncrementalReadInterface.cpp
Getche.cpp
RakNetSocket2_Berkley_NativeClient.cpp
WSAStartupSingleton.cpp
DataCompressor.cpp
RakMemoryOverride.cpp
CommandParserInterface.cpp
GetTime.cpp
RakNetSocket2_Berkley.cpp
PacketOutputWindowLogger.cpp
DynDNS.cpp
LocklessTypes.cpp
UDPForwarder.cpp
RakString.cpp
SimpleMutex.cpp
Itoa.cpp
VitaIncludes.cpp
TableSerializer.cpp
EpochTimeToString.cpp
ConnectionGraph2.cpp
EmailSender.cpp
UDPProxyCoordinator.cpp
UDPProxyClient.cpp
CloudClient.cpp
ReadyEvent.cpp
MessageFilter.cpp
TCPInterface.cpp
PS4Includes.cpp
NatPunchthroughClient.cpp
RakNetStatistics.cpp
PacketConsoleLogger.cpp
RakNetSocket2_NativeClient.cpp
PacketLogger.cpp
Gets.cpp
NatPunchthroughServer.cpp
FileOperations.cpp
CheckSum.cpp
HTTPConnection.cpp
NatTypeDetectionServer.cpp
RakNetSocket.cpp
DS_Table.cpp
RakNetSocket2.cpp
PacketizedTCP.cpp
RelayPlugin.cpp
ThreadsafePacketLogger.cpp
Rand.cpp
GridSectorizer.cpp
DS_BytePool.cpp
FullyConnectedMesh2.cpp
SocketLayer.cpp
RakWString.cpp
UDPProxyServer.cpp
StringTable.cpp
DR_SHA1.cpp
LinuxStrings.cpp
VariableDeltaSerializer.cpp
CloudServer.cpp
RPC4Plugin.cpp
PacketFileLogger.cpp
CloudCommon.cpp
SecureHandshake.cpp
FormatString.cpp
RakNetSocket2_PS4.cpp
DS_ByteQueue.cpp
NetworkIDObject.cpp
PluginInterface2.cpp
RakNetSocket2_WindowsStore8.cpp
RandSync.cpp
RakPeer.cpp
RakNetTransport2.cpp
RakNetSocket2_Windows_Linux_360.cpp
NatTypeDetectionClient.cpp
ConsoleServer.cpp
TelnetTransport.cpp
Base64Encoder.cpp
TeamManager.cpp
RakThread.cpp
DirectoryDeltaTransfer.cpp
CCRakNetSlidingWindow.cpp
Router2.cpp
StringCompressor.cpp
ReliabilityLayer.cpp
RakNetSocket2_Vita.cpp
NatTypeDetectionCommon.cpp
Rackspace.cpp
RakNetCommandParser.cpp
LogCommandParser.cpp
BitStream.cpp
HTTPConnection2.cpp
RakNetSocket2_Windows_Linux.cpp
RakNetTypes.cpp
RakNetSocket2_PS3_PS4.cpp
FileListTransfer.cpp
FileList.cpp
TwoWayAuthentication.cpp
_FindFirst.cpp
DS_HuffmanEncodingTree.cpp
gettimeofday.cpp
NetworkIDManager.cpp
TeamBalancer.cpp
CCRakNetUDT.cpp
RakNetSocket2_360_720.cpp
RakSleep.cpp
)
target_include_directories(raknet PUBLIC .)

View File

@@ -20,7 +20,7 @@
#include <io.h>
#elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __S3E__ )
#elif !defined ( __APPLE__ ) && !defined ( __APPLE_CC__ ) && !defined ( __PPC__ ) && !defined ( __FreeBSD__ ) && !defined ( __S3E__ ) && !defined( __EMSCRIPTEN__ )
#include <sys/io.h>
#endif