diff --git a/binding/binding-mri.cpp b/binding/binding-mri.cpp index 9a80bcb5..f7f293a1 100644 --- a/binding/binding-mri.cpp +++ b/binding/binding-mri.cpp @@ -326,8 +326,7 @@ RB_METHOD(mriP) { RB_METHOD(mkxpDelta) { RB_UNUSED_PARAM; - - return ULL2NUM(shState->runTime()); + return rb_float_new(shState->runTime()); } RB_METHOD(mkxpDataDirectory) { diff --git a/binding/bitmap-binding.cpp b/binding/bitmap-binding.cpp index b8c7b086..597b1f94 100644 --- a/binding/bitmap-binding.cpp +++ b/binding/bitmap-binding.cpp @@ -434,7 +434,11 @@ RB_METHOD(bitmapGetMega){ Bitmap *b = getPrivateData(self); - return rb_bool_new(b->isMega()); + VALUE ret; + + GFX_GUARD_EXC(ret = rb_bool_new(b->isMega());); + + return ret; } RB_METHOD(bitmapGetAnimated){ @@ -444,7 +448,11 @@ RB_METHOD(bitmapGetAnimated){ Bitmap *b = getPrivateData(self); - return rb_bool_new(b->isAnimated()); + VALUE ret; + + GFX_GUARD_EXC(ret = rb_bool_new(b->isAnimated());); + + return ret; } RB_METHOD(bitmapGetPlaying){ diff --git a/binding/disposable-binding.h b/binding/disposable-binding.h index 637c0425..2d22895a 100644 --- a/binding/disposable-binding.h +++ b/binding/disposable-binding.h @@ -37,6 +37,8 @@ disposableAddChild(VALUE disp, VALUE child) return; } + VALUE objID = rb_obj_id(child); + VALUE children = rb_iv_get(disp, "children"); bool exists = false; @@ -47,11 +49,11 @@ disposableAddChild(VALUE disp, VALUE child) rb_iv_set(disp, "children", children); } else { - exists = RTEST(rb_funcall(children, rb_intern("include?"), 1, child)); + exists = RTEST(rb_funcall(children, rb_intern("include?"), 1, objID)); } if (!exists) - rb_ary_push(children, child); + rb_ary_push(children, objID); GFX_UNLOCK; } @@ -63,11 +65,13 @@ disposableRemoveChild(VALUE disp, VALUE child) return; } + VALUE objID = rb_obj_id(child); + VALUE children = rb_iv_get(disp, "children"); if (NIL_P(children)) return; - VALUE index = rb_funcall(children, rb_intern("index"), 1, child); + VALUE index = rb_funcall(children, rb_intern("index"), 1, objID); if (NIL_P(index)) return; @@ -83,10 +87,16 @@ disposableDisposeChildren(VALUE disp) if (NIL_P(children)) return; - ID dispFun = rb_intern("_mkxp_dispose_alias"); - - for (long i = 0; i < RARRAY_LEN(children); ++i) - rb_funcall2(rb_ary_entry(children, i), dispFun, 0, 0); + for (long i = 0; i < RARRAY_LEN(children); ++i) { + int state; + rb_protect([](VALUE args){ + VALUE objectspace = rb_const_get(rb_cObject, rb_intern("ObjectSpace")); + VALUE ref = rb_funcall(objectspace, rb_intern("_id2ref"), 1, args); + rb_funcall(ref, rb_intern("_mkxp_dispose_alias"), 0); + return Qnil; + }, rb_ary_entry(children, i), &state); + } + //rb_funcall2(rb_ary_entry(children, i), dispFun, 0, 0); } template diff --git a/binding/graphics-binding.cpp b/binding/graphics-binding.cpp index 5b17f348..d7292598 100644 --- a/binding/graphics-binding.cpp +++ b/binding/graphics-binding.cpp @@ -32,7 +32,7 @@ RB_METHOD(graphicsDelta) { RB_UNUSED_PARAM; GFX_LOCK; - VALUE ret = ULL2NUM(shState->graphics().getDelta()); + VALUE ret = rb_float_new(shState->graphics().getDelta()); GFX_UNLOCK; return ret; } diff --git a/binding/input-binding.cpp b/binding/input-binding.cpp index 3bb8163d..c06270d3 100644 --- a/binding/input-binding.cpp +++ b/binding/input-binding.cpp @@ -34,7 +34,7 @@ RB_METHOD(inputDelta) { RB_UNUSED_PARAM; - return ULL2NUM(shState->input().getDelta()); + return rb_float_new(shState->input().getDelta()); } RB_METHOD(inputUpdate) { diff --git a/src/display/bitmap.cpp b/src/display/bitmap.cpp index c71f8a72..4b431231 100644 --- a/src/display/bitmap.cpp +++ b/src/display/bitmap.cpp @@ -166,12 +166,11 @@ struct BitmapPrivate std::vector frames; float fps; int lastFrame; - unsigned long long startTime; - unsigned long long playTime; + double startTime, playTime; inline unsigned int currentFrameIRaw() { if (fps <= 0) return lastFrame; - return floor(lastFrame + (playTime / ((1 / fps) * 1000000))); + return floor(lastFrame + (playTime / (1 / fps))); } unsigned int currentFrameI() { @@ -2104,6 +2103,24 @@ int Bitmap::maxSize(){ return glState.caps.maxTexSize; } +// This might look ridiculous, but apparently, it is possible +// to encounter seemingly empty bitmaps during Graphics::update, +// or specifically, during a Sprite's prepare function. + +// I have no idea why it happens, but it seems like just skipping +// them makes it okay, so... that's what this function is for, at +// least unless the actual source of the problem gets found, at +// which point I'd get rid of it. + +// I get it to happen by trying to beat the first rival fight in +// Pokemon Flux, on macOS. I don't think I've seen anyone bring up +// something like this happening anywhere else, so... I dunno. +// If a game suddenly explodes during Graphics.update, maybe try +// breakpointing this? +bool Bitmap::invalid() const { + return p == 0; +} + void Bitmap::releaseResources() { if (p->megaSurface) diff --git a/src/display/bitmap.h b/src/display/bitmap.h index 8d51d774..0b747470 100644 --- a/src/display/bitmap.h +++ b/src/display/bitmap.h @@ -158,6 +158,8 @@ public: sigslot::signal<> modified; static int maxSize(); + + bool invalid() const; private: void releaseResources(); diff --git a/src/display/graphics.cpp b/src/display/graphics.cpp index b72ad013..64dc47f3 100644 --- a/src/display/graphics.cpp +++ b/src/display/graphics.cpp @@ -797,7 +797,7 @@ struct GraphicsPrivate { int frameCount; int brightness; - unsigned long long last_update; + double last_update; FPSLimiter fpsLimiter; @@ -816,8 +816,8 @@ struct GraphicsPrivate { bool integerScaleActive; bool integerLastMileScaling; - std::vector avgFPSData; - unsigned long long last_avg_update; + std::vector avgFPSData; + double last_avg_update; SDL_mutex *avgFPSLock; SDL_mutex *glResourceLock; @@ -837,7 +837,7 @@ struct GraphicsPrivate { last_update(0), last_avg_update(0), backingScaleFactor(1), integerScaleFactor(0, 0), integerScaleActive(rtData->config.integerScaling.active), integerLastMileScaling(rtData->config.integerScaling.lastMileScaling) { - avgFPSData = std::vector(); + avgFPSData = std::vector(); avgFPSLock = SDL_CreateMutex(); glResourceLock = SDL_CreateMutex(); @@ -1079,7 +1079,7 @@ struct GraphicsPrivate { if (avgFPSData.size() > 40) avgFPSData.erase(avgFPSData.begin()); - unsigned long long time = shState->runTime(); + double time = shState->runTime(); avgFPSData.push_back(time - last_avg_update); last_avg_update = time; SDL_UnlockMutex(avgFPSLock); @@ -1102,10 +1102,10 @@ struct GraphicsPrivate { double averageFPS() { double ret = 0; SDL_LockMutex(avgFPSLock); - for (unsigned long long times : avgFPSData) + for (double times : avgFPSData) ret += times; - ret = 1 / (ret / avgFPSData.size() / 1000000); + ret = 1 / (ret / avgFPSData.size()); SDL_UnlockMutex(avgFPSLock); return ret; } @@ -1138,11 +1138,11 @@ Graphics::Graphics(RGSSThreadData *data) { Graphics::~Graphics() { delete p; } -unsigned long long Graphics::getDelta() { +double Graphics::getDelta() { return shState->runTime() - p->last_update; } -unsigned long long Graphics::lastUpdate() { +double Graphics::lastUpdate() { return p->last_update; } diff --git a/src/display/graphics.h b/src/display/graphics.h index cf2ff17e..b29f68a5 100644 --- a/src/display/graphics.h +++ b/src/display/graphics.h @@ -36,8 +36,8 @@ struct Movie; class Graphics { public: - unsigned long long getDelta(); - unsigned long long lastUpdate(); + double getDelta(); + double lastUpdate(); void update(bool checkForShutdown = true); void freeze(); diff --git a/src/display/sprite.cpp b/src/display/sprite.cpp index 3e7f1d5c..7d956327 100644 --- a/src/display/sprite.cpp +++ b/src/display/sprite.cpp @@ -188,6 +188,9 @@ struct SpritePrivate if (nullOrDisposed(bitmap)) return; + if (bitmap->invalid()) + return; + if (!opacity) return; diff --git a/src/input/input.cpp b/src/input/input.cpp index 993473e7..67c77996 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -707,14 +707,12 @@ struct InputPrivate unsigned int rawRepeatCount; unsigned int buttonRepeatCount; - unsigned long long repeatTime; - unsigned long long rawRepeatTime; - unsigned long long buttonRepeatTime; + double repeatTime, rawRepeatTime, buttonRepeatTime; unsigned int repeatStart; unsigned int repeatDelay; - unsigned long long last_update; + double last_update; int vScrollDistance; @@ -1185,7 +1183,7 @@ Input::Input(const RGSSThreadData &rtData) p = new InputPrivate(rtData); } -unsigned long long Input::getDelta() { +double Input::getDelta() { return shState->runTime() - p->last_update; } @@ -1301,7 +1299,7 @@ unsigned int Input::count(int button) { return p->repeatCount; } -unsigned long long Input::repeatTime(int button) { +double Input::repeatTime(int button) { if (button != p->repeating) return 0; @@ -1367,7 +1365,7 @@ unsigned int Input::controllerRepeatcount(int button) { return p->buttonRepeatCount; } -unsigned long long Input::repeatTimeEx(int code, bool isVKey) { +double Input::repeatTimeEx(int code, bool isVKey) { int c = code; if (isVKey) { try { c = vKeyToScancode[code]; } @@ -1380,7 +1378,7 @@ unsigned long long Input::repeatTimeEx(int code, bool isVKey) { return shState->runTime() - p->rawRepeatTime; } -unsigned long long Input::controllerRepeatTimeEx(int button) { +double Input::controllerRepeatTimeEx(int button) { if (button != p->buttonRepeating) return 0; diff --git a/src/input/input.h b/src/input/input.h index dacfe717..ac6a8a10 100644 --- a/src/input/input.h +++ b/src/input/input.h @@ -58,7 +58,7 @@ public: void recalcRepeat(unsigned int fps); - unsigned long long getDelta(); + double getDelta(); void update(); std::vector getBindings(ButtonCode code); @@ -68,21 +68,21 @@ public: bool isRepeated(int button); bool isReleased(int button); unsigned int count(int button); - unsigned long long repeatTime(int button); + double repeatTime(int button); bool isPressedEx(int code, bool isVKey); bool isTriggeredEx(int code, bool isVKey); bool isRepeatedEx(int code, bool isVKey); bool isReleasedEx(int code, bool isVKey); unsigned int repeatcount(int code, bool isVKey); - unsigned long long repeatTimeEx(int code, bool isVKey); + double repeatTimeEx(int code, bool isVKey); bool controllerIsPressedEx(int button); bool controllerIsTriggeredEx(int button); bool controllerIsRepeatedEx(int button); bool controllerIsReleasedEx(int button); unsigned int controllerRepeatcount(int button); - unsigned long long controllerRepeatTimeEx(int button); + double controllerRepeatTimeEx(int button); uint8_t *rawKeyStates(); unsigned int rawKeyStatesLength(); diff --git a/src/sharedstate.cpp b/src/sharedstate.cpp index 28be795e..a66a18ac 100644 --- a/src/sharedstate.cpp +++ b/src/sharedstate.cpp @@ -363,10 +363,10 @@ Font &SharedState::defaultFont() const return *p->defaultFont; } -unsigned long long SharedState::runTime() { +double SharedState::runTime() { if (!p) return 0; const auto now = std::chrono::steady_clock::now(); - return std::chrono::duration_cast(now - p->startupTime).count(); + return std::chrono::duration_cast(now - p->startupTime).count() / 1000.0 / 1000.0; } unsigned int SharedState::genTimeStamp() diff --git a/src/sharedstate.h b/src/sharedstate.h index e27674ff..442cbe35 100644 --- a/src/sharedstate.h +++ b/src/sharedstate.h @@ -86,7 +86,7 @@ struct SharedState unsigned int genTimeStamp(); // Returns time since SharedState was constructed in microseconds - unsigned long long runTime(); + double runTime(); /* Returns global quad IBO, and ensures it has indices * for at least minSize quads */