mirror of
https://forgejo.xatacraft.ru/Sunshine/mkxp-sunshine.git
synced 2026-08-20 22:09:55 +00:00
349 lines
12 KiB
C++
349 lines
12 KiB
C++
#include <SDL3/SDL_messagebox.h>
|
|
#include <SDL3/SDL_dialog.h>
|
|
#include <SDL3/SDL_version.h>
|
|
#include <SDL3/SDL_platform.h>
|
|
#include <SDL3/SDL_rect.h>
|
|
#include <SDL3/SDL_audio.h>
|
|
#include <SDL3/SDL_video.h>
|
|
#include <SDL3_image/SDL_image.h>
|
|
#include <SDL3_ttf/SDL_ttf.h>
|
|
#include <SDL3/SDL_filesystem.h>
|
|
#include "meow.h"
|
|
#include "eventthread.h"
|
|
#include "exception.h"
|
|
#include "config.h"
|
|
#include "gl-debug.h"
|
|
#include "gl-fun.h"
|
|
#include "debugwriter.h"
|
|
#include "define.h"
|
|
#include <SDL3/SDL_stdinc.h>
|
|
#include <ctime>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <ruby/version.h>
|
|
#include <ruby/internal/interpreter.h>
|
|
#undef vsnprintf
|
|
#undef snprintf
|
|
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
|
#define BOOST_STACKTRACE_GNU_SOURCE_NOT_REQUIRED
|
|
#endif
|
|
#include <boost/stacktrace.hpp>
|
|
#include <boost/version.hpp>
|
|
#include <zlib.h>
|
|
#include <physfs.h>
|
|
#include <pixman.h>
|
|
#include <SDL3/SDL_system.h>
|
|
#include <SDL3/SDL_cpuinfo.h>
|
|
#include "sunshine.h"
|
|
#ifdef unix_like
|
|
#include <gtk/gtk.h>
|
|
#elif android
|
|
#include <android/trace.h>
|
|
#include <android/api-level.h>
|
|
#elif web
|
|
#include <emscripten/console.h>
|
|
#elif dos
|
|
#include <dpmi.h>
|
|
#endif
|
|
#include "crash.png.xxd"
|
|
using namespace std;
|
|
|
|
static inline const char* glGetStringInt(GLenum name){
|
|
return (const char*) gl.GetString(name);
|
|
}
|
|
|
|
static void get_reason_and_solution(Exception::Type t) {
|
|
switch (t) {
|
|
case Exception::ModLoaderError:
|
|
crash_reason = "Broken mod";
|
|
crash_possible_solution = "Fix mode manualy or ask developer to fix it or delete mod";
|
|
break;
|
|
case Exception::NoFileError:
|
|
crash_reason = "Broken installation";
|
|
crash_possible_solution = "Try reinstall game";
|
|
break;
|
|
case Exception::ShaderError:
|
|
crash_reason = "Broken Shader";
|
|
crash_possible_solution = "Try reinstall game";
|
|
break;
|
|
case Exception::RGSSError:
|
|
crash_reason = "Internal Error";
|
|
crash_possible_solution = "Try reinstall game or disable some mods";
|
|
break;
|
|
case Exception::RUBYError:
|
|
crash_reason = "Internal Error";
|
|
crash_possible_solution = "Try reinstall game or disable some mods";
|
|
break;
|
|
case Exception::IOError:
|
|
crash_reason = "Broken installation";
|
|
crash_possible_solution = "Try reinstall game";
|
|
break;
|
|
case Exception::TypeError:
|
|
crash_reason = "Internal Error";
|
|
crash_possible_solution = "Try reinstall game or disable some mods";
|
|
break;
|
|
case Exception::ArgumentError:
|
|
crash_reason = "Internal error";
|
|
crash_possible_solution = "Try reinstall game or disable some mods";
|
|
break;
|
|
case Exception::PHYSFSError:
|
|
crash_reason = "Internal error";
|
|
crash_possible_solution = "Maybe you tryed load corrupted mod via modloader, try delete it";
|
|
break;
|
|
case Exception::SDLError:
|
|
crash_reason = "Internal error";
|
|
crash_possible_solution = "Internal Engine Error, maybe something wrong with your device or operating system";
|
|
break;
|
|
case Exception::MKXPError:
|
|
crash_reason = "Internal error";
|
|
crash_possible_solution = "Try reinstall game or disable some mods";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void crash(Exception::Type t, const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
unsigned int len = (unsigned int)SDL_vsnprintf(NULL, 0, fmt, args_copy);
|
|
va_end(args_copy);
|
|
|
|
if (len >= sizeof(crash_message)) len = sizeof(crash_message) - 1;
|
|
|
|
SDL_vsnprintf(crash_message, sizeof(crash_message), fmt, args);
|
|
va_end(args);
|
|
get_reason_and_solution(t);
|
|
show_crash_sceen = true;
|
|
//Protect against segfaults
|
|
if(is_ruby_initialized)
|
|
ruby_stop(-1);
|
|
}
|
|
|
|
void crash_screen(SDL_Window* win){
|
|
// Skil Crash screen if failed initialize
|
|
static bool skip_crash_screen = false;
|
|
//creating render
|
|
SDL_Renderer* ren = SDL_CreateRenderer(win, NULL);
|
|
if (ren == nullptr) {
|
|
WarnMsg("Failed to create renderer, please check if your device is too strong to run game or report bug.Error Message: ", SDL_GetError());
|
|
skip_crash_screen = true;
|
|
}
|
|
SDL_Surface* crash_img = IMG_Load_IO(SDL_IOFromConstMem(assets_crash_png, assets_crash_png_len), true);
|
|
if (crash_img == nullptr) {
|
|
WarnMsg("Failed to create surface, please check if your device is too strong to run game or report bug.Error Message: ", SDL_GetError());
|
|
skip_crash_screen = true;
|
|
}
|
|
SDL_Texture* tex = SDL_CreateTextureFromSurface(ren, crash_img);
|
|
SDL_DestroySurface(crash_img);
|
|
if (tex == nullptr) {
|
|
WarnMsg("Failed to create texture, please check if your device is too strong to run game or report bug.Error Message: ", SDL_GetError());
|
|
skip_crash_screen = true;
|
|
}else{
|
|
SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_NEAREST);
|
|
}
|
|
//creating file and timestamp
|
|
ofstream o;
|
|
time_t timestamp;
|
|
time(×tamp);
|
|
string timeeeeee(ctime(×tamp));
|
|
if (!timeeeeee.empty() && timeeeeee.back() == '\n') {
|
|
timeeeeee.pop_back();
|
|
}
|
|
string file = "crash " + timeeeeee + ".txt";
|
|
std::erase(file, ':');
|
|
o.open(file);
|
|
//collecting info and writing to crashdump
|
|
if (o.is_open()){
|
|
#ifdef DEVBUILD
|
|
o << "EXPEREMENTAL BUILD" << endl;
|
|
#endif
|
|
o << "VERSION: " << VERSION_STRING << endl;
|
|
o << "REASON: " << crash_message << endl;
|
|
o << "[BOOST stacktrace()]" << endl << endl;
|
|
o << boost::stacktrace::stacktrace() << endl;
|
|
|
|
o << "[LOG BUFFER]" << endl << endl;
|
|
for (const auto& s : logs) {
|
|
o << s << endl;
|
|
}
|
|
|
|
o << endl;
|
|
o << "[AUDIO]" << endl;
|
|
o << "Driver used: " << SDL_GetCurrentAudioDriver() << endl;
|
|
|
|
o << endl;
|
|
o << "[VIDEO]" << endl;
|
|
o << "Driver used: " << SDL_GetCurrentVideoDriver() << endl;
|
|
|
|
o << endl;
|
|
o << "[VERSIONS OF LIBS]" << endl;
|
|
const static int sdlcompiled = SDL_VERSION;
|
|
const static int sdllinked = SDL_GetVersion();
|
|
o << "SDL(compiled) version: " << SDL_VERSIONNUM_MAJOR(sdlcompiled) << "." << SDL_VERSIONNUM_MINOR(sdlcompiled) << "." << SDL_VERSIONNUM_MICRO(sdlcompiled) << endl;
|
|
o << "SDL(linked) version: " << SDL_VERSIONNUM_MAJOR(sdllinked) << "." << SDL_VERSIONNUM_MINOR(sdllinked) << "." << SDL_VERSIONNUM_MICRO(sdllinked) << endl;
|
|
o << "SDL_image(compiled) version: " << SDL_IMAGE_MAJOR_VERSION << "." << SDL_IMAGE_MINOR_VERSION << "." << SDL_IMAGE_MICRO_VERSION << endl;
|
|
o << "SDL_TTF(compiled) version: " << SDL_TTF_MAJOR_VERSION << "." << SDL_TTF_MINOR_VERSION << "." << SDL_TTF_MICRO_VERSION << endl;
|
|
o << "Ruby version: " << RUBY_API_VERSION_CODE << endl;
|
|
o << "ZLib version: " << ZLIB_VERSION << endl;
|
|
o << "Boost versino: " << BOOST_VERSION / 100000 << "." << BOOST_VERSION / 100 % 1000 << "." << BOOST_VERSION % 100 << endl;
|
|
o << "Pixman version: " << PIXMAN_VERSION_STRING << endl;
|
|
|
|
o << endl;
|
|
o << "[Platform specific]" << endl;
|
|
try{
|
|
o << "Detected OS: " << SDL_GetPlatform() << endl;
|
|
}catch(const std::exception& e){
|
|
o << "Detected OS: " << e.what() << endl;
|
|
}
|
|
o << "System page size: " << SDL_GetSystemPageSize() << endl;
|
|
#ifdef unix_like
|
|
if(SDL_getenv("XDG_CURRENT_DESKTOP") != nullptr){
|
|
o << "Desktop enviroment(XDG_CURRENT_DESKTOP): " << SDL_getenv("XDG_CURRENT_DESKTOP") << endl;
|
|
}
|
|
#elif android
|
|
o << "Android API version: " << android_get_device_api_level() << endl;
|
|
o << "Internal storage path: " << SDL_GetAndroidInternalStoragePath() << endl;
|
|
o << "External Storage path: " << SDL_GetAndroidExternalStoragePath() << endl;
|
|
o << "Cache path: " << SDL_GetAndroidCachePath() << endl;
|
|
if(!is_privacy_crashdump_enabled){
|
|
o << "Is ChromeBook? " << SDL_IsChromebook() << endl;
|
|
o << "Is Phone? " << SDL_IsPhone() << endl;
|
|
o << "Is Tablet? " << SDL_IsTablet() << endl;
|
|
o << "Is Samsung DeX? " << SDL_IsDeXMode() << endl;
|
|
o << "Is TV? " << SDL_IsTV() << endl;
|
|
o << "Is Ubuntu Touch? " << SDL_IsUbuntuTouch() << endl;
|
|
}
|
|
#elif web
|
|
o << "Emscripten start address of the stack: " << emscripten_stack_get_base() << endl;
|
|
o << "Emscripten end address of the stack: " << emscripten_stack_get_end() << endl;
|
|
o << "Emscripten current stack pointer: " << emscripten_stack_get_current() << endl;
|
|
o << "Emscripten number of free bytes left on stack: " << emscripten_stack_get_free() << endl;
|
|
#elif psp
|
|
o << "PSPdev MIPS Stack Trace: " << pspDebugGetStackTrace() << endl;
|
|
#endif
|
|
|
|
o << endl;
|
|
o << "[Hardware]" << endl;
|
|
o << "number of logical CPU cores: " << SDL_GetNumLogicalCPUCores() << endl;
|
|
o << "System RAM size: " << SDL_GetSystemRAM() << " MiB" << endl;
|
|
if(!is_privacy_crashdump_enabled){
|
|
o << "L1 cache size: " << SDL_GetCPUCacheLineSize() << endl;
|
|
}
|
|
|
|
o << endl;
|
|
o << "[OpenGL]" << endl;
|
|
try{
|
|
o << "GL Vendor: " << glGetStringInt(GL_VENDOR) << endl;
|
|
o << "GL Renderer: " << glGetStringInt(GL_RENDERER) << endl;
|
|
o << "GL Version: " << glGetStringInt(GL_VERSION) << endl;
|
|
o << "GLSL Version: " << glGetStringInt(GL_SHADING_LANGUAGE_VERSION) << endl;
|
|
o << "Shading language version: " << glGetStringInt(GL_SHADING_LANGUAGE_VERSION) << endl;
|
|
o << "GL Extensions: " << glGetStringInt(GL_EXTENSIONS) << endl;
|
|
}catch(const exception& e){
|
|
o << "Crashed before OpenGL initialization: " << e.what() << endl;
|
|
}
|
|
o.close();
|
|
}else{
|
|
WarnMsg("[CRASHLOG] Failed to write crashdump file");
|
|
}
|
|
|
|
if(!skip_crash_screen){
|
|
SDL_Event e;
|
|
bool quit = false;
|
|
|
|
int texW = 100, texH = 100;
|
|
int winW = 0, winH = 0;
|
|
SDL_GetWindowSize(win, &winW, &winH);
|
|
SDL_FRect dst{
|
|
(float)((winW - 100) / 2),
|
|
(float)((winH - 100) / 2),
|
|
(float)100,
|
|
(float)100
|
|
};
|
|
|
|
while (!quit) {
|
|
while (SDL_PollEvent(&e)) {
|
|
if (e.type == SDL_EVENT_QUIT) quit = true;
|
|
}
|
|
|
|
SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
|
|
SDL_RenderClear(ren);
|
|
SDL_RenderTexture(ren, tex, NULL, &dst);
|
|
SDL_SetRenderDrawColor(ren, 255, 255, 255, 255);
|
|
SDL_RenderDebugTextFormat(ren, 10, 10, "World machine crashed, crashdump created in game directory");
|
|
SDL_RenderDebugTextFormat(ren, 10, 20, "%s", crash_message);
|
|
SDL_RenderDebugTextFormat(ren, 10, 30, "Possible reason: %s", crash_reason);
|
|
SDL_RenderDebugTextFormat(ren, 10, 40, "Possible solution: %s", crash_possible_solution);
|
|
SDL_RenderDebugTextFormat(ren, 10, 50, "Path: %s%s", SDL_GetCurrentDirectory(), file.c_str());
|
|
SDL_RenderDebugTextFormat(ren, 10, 60, "Crashdump privacy: %s", is_privacy_crashdump_enabled ? "enabled" : "disabled");
|
|
SDL_RenderDebugTextFormat(ren, 10, 70, "If you are sure that the problem is not in your modifications,");
|
|
SDL_RenderDebugTextFormat(ren, 10, 80, "your hands or in your device - please report the bug to the developers");
|
|
SDL_RenderPresent(ren);
|
|
}
|
|
SDL_DestroyTexture(tex);
|
|
SDL_DestroyRenderer(ren);
|
|
}
|
|
}
|
|
|
|
void ErrorMsg(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
unsigned int len = (unsigned int)SDL_vsnprintf(NULL, 0, fmt, args_copy);
|
|
va_end(args_copy);
|
|
|
|
char *buf = (char*)SDL_malloc((size_t)len + 1);
|
|
if (!buf) { va_end(args); return; }
|
|
|
|
SDL_vsnprintf(buf, (size_t)len + 1, fmt, args);
|
|
va_end(args);
|
|
|
|
SDL_snprintf(crash_message, sizeof(crash_message), "%s", buf);
|
|
show_crash_sceen = true;
|
|
}
|
|
|
|
void ErrorMsg(Exception::Type t, const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
unsigned int len = (unsigned int)SDL_vsnprintf(NULL, 0, fmt, args_copy);
|
|
va_end(args_copy);
|
|
|
|
char *buf = (char*)SDL_malloc((size_t)len + 1);
|
|
if (!buf) { va_end(args); return; }
|
|
|
|
SDL_vsnprintf(buf, (size_t)len + 1, fmt, args);
|
|
va_end(args);
|
|
|
|
SDL_snprintf(crash_message, sizeof(crash_message), "%s", buf);
|
|
get_reason_and_solution(t);
|
|
show_crash_sceen = true;
|
|
}
|
|
|
|
void WarnMsg(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
|
|
va_list args_copy;
|
|
va_copy(args_copy, args);
|
|
unsigned int len = (unsigned int)SDL_vsnprintf(NULL, 0, fmt, args_copy);
|
|
va_end(args_copy);
|
|
|
|
char *buf = (char*)SDL_malloc((size_t)len + 1);
|
|
if (!buf) { va_end(args); return; }
|
|
|
|
SDL_vsnprintf(buf, (size_t)len + 1, fmt, args);
|
|
va_end(args);
|
|
Debug() << "[WARNMSG]" << buf;
|
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, "Warning", buf, NULL);
|
|
}
|
|
|