mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-06-17 20:13:41 +00:00
CAnimSet: Simplify allocation code
We can make use of std::unique_ptr to prevent any potential memory leaks from occurring and simplifying the destruction code.
This commit is contained in:
parent
4eb1027362
commit
eabc789910
@ -29,7 +29,7 @@ struct SAdditiveAnim
|
||||
struct SAnimation
|
||||
{
|
||||
TString Name;
|
||||
IMetaAnimation *pMetaAnim;
|
||||
std::unique_ptr<IMetaAnimation> pMetaAnim;
|
||||
};
|
||||
|
||||
struct STransition
|
||||
@ -37,13 +37,13 @@ struct STransition
|
||||
uint32 Unknown;
|
||||
uint32 AnimIdA;
|
||||
uint32 AnimIdB;
|
||||
IMetaTransition *pMetaTrans;
|
||||
std::unique_ptr<IMetaTransition> pMetaTrans;
|
||||
};
|
||||
|
||||
struct SHalfTransition
|
||||
{
|
||||
uint32 AnimID;
|
||||
IMetaTransition *pMetaTrans;
|
||||
std::unique_ptr<IMetaTransition> pMetaTrans;
|
||||
};
|
||||
|
||||
// Character structures
|
||||
@ -96,7 +96,7 @@ class CAnimSet : public CResource
|
||||
std::vector<CAnimPrimitive> mAnimPrimitives;
|
||||
std::vector<SAnimation> mAnimations;
|
||||
std::vector<STransition> mTransitions;
|
||||
IMetaTransition *mpDefaultTransition = nullptr;
|
||||
std::unique_ptr<IMetaTransition> mpDefaultTransition;
|
||||
std::vector<SAdditiveAnim> mAdditiveAnims;
|
||||
float mDefaultAdditiveFadeIn = 0.0f;
|
||||
float mDefaultAdditiveFadeOut = 0.0f;
|
||||
@ -110,17 +110,6 @@ public:
|
||||
|
||||
~CAnimSet()
|
||||
{
|
||||
for (auto& anim : mAnimations)
|
||||
delete anim.pMetaAnim;
|
||||
|
||||
for (auto& trans : mTransitions)
|
||||
delete trans.pMetaTrans;
|
||||
|
||||
for (auto& half : mHalfTransitions)
|
||||
delete half.pMetaTrans;
|
||||
|
||||
delete mpDefaultTransition;
|
||||
|
||||
// For MP2, anim events need to be cleaned up manually
|
||||
for ([[maybe_unused]] const auto& event : mAnimEvents)
|
||||
{
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "IMetaTransition.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class CSourceAnimData : public CResource
|
||||
{
|
||||
DECLARE_RESOURCE_TYPE(SourceAnimData)
|
||||
@ -13,35 +15,25 @@ class CSourceAnimData : public CResource
|
||||
{
|
||||
CAssetID AnimA;
|
||||
CAssetID AnimB;
|
||||
IMetaTransition *pTransition;
|
||||
std::unique_ptr<IMetaTransition> pTransition;
|
||||
};
|
||||
|
||||
struct SHalfTransition
|
||||
{
|
||||
CAssetID Anim;
|
||||
IMetaTransition *pTransition;
|
||||
std::unique_ptr<IMetaTransition> pTransition;
|
||||
};
|
||||
|
||||
std::vector<STransition> mTransitions;
|
||||
std::vector<SHalfTransition> mHalfTransitions;
|
||||
IMetaTransition *mpDefaultTransition;
|
||||
std::unique_ptr<IMetaTransition> mpDefaultTransition;
|
||||
|
||||
public:
|
||||
explicit CSourceAnimData(CResourceEntry *pEntry = nullptr)
|
||||
: CResource(pEntry)
|
||||
, mpDefaultTransition(nullptr)
|
||||
{}
|
||||
|
||||
~CSourceAnimData()
|
||||
{
|
||||
for (uint32 TransIdx = 0; TransIdx < mTransitions.size(); TransIdx++)
|
||||
delete mTransitions[TransIdx].pTransition;
|
||||
|
||||
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++)
|
||||
delete mHalfTransitions[HalfIdx].pTransition;
|
||||
|
||||
delete mpDefaultTransition;
|
||||
}
|
||||
~CSourceAnimData() = default;
|
||||
|
||||
std::unique_ptr<CDependencyTree> BuildDependencyTree() const override
|
||||
{
|
||||
@ -74,16 +66,16 @@ public:
|
||||
// Find all relevant primitives
|
||||
std::set<CAnimPrimitive> PrimSet;
|
||||
|
||||
if (UsedTransitions.find(mpDefaultTransition) == UsedTransitions.end())
|
||||
if (UsedTransitions.find(mpDefaultTransition.get()) == UsedTransitions.end())
|
||||
{
|
||||
mpDefaultTransition->GetUniquePrimitives(PrimSet);
|
||||
UsedTransitions.insert(mpDefaultTransition);
|
||||
UsedTransitions.insert(mpDefaultTransition.get());
|
||||
}
|
||||
|
||||
for (uint32 TransitionIdx = 0; TransitionIdx < mTransitions.size(); TransitionIdx++)
|
||||
{
|
||||
const STransition& rkTransition = mTransitions[TransitionIdx];
|
||||
IMetaTransition *pTransition = rkTransition.pTransition;
|
||||
IMetaTransition *pTransition = rkTransition.pTransition.get();
|
||||
|
||||
if ( pTree->HasDependency(rkTransition.AnimA) &&
|
||||
pTree->HasDependency(rkTransition.AnimB) &&
|
||||
@ -97,7 +89,7 @@ public:
|
||||
for (uint32 HalfIdx = 0; HalfIdx < mHalfTransitions.size(); HalfIdx++)
|
||||
{
|
||||
const SHalfTransition& rkHalfTrans = mHalfTransitions[HalfIdx];
|
||||
IMetaTransition *pTransition = rkHalfTrans.pTransition;
|
||||
IMetaTransition *pTransition = rkHalfTrans.pTransition.get();
|
||||
|
||||
if ( pTree->HasDependency(rkHalfTrans.Anim) &&
|
||||
UsedTransitions.find(pTransition) == UsedTransitions.end() )
|
||||
|
@ -3,27 +3,27 @@
|
||||
// ************ CMetaAnimFactory ************
|
||||
CMetaAnimFactory gMetaAnimFactory;
|
||||
|
||||
IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game)
|
||||
std::unique_ptr<IMetaAnimation> CMetaAnimFactory::LoadFromStream(IInputStream& rInput, EGame Game) const
|
||||
{
|
||||
EMetaAnimType Type = (EMetaAnimType) rInput.ReadLong();
|
||||
const auto Type = static_cast<EMetaAnimType>(rInput.ReadLong());
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case EMetaAnimType::Play:
|
||||
return new CMetaAnimPlay(rInput, Game);
|
||||
return std::make_unique<CMetaAnimPlay>(rInput, Game);
|
||||
|
||||
case EMetaAnimType::Blend:
|
||||
case EMetaAnimType::PhaseBlend:
|
||||
return new CMetaAnimBlend(Type, rInput, Game);
|
||||
return std::make_unique<CMetaAnimBlend>(Type, rInput, Game);
|
||||
|
||||
case EMetaAnimType::Random:
|
||||
return new CMetaAnimRandom(rInput, Game);
|
||||
return std::make_unique<CMetaAnimRandom>(rInput, Game);
|
||||
|
||||
case EMetaAnimType::Sequence:
|
||||
return new CMetaAnimSequence(rInput, Game);
|
||||
return std::make_unique<CMetaAnimSequence>(rInput, Game);
|
||||
|
||||
default:
|
||||
errorf("Unrecognized meta-animation type: %d", Type);
|
||||
errorf("Unrecognized meta-animation type: %d", static_cast<int>(Type));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -64,11 +64,7 @@ CMetaAnimBlend::CMetaAnimBlend(EMetaAnimType Type, IInputStream& rInput, EGame G
|
||||
mUnknownB = rInput.ReadBool();
|
||||
}
|
||||
|
||||
CMetaAnimBlend::~CMetaAnimBlend()
|
||||
{
|
||||
delete mpMetaAnimA;
|
||||
delete mpMetaAnimB;
|
||||
}
|
||||
CMetaAnimBlend::~CMetaAnimBlend() = default;
|
||||
|
||||
EMetaAnimType CMetaAnimBlend::Type() const
|
||||
{
|
||||
@ -84,7 +80,7 @@ void CMetaAnimBlend::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) con
|
||||
// ************ CMetaAnimRandom ************
|
||||
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
|
||||
{
|
||||
uint32 NumPairs = rInput.ReadLong();
|
||||
const uint32 NumPairs = rInput.ReadLong();
|
||||
mProbabilityPairs.reserve(NumPairs);
|
||||
|
||||
for (uint32 iAnim = 0; iAnim < NumPairs; iAnim++)
|
||||
@ -92,15 +88,11 @@ CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput, EGame Game)
|
||||
SAnimProbabilityPair Pair;
|
||||
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
|
||||
Pair.Probability = rInput.ReadLong();
|
||||
mProbabilityPairs.push_back(Pair);
|
||||
mProbabilityPairs.push_back(std::move(Pair));
|
||||
}
|
||||
}
|
||||
|
||||
CMetaAnimRandom::~CMetaAnimRandom()
|
||||
{
|
||||
for (uint32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++)
|
||||
delete mProbabilityPairs[iPair].pAnim;
|
||||
}
|
||||
CMetaAnimRandom::~CMetaAnimRandom() = default;
|
||||
|
||||
EMetaAnimType CMetaAnimRandom::Type() const
|
||||
{
|
||||
@ -109,28 +101,23 @@ EMetaAnimType CMetaAnimRandom::Type() const
|
||||
|
||||
void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||
{
|
||||
for (uint32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++)
|
||||
mProbabilityPairs[iPair].pAnim->GetUniquePrimitives(rPrimSet);
|
||||
for (auto& pair : mProbabilityPairs)
|
||||
pair.pAnim->GetUniquePrimitives(rPrimSet);
|
||||
}
|
||||
|
||||
// ************ CMetaAnimSequence ************
|
||||
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput, EGame Game)
|
||||
{
|
||||
uint32 NumAnims = rInput.ReadLong();
|
||||
const uint32 NumAnims = rInput.ReadLong();
|
||||
mAnimations.reserve(NumAnims);
|
||||
|
||||
for (uint32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||
{
|
||||
IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
|
||||
mAnimations.push_back(pAnim);
|
||||
mAnimations.push_back(gMetaAnimFactory.LoadFromStream(rInput, Game));
|
||||
}
|
||||
}
|
||||
|
||||
CMetaAnimSequence::~CMetaAnimSequence()
|
||||
{
|
||||
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||
delete mAnimations[iAnim];
|
||||
}
|
||||
CMetaAnimSequence::~CMetaAnimSequence() = default;
|
||||
|
||||
EMetaAnimType CMetaAnimSequence::Type() const
|
||||
{
|
||||
@ -139,6 +126,6 @@ EMetaAnimType CMetaAnimSequence::Type() const
|
||||
|
||||
void CMetaAnimSequence::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||
{
|
||||
for (uint32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||
mAnimations[iAnim]->GetUniquePrimitives(rPrimSet);
|
||||
for (auto& anim : mAnimations)
|
||||
anim->GetUniquePrimitives(rPrimSet);
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ enum class EMetaAnimType
|
||||
class CMetaAnimFactory
|
||||
{
|
||||
public:
|
||||
class IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game);
|
||||
std::unique_ptr<class IMetaAnimation> LoadFromStream(IInputStream& rInput, EGame Game) const;
|
||||
};
|
||||
extern CMetaAnimFactory gMetaAnimFactory;
|
||||
|
||||
@ -65,7 +65,7 @@ public:
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
|
||||
|
||||
// Static
|
||||
static IMetaAnimation* LoadFromStream(IInputStream& rInput, EGame Game);
|
||||
static std::unique_ptr<IMetaAnimation> LoadFromStream(IInputStream& rInput, EGame Game);
|
||||
};
|
||||
|
||||
// CMetaAnimPlay - plays an animation
|
||||
@ -93,8 +93,8 @@ class CMetaAnimBlend : public IMetaAnimation
|
||||
{
|
||||
protected:
|
||||
EMetaAnimType mType;
|
||||
IMetaAnimation *mpMetaAnimA;
|
||||
IMetaAnimation *mpMetaAnimB;
|
||||
std::unique_ptr<IMetaAnimation> mpMetaAnimA;
|
||||
std::unique_ptr<IMetaAnimation> mpMetaAnimB;
|
||||
float mUnknownA;
|
||||
bool mUnknownB;
|
||||
|
||||
@ -105,8 +105,8 @@ public:
|
||||
void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const override;
|
||||
|
||||
// Accessors
|
||||
IMetaAnimation* BlendAnimationA() const { return mpMetaAnimA; }
|
||||
IMetaAnimation* BlendAnimationB() const { return mpMetaAnimB; }
|
||||
IMetaAnimation* BlendAnimationA() const { return mpMetaAnimA.get(); }
|
||||
IMetaAnimation* BlendAnimationB() const { return mpMetaAnimB.get(); }
|
||||
float UnknownA() const { return mUnknownA; }
|
||||
bool UnknownB() const { return mUnknownB; }
|
||||
};
|
||||
@ -114,7 +114,7 @@ public:
|
||||
// SAnimProbabilityPair - structure used by CMetaAnimationRandom to associate an animation with a probability value
|
||||
struct SAnimProbabilityPair
|
||||
{
|
||||
IMetaAnimation *pAnim;
|
||||
std::unique_ptr<IMetaAnimation> pAnim;
|
||||
uint32 Probability;
|
||||
};
|
||||
|
||||
@ -135,7 +135,7 @@ public:
|
||||
class CMetaAnimSequence : public IMetaAnimation
|
||||
{
|
||||
protected:
|
||||
std::vector<IMetaAnimation*> mAnimations;
|
||||
std::vector<std::unique_ptr<IMetaAnimation>> mAnimations;
|
||||
|
||||
public:
|
||||
CMetaAnimSequence(IInputStream& rInput, EGame Game);
|
||||
|
@ -4,41 +4,38 @@
|
||||
// ************ CMetaTransFactory ************
|
||||
CMetaTransFactory gMetaTransFactory;
|
||||
|
||||
IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game)
|
||||
std::unique_ptr<IMetaTransition> CMetaTransFactory::LoadFromStream(IInputStream& rInput, EGame Game) const
|
||||
{
|
||||
EMetaTransType Type = (EMetaTransType) rInput.ReadLong();
|
||||
const auto Type = static_cast<EMetaTransType>(rInput.ReadLong());
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case EMetaTransType::MetaAnim:
|
||||
return new CMetaTransMetaAnim(rInput, Game);
|
||||
return std::make_unique<CMetaTransMetaAnim>(rInput, Game);
|
||||
|
||||
case EMetaTransType::Trans:
|
||||
case EMetaTransType::PhaseTrans:
|
||||
return new CMetaTransTrans(Type, rInput, Game);
|
||||
return std::make_unique<CMetaTransTrans>(Type, rInput, Game);
|
||||
|
||||
case EMetaTransType::Snap:
|
||||
return new CMetaTransSnap(rInput, Game);
|
||||
return std::make_unique<CMetaTransSnap>(rInput, Game);
|
||||
|
||||
case EMetaTransType::Type4:
|
||||
return new CMetaTransType4(rInput, Game);
|
||||
return std::make_unique<CMetaTransType4>(rInput, Game);
|
||||
|
||||
default:
|
||||
errorf("Unrecognized meta-transition type: %d", Type);
|
||||
errorf("Unrecognized meta-transition type: %d", static_cast<int>(Type));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ CMetaTransMetaAnim ************
|
||||
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput, EGame Game)
|
||||
: mpAnim{gMetaAnimFactory.LoadFromStream(rInput, Game)}
|
||||
{
|
||||
mpAnim = gMetaAnimFactory.LoadFromStream(rInput, Game);
|
||||
}
|
||||
|
||||
CMetaTransMetaAnim::~CMetaTransMetaAnim()
|
||||
{
|
||||
delete mpAnim;
|
||||
}
|
||||
CMetaTransMetaAnim::~CMetaTransMetaAnim() = default;
|
||||
|
||||
EMetaTransType CMetaTransMetaAnim::Type() const
|
||||
{
|
||||
|
@ -2,9 +2,13 @@
|
||||
#define IMETATRANSITION_H
|
||||
|
||||
#include "IMetaAnimation.h"
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
class IInputStream;
|
||||
class IMetaAnimation;
|
||||
class IMetaTransition;
|
||||
enum class EGame;
|
||||
|
||||
enum class EMetaTransType
|
||||
{
|
||||
@ -19,7 +23,7 @@ enum class EMetaTransType
|
||||
class CMetaTransFactory
|
||||
{
|
||||
public:
|
||||
class IMetaTransition* LoadFromStream(IInputStream& rInput, EGame Game);
|
||||
std::unique_ptr<IMetaTransition> LoadFromStream(IInputStream& rInput, EGame Game) const;
|
||||
};
|
||||
extern CMetaTransFactory gMetaTransFactory;
|
||||
|
||||
@ -36,7 +40,7 @@ public:
|
||||
// CMetaTransMetaAnim
|
||||
class CMetaTransMetaAnim : public IMetaTransition
|
||||
{
|
||||
IMetaAnimation *mpAnim;
|
||||
std::unique_ptr<IMetaAnimation> mpAnim;
|
||||
|
||||
public:
|
||||
CMetaTransMetaAnim(IInputStream& rInput, EGame Game);
|
||||
|
@ -52,7 +52,7 @@ void CAnimSetLoader::LoadCorruptionCHAR(IInputStream& rCHAR)
|
||||
SAnimation Anim;
|
||||
Anim.Name = rCHAR.ReadString();
|
||||
Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rCHAR, mGame);
|
||||
pSet->mAnimations.push_back(Anim);
|
||||
pSet->mAnimations.push_back(std::move(Anim));
|
||||
}
|
||||
|
||||
// Animation Bounds
|
||||
@ -141,8 +141,8 @@ void CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
|
||||
// small hack - create a meta-anim for it so we can generate asset names for the ANIM files correctly
|
||||
SAnimation Anim;
|
||||
Anim.Name = AnimName;
|
||||
Anim.pMetaAnim = new CMetaAnimPlay( CAnimPrimitive(AnimID, AnimIdx, AnimName), 0.f, 0 );
|
||||
pSet->mAnimations.push_back(Anim);
|
||||
Anim.pMetaAnim = std::make_unique<CMetaAnimPlay>(CAnimPrimitive(AnimID, AnimIdx, AnimName), 0.f, 0);
|
||||
pSet->mAnimations.push_back(std::move(Anim));
|
||||
}
|
||||
|
||||
// The only other thing we care about right now is the dependency list. If this file doesn't have a dependency list, exit out.
|
||||
@ -322,7 +322,7 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
|
||||
SAnimation Anim;
|
||||
Anim.Name = rANCS.ReadString();
|
||||
Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rANCS, mGame);
|
||||
pSet->mAnimations.push_back(Anim);
|
||||
pSet->mAnimations.push_back(std::move(Anim));
|
||||
}
|
||||
|
||||
// Transitions
|
||||
@ -336,7 +336,7 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
|
||||
Trans.AnimIdA = rANCS.ReadLong();
|
||||
Trans.AnimIdB = rANCS.ReadLong();
|
||||
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS, mGame);
|
||||
pSet->mTransitions.push_back(Trans);
|
||||
pSet->mTransitions.push_back(std::move(Trans));
|
||||
}
|
||||
|
||||
pSet->mpDefaultTransition = gMetaTransFactory.LoadFromStream(rANCS, mGame);
|
||||
@ -351,7 +351,7 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
|
||||
Anim.AnimID = rANCS.ReadLong();
|
||||
Anim.FadeInTime = rANCS.ReadFloat();
|
||||
Anim.FadeOutTime = rANCS.ReadFloat();
|
||||
pSet->mAdditiveAnims.push_back(Anim);
|
||||
pSet->mAdditiveAnims.push_back(std::move(Anim));
|
||||
}
|
||||
|
||||
pSet->mDefaultAdditiveFadeIn = rANCS.ReadFloat();
|
||||
@ -368,7 +368,7 @@ void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
|
||||
SHalfTransition Trans;
|
||||
Trans.AnimID = rANCS.ReadLong();
|
||||
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS, mGame);
|
||||
pSet->mHalfTransitions.push_back(Trans);
|
||||
pSet->mHalfTransitions.push_back(std::move(Trans));
|
||||
}
|
||||
}
|
||||
|
||||
@ -673,7 +673,7 @@ std::unique_ptr<CSourceAnimData> CAnimSetLoader::LoadSAND(IInputStream& rSAND, C
|
||||
Transition.AnimA = CAssetID(rSAND, EIDLength::k64Bit);
|
||||
Transition.AnimB = CAssetID(rSAND, EIDLength::k64Bit);
|
||||
Transition.pTransition = gMetaTransFactory.LoadFromStream(rSAND, pEntry->Game());
|
||||
pData->mTransitions.push_back(Transition);
|
||||
pData->mTransitions.push_back(std::move(Transition));
|
||||
}
|
||||
|
||||
// Half Transitions
|
||||
@ -687,7 +687,7 @@ std::unique_ptr<CSourceAnimData> CAnimSetLoader::LoadSAND(IInputStream& rSAND, C
|
||||
CSourceAnimData::SHalfTransition HalfTrans;
|
||||
HalfTrans.Anim = CAssetID(rSAND, EIDLength::k64Bit);
|
||||
HalfTrans.pTransition = gMetaTransFactory.LoadFromStream(rSAND, pEntry->Game());
|
||||
pData->mHalfTransitions.push_back(HalfTrans);
|
||||
pData->mHalfTransitions.push_back(std::move(HalfTrans));
|
||||
}
|
||||
|
||||
// Default Transition
|
||||
|
Loading…
x
Reference in New Issue
Block a user