Add 'onEventSpriteLoading' to API
Some checks are pending
Build Porymap / build-linux (, 5.14.2) (push) Waiting to run
Build Porymap / build-linux (, 6.8.*) (push) Waiting to run
Build Porymap / build-linux (minimal, 5.14.2) (push) Waiting to run
Build Porymap / build-macos (macos-15-intel) (push) Waiting to run
Build Porymap / build-macos (macos-latest) (push) Waiting to run
Build Porymap / build-static-windows (push) Waiting to run

This commit is contained in:
GriffinR 2026-01-30 03:37:42 -05:00
parent f2bc3613ad
commit c89aff236f
5 changed files with 60 additions and 20 deletions

View File

@ -213,7 +213,6 @@ public:
QMap<QString, QMap<QString, QString>> readObjEventGfxInfo();
QPixmap getEventPixmap(const QString &gfxName, const QString &movementName);
QPixmap getEventPixmap(const QString &gfxName, int frame, bool hFlip);
QPixmap getEventPixmap(Event::Group group);
void loadEventPixmap(Event *event, bool forceLoad = false);
@ -360,6 +359,7 @@ private:
bool appendTextFile(const QString &path, const QString &text);
QString findSpeciesIconPath(const QStringList &names) const;
QPixmap getEventPixmap(const QString &gfxName, int frame, bool hFlip);
int maxObjectEvents;
int maxMapDataSize;

View File

@ -37,6 +37,7 @@ enum CallbackType {
OnMainTabChanged,
OnMapViewTabChanged,
OnBorderVisibilityToggled,
OnEventSpriteLoading,
};
class Scripting
@ -67,6 +68,7 @@ public:
static void cb_MainTabChanged(int oldTab, int newTab);
static void cb_MapViewTabChanged(int oldTab, int newTab);
static void cb_BorderVisibilityToggled(bool visible);
static QImage cb_EventSpriteLoading(const QString &gfxName, const QString &direction);
static bool tryErrorJS(QJSValue js);
static QJSValue fromBlock(Block block);
@ -127,7 +129,7 @@ private:
ScriptUtility *scriptUtility;
void loadScript(const QString &filepath);
void invokeCallback(CallbackType type, const QJSValueList &args);
QJSValue invokeCallback(CallbackType type, const QJSValueList &args);
QSharedPointer<Script> getActiveScript() const;
QJSValue call(QSharedPointer<Script> script, QJSValue func, const QJSValueList &args = QJSValueList());
bool askForTrust(QSharedPointer<Script> script, const QString &reason);
@ -159,6 +161,7 @@ public:
static void cb_MainTabChanged(int, int) {};
static void cb_MapViewTabChanged(int, int) {};
static void cb_BorderVisibilityToggled(bool) {};
static QImage cb_EventSpriteLoading(const QString &, const QString &) {};
};
#endif // QT_QML_LIB

View File

@ -11,6 +11,7 @@
#include "validator.h"
#include "orderedjson.h"
#include "utility.h"
#include "scripting.h"
#include <QDir>
#include <QJsonArray>
@ -3102,6 +3103,19 @@ bool Project::readEventGraphics() {
}
QPixmap Project::getEventPixmap(const QString &gfxName, const QString &movementName) {
QPixmap pixmap;
const QString direction = this->facingDirections.value(movementName, "DIR_SOUTH");
const QString cacheKey = QString("EVENT#%1#%2").arg(gfxName).arg(direction);
if (QPixmapCache::find(cacheKey, &pixmap)) return pixmap;
// Users may intercept the sprite loading with a scripting callback.
QImage scriptImage = Scripting::cb_EventSpriteLoading(gfxName, direction);
if (!scriptImage.isNull()) {
pixmap = QPixmap::fromImage(scriptImage);
QPixmapCache::insert(cacheKey, pixmap);
return pixmap;
}
struct FrameData {
int index;
bool hFlip;
@ -3117,18 +3131,13 @@ QPixmap Project::getEventPixmap(const QString &gfxName, const QString &movementN
{"DIR_WEST", { 2, false }},
{"DIR_EAST", { 2, true }}, // East-facing sprite is just the West-facing sprite mirrored
};
const QString direction = this->facingDirections.value(movementName, "DIR_SOUTH");
auto frameData = directionToFrameData.value(direction);
return getEventPixmap(gfxName, frameData.index, frameData.hFlip);
pixmap = getEventPixmap(gfxName, frameData.index, frameData.hFlip);
QPixmapCache::insert(cacheKey, pixmap);
return pixmap;
}
QPixmap Project::getEventPixmap(const QString &gfxName, int frame, bool hFlip) {
QPixmap pixmap;
const QString cacheKey = QString("EVENT#%1#%2#%3").arg(gfxName).arg(frame).arg(hFlip ? "1" : "0");
if (QPixmapCache::find(cacheKey, &pixmap)) {
return pixmap;
}
EventGraphics* gfx = this->eventGraphicsMap.value(gfxName, nullptr);
if (!gfx) {
// Invalid gfx constant. If this is a number, try to use that instead.
@ -3177,10 +3186,7 @@ QPixmap Project::getEventPixmap(const QString &gfxName, int frame, bool hFlip) {
}
// Set first palette color fully transparent.
img.setColor(0, qRgba(0, 0, 0, 0));
pixmap = QPixmap::fromImage(img);
QPixmapCache::insert(cacheKey, pixmap);
return pixmap;
return QPixmap::fromImage(img);
}
QPixmap Project::getEventPixmap(Event::Group group) {

View File

@ -22,6 +22,7 @@ const QMap<CallbackType, QString> callbackFunctions = {
{OnMainTabChanged, "onMainTabChanged"},
{OnMapViewTabChanged, "onMapViewTabChanged"},
{OnBorderVisibilityToggled, "onBorderVisibilityToggled"},
{OnEventSpriteLoading, "onEventSpriteLoading"},
};
Scripting *instance = nullptr;
@ -166,18 +167,20 @@ bool Scripting::tryErrorJS(QJSValue js) {
QJSValue Scripting::call(QSharedPointer<Script> script, QJSValue func, const QJSValueList &args) {
this->scriptExecutionStack.push(script);
QJSValue result = func.call(args);
tryErrorJS(result);
bool error = tryErrorJS(result);
this->scriptExecutionStack.pop();
return result;
return error ? QJSValue() : result;
}
void Scripting::invokeCallback(CallbackType type, const QJSValueList &args) {
QJSValue Scripting::invokeCallback(CallbackType type, const QJSValueList &args) {
const QString functionName = callbackFunctions[type];
for (const auto& script : this->scripts) {
QString functionName = callbackFunctions[type];
QJSValue callbackFunction = script->module().property(functionName);
if (tryErrorJS(callbackFunction)) return;
call(script, callbackFunction, args);
if (tryErrorJS(callbackFunction)) return QJSValue();
QJSValue result = call(script, callbackFunction, args);
if (!result.isNull() && !result.isUndefined()) return result;
}
return QJSValue();
}
void Scripting::invokeAction(int actionIndex) {
@ -368,6 +371,33 @@ void Scripting::cb_BorderVisibilityToggled(bool visible) {
instance->invokeCallback(OnBorderVisibilityToggled, args);
}
QImage Scripting::cb_EventSpriteLoading(const QString &gfxName, const QString &directionName) {
if (!instance) return QImage();
QJSValueList args {
gfxName,
directionName,
};
QJSValue settings = instance->invokeCallback(OnEventSpriteLoading, args);
if (!settings.hasProperty("path")) return QImage();
const QString path = settings.property("path").toString();
QImage image(Project::getExistingFilepath(path));
if (image.isNull()) return image;
int x = settings.hasProperty("x") ? settings.property("x").toInt() : 0;
int y = settings.hasProperty("y") ? settings.property("y").toInt() : 0;
int width = settings.hasProperty("width") ? settings.property("width").toInt() : image.width();
int height = settings.hasProperty("height") ? settings.property("height").toInt() : image.height();
double xScale = settings.hasProperty("xScale") ? settings.property("xScale").toNumber() : 1;
double yScale = settings.hasProperty("yScale") ? settings.property("yScale").toNumber() : 1;
QTransform transform = QTransform().scale(xScale, yScale);
image = image.copy(x, y, width, height).transformed(transform);
image.setColor(0, qRgba(0, 0, 0, 0));
return image;
}
QJSValue Scripting::fromBlock(Block block) {
QJSValue obj = instance->engine->newObject();
obj.setProperty("metatileId", block.metatileId());

View File

@ -62,5 +62,6 @@ void MapView::clearOverlay() {
delete innerIt.value();
}
this->overlayMap.clear();
this->hashToPriority.clear();
#endif
}