1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-12-09 04:34:32 +00:00

add loop + vfxId params to world.vfx.spawn and add world.vfx.remove

This commit is contained in:
Sebastian Fieber 2025-06-20 23:05:06 +02:00 committed by Alexei Kotov
parent 3ef9237f51
commit e8c917d35e
10 changed files with 94 additions and 15 deletions

View file

@ -529,9 +529,12 @@ namespace MWBase
virtual void spawnRandomCreature(const ESM::RefId& creatureList) = 0;
virtual void spawnEffect(VFS::Path::NormalizedView model, const std::string& textureOverride,
const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true, bool useAmbientLight = true)
const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true, bool useAmbientLight = true,
std::string_view effectId = {}, bool loop = false)
= 0;
virtual void removeEffect(std::string_view effectId) = 0;
/// @see MWWorld::WeatherManager::isInStorm
virtual bool isInStorm() const = 0;

View file

@ -291,6 +291,11 @@ namespace MWLua
{
sol::table api(context.mLua->unsafeState(), sol::create);
api["remove"] = [context](std::string vfxId) {
context.mLuaManager->addAction(
[vfxId = vfxId] { MWBase::Environment::get().getWorld()->removeEffect(vfxId); }, "openmw.vfx.remove");
};
api["spawn"]
= [context](std::string_view model, const osg::Vec3f& worldPos, sol::optional<sol::table> options) {
if (options)
@ -298,12 +303,14 @@ namespace MWLua
bool magicVfx = options->get_or("mwMagicVfx", true);
std::string texture = options->get_or<std::string>("particleTextureOverride", "");
float scale = options->get_or("scale", 1.f);
std::string vfxId = options->get_or<std::string>("vfxId", "");
bool loop = options->get_or("loop", false);
bool useAmbientLight = options->get_or("useAmbientLight", true);
context.mLuaManager->addAction(
[model = VFS::Path::Normalized(model), texture = std::move(texture), worldPos, scale,
magicVfx, useAmbientLight]() {
magicVfx, useAmbientLight, vfxId, loop]() {
MWBase::Environment::get().getWorld()->spawnEffect(
model, texture, worldPos, scale, magicVfx, useAmbientLight);
model, texture, worldPos, scale, magicVfx, useAmbientLight, vfxId, loop);
},
"openmw.vfx.spawn");
}

View file

@ -28,7 +28,8 @@ namespace MWRender
}
void EffectManager::addEffect(VFS::Path::NormalizedView model, std::string_view textureOverride,
const osg::Vec3f& worldPosition, float scale, bool isMagicVFX, bool useAmbientLight)
const osg::Vec3f& worldPosition, float scale, bool isMagicVFX, bool useAmbientLight, std::string_view effectId,
bool loop)
{
osg::ref_ptr<osg::Node> node = mResourceSystem->getSceneManager()->getInstance(model);
@ -36,6 +37,8 @@ namespace MWRender
Effect effect;
effect.mAnimTime = std::make_shared<EffectAnimationTime>();
effect.mLoop = loop;
effect.mEffectId = effectId;
SceneUtil::FindMaxControllerLengthVisitor findMaxLengthVisitor;
node->accept(findMaxLengthVisitor);
@ -67,17 +70,47 @@ namespace MWRender
mResourceSystem->getSceneManager()->setUpNormalsRTForStateSet(node->getOrCreateStateSet(), false);
std::lock_guard<std::mutex> lock(mEffectsMutex);
mEffects.push_back(std::move(effect));
}
void EffectManager::removeEffect(std::string_view effectId)
{
std::lock_guard<std::mutex> lock(mEffectsMutex);
mEffects.erase(std::remove_if(mEffects.begin(), mEffects.end(),
[effectId, this](Effect& effect) {
if (effectId == effect.mEffectId)
{
mParentNode->removeChild(effect.mTransform);
return true;
}
return false;
}),
mEffects.end());
}
void EffectManager::update(float dt)
{
std::lock_guard<std::mutex> lock(mEffectsMutex);
mEffects.erase(std::remove_if(mEffects.begin(), mEffects.end(),
[dt, this](Effect& effect) {
bool remove = false;
effect.mAnimTime->addTime(dt);
const auto remove = effect.mAnimTime->getTime() >= effect.mMaxControllerLength;
if (remove)
mParentNode->removeChild(effect.mTransform);
if (effect.mAnimTime->getTime() >= effect.mMaxControllerLength)
{
if (effect.mLoop)
{
float remainder = effect.mAnimTime->getTime() - effect.mMaxControllerLength;
effect.mAnimTime->resetTime(remainder);
}
else
{
mParentNode->removeChild(effect.mTransform);
remove = true;
}
}
return remove;
}),
mEffects.end());
@ -85,6 +118,7 @@ namespace MWRender
void EffectManager::clear()
{
std::lock_guard<std::mutex> lock(mEffectsMutex);
for (const auto& effect : mEffects)
{
mParentNode->removeChild(effect.mTransform);

View file

@ -35,7 +35,10 @@ namespace MWRender
/// Add an effect. When it's finished playing, it will be removed automatically.
void addEffect(VFS::Path::NormalizedView model, std::string_view textureOverride,
const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true, bool useAmbientLight = true);
const osg::Vec3f& worldPosition, float scale, bool isMagicVFX = true, bool useAmbientLight = true,
std::string_view effectId = {}, bool loop = false);
void removeEffect(std::string_view effectId);
void update(float dt);
@ -45,11 +48,14 @@ namespace MWRender
private:
struct Effect
{
std::string mEffectId;
float mMaxControllerLength;
bool mLoop;
std::shared_ptr<EffectAnimationTime> mAnimTime;
osg::ref_ptr<osg::PositionAttitudeTransform> mTransform;
};
std::mutex mEffectsMutex;
std::vector<Effect> mEffects;
osg::ref_ptr<osg::Group> mParentNode;

View file

@ -1252,9 +1252,15 @@ namespace MWRender
}
void RenderingManager::spawnEffect(VFS::Path::NormalizedView model, std::string_view texture,
const osg::Vec3f& worldPosition, float scale, bool isMagicVFX, bool useAmbientLight)
const osg::Vec3f& worldPosition, float scale, bool isMagicVFX, bool useAmbientLight, std::string_view effectId,
bool loop)
{
mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX, useAmbientLight);
mEffectManager->addEffect(model, texture, worldPosition, scale, isMagicVFX, useAmbientLight, effectId, loop);
}
void RenderingManager::removeEffect(std::string_view effectId)
{
mEffectManager->removeEffect(effectId);
}
void RenderingManager::notifyWorldSpaceChanged()

View file

@ -196,7 +196,10 @@ namespace MWRender
SkyManager* getSkyManager();
void spawnEffect(VFS::Path::NormalizedView model, std::string_view texture, const osg::Vec3f& worldPosition,
float scale = 1.f, bool isMagicVFX = true, bool useAmbientLight = true);
float scale = 1.f, bool isMagicVFX = true, bool useAmbientLight = true, std::string_view effectId = {},
bool loop = false);
void removeEffect(std::string_view effectId);
/// Clear all savegame-specific data
void clear();

View file

@ -3713,9 +3713,15 @@ namespace MWWorld
}
void World::spawnEffect(VFS::Path::NormalizedView model, const std::string& textureOverride,
const osg::Vec3f& worldPos, float scale, bool isMagicVFX, bool useAmbientLight)
const osg::Vec3f& worldPos, float scale, bool isMagicVFX, bool useAmbientLight, std::string_view effectId,
bool loop)
{
mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX, useAmbientLight);
mRendering->spawnEffect(model, textureOverride, worldPos, scale, isMagicVFX, useAmbientLight, effectId, loop);
}
void World::removeEffect(std::string_view effectId)
{
mRendering->removeEffect(effectId);
}
struct ResetActorsVisitor

View file

@ -611,8 +611,10 @@ namespace MWWorld
void spawnRandomCreature(const ESM::RefId& creatureList) override;
void spawnEffect(VFS::Path::NormalizedView model, const std::string& textureOverride,
const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true,
bool useAmbientLight = true) override;
const osg::Vec3f& worldPos, float scale = 1.f, bool isMagicVFX = true, bool useAmbientLight = true,
std::string_view effectId = {}, bool loop = false) override;
void removeEffect(std::string_view effectId) override;
/// @see MWWorld::WeatherManager::isInStorm
bool isInStorm() const override;

View file

@ -7,5 +7,6 @@ return {
SetGameTimeScale = function(scale) world.setGameTimeScale(scale) end,
SetSimulationTimeScale = function(scale) world.setSimulationTimeScale(scale) end,
SpawnVfx = function(data) world.vfx.spawn(data.model, data.position, data.options) end,
RemoveVfx = function(vfxId) world.vfx.remove(vfxId) end,
},
}

View file

@ -197,6 +197,8 @@
-- * `particleTextureOverride` - Name of a particle texture that should override this effect's default texture. (default: "")
-- * `scale` - A number that scales the size of the vfx (Default: 1)
-- * `useAmbientLight` - boolean, vfx get a white ambient light attached in Morrowind. If false don't attach this. (default: true)
-- * `loop` - boolean, if true the effect will loop until removed (default: false).
-- * `vfxId` - a string ID that can be used to remove the effect later, using #remove. (Default: "").
--
-- @usage -- Spawn a sanctuary effect near the player
-- local effect = core.magic.effects.records[core.magic.EFFECT_TYPE.Sanctuary]
@ -205,6 +207,15 @@
-- core.sendGlobalEvent('SpawnVfx', {model = model, position = pos})
--
---
-- Remove all VFX with the given vfxId. Best invoked through the RemoveVfx global event
-- @function [parent=#VFX] remove
-- @param #string vfxId the vfxId of the VFX to remove.
--
-- @usage -- Remove all VFX with vfxId "myvfx"
-- core.sendGlobalEvent('RemoveVfx', "myvfx")
--
---
-- Advance the world time by a certain number of hours. This advances time, weather, and AI, but does not perform other functions associated with the passage of time, e.g., regeneration.
-- @function [parent=#world] advanceTime