A_ChangeModel now has generatorIndex

- To really take advantage of this function, I thought it would be useful to be able to add additional models if the user wants to. Let's say you got a player model at index 0. Your gun model has the same frames, but you don't want to duplicate the modeldef data. With generator index, you don't need to duplicate the data, just tell generator index to clone frame data from index 0.
- Implemented a little something to check if a negative skin or model index were passed, and prevent modders from pulling that off.
This commit is contained in:
Shiny Metagross 2022-07-08 22:47:12 -07:00 committed by Christoph Oelckers
parent fa6dfdf64c
commit 9ab6557822
5 changed files with 53 additions and 11 deletions

View File

@ -682,6 +682,7 @@ public:
TArray<int> modelIDs;
TArray<FTextureID> skinIDs;
TArray<FTextureID> surfaceSkinIDs;
TArray<int> modelFrameGenerators;
DActorModelData() = default;
virtual void Serialize(FSerializer& arc) override;

View File

@ -5038,17 +5038,28 @@ enum ChangeModelFlags
DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_NAME(modeldef)
PARAM_INT(modelindex)
PARAM_STRING_VAL(modelpath)
PARAM_NAME(model)
PARAM_INT(skinindex)
PARAM_STRING_VAL(skinpath)
PARAM_NAME(skin)
PARAM_INT(flags)
PARAM_NAME(modeldef);
PARAM_INT(modelindex);
PARAM_STRING_VAL(modelpath);
PARAM_NAME(model);
PARAM_INT(skinindex);
PARAM_STRING_VAL(skinpath);
PARAM_NAME(skin);
PARAM_INT(flags);
PARAM_INT(generatorindex);
if (self == nullptr)
ACTION_RETURN_BOOL(false);
else if (modelindex < 0)
{
Printf("Attempt to pass invalid model index %d in %s, index must be non-negative.", modelindex, self->GetCharacterName());
ACTION_RETURN_BOOL(false);
}
else if (skinindex < 0)
{
Printf("Attempt to pass invalid skin index %d in %s, index must be non-negative.", skinindex, self->GetCharacterName());
ACTION_RETURN_BOOL(false);
}
AActor* mobj = (ACTION_CALL_FROM_PSPRITE() && (flags & CMDL_WEAPONTOPLAYER)) || ACTION_CALL_FROM_INVENTORY() ? self : stateowner;
@ -5062,6 +5073,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
ptr->modelIDs = *new TArray<int>();
ptr->skinIDs = *new TArray<FTextureID>();
ptr->surfaceSkinIDs = *new TArray<FTextureID>();
ptr->modelFrameGenerators = *new TArray<int>();
ptr->modelDef = NAME_None;
mobj->modelData = ptr;
mobj->hasmodel = 1;
@ -5071,6 +5083,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
int maxModels = mobj->modelData->modelIDs.Size();
int maxSkins = mobj->modelData->skinIDs.Size();
int maxSurfaceSkins = mobj->modelData->surfaceSkinIDs.Size();
int maxGenerators = mobj->modelData->modelFrameGenerators.Size();
int skinPosition = skinindex + modelindex * MD3_MAX_SURFACES;
@ -5079,6 +5092,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
//[SM] - Let's clear out any potential entries at the specified indices
mobj->modelData->modelDef = modeldef;
if(maxModels > modelindex) mobj->modelData->modelIDs.Pop(mobj->modelData->modelIDs[modelindex]);
if(maxGenerators > modelindex) mobj->modelData->modelFrameGenerators.Pop(mobj->modelData->modelFrameGenerators[modelindex]);
if (flags & CMDL_USESURFACESKIN)
{
if (maxSurfaceSkins > skinPosition)
@ -5092,12 +5107,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
//[SM] - We need to fill up any holes this new index will make so that it doesn't leave behind any undefined behavior
while ((int)mobj->modelData->modelIDs.Size() < modelindex) mobj->modelData->modelIDs.Push(-1);
while ((int)mobj->modelData->modelFrameGenerators.Size() < modelindex) mobj->modelData->modelFrameGenerators.Push(-1);
if (flags & CMDL_USESURFACESKIN)
while ((int)mobj->modelData->surfaceSkinIDs.Size() < skinPosition) mobj->modelData->surfaceSkinIDs.Push(FNullTextureID());
else
while ((int)mobj->modelData->skinIDs.Size() < skinindex) mobj->modelData->skinIDs.Push(FNullTextureID());
mobj->modelData->modelIDs.Insert(modelindex, queryModel);
mobj->modelData->modelFrameGenerators.Insert(modelindex, generatorindex);
if (flags & CMDL_USESURFACESKIN)
mobj->modelData->surfaceSkinIDs.Insert(skinPosition, skin != NAME_None ? LoadSkin(skinpath.GetChars(), skin.GetChars()) : FNullTextureID());
else
@ -5118,15 +5135,18 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeModel)
//[SM] - if an indice of modelIDs or skinIDs comes up blank and it's the last one, just delete it. For using very large amounts of indices, common sense says to just not run this repeatedly.
while (mobj->modelData->modelIDs.Size() > 0 && mobj->modelData->modelIDs.Last() == -1)
mobj->modelData->modelIDs.Pop(mobj->modelData->modelIDs.Last());
while (mobj->modelData->modelFrameGenerators.Size() > 0 && mobj->modelData->modelFrameGenerators.Last() == -1)
mobj->modelData->modelFrameGenerators.Pop(mobj->modelData->modelFrameGenerators.Last());
while (mobj->modelData->skinIDs.Size() > 0 && mobj->modelData->skinIDs.Last() == FNullTextureID())
mobj->modelData->skinIDs.Pop(mobj->modelData->skinIDs.Last());
while (mobj->modelData->surfaceSkinIDs.Size() > 0 && mobj->modelData->surfaceSkinIDs.Last() == FNullTextureID())
mobj->modelData->surfaceSkinIDs.Pop(mobj->modelData->surfaceSkinIDs.Last());
if (mobj->modelData->modelIDs.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->surfaceSkinIDs.Size() == 0 && modeldef == NAME_None)
if (mobj->modelData->modelIDs.Size() == 0 && mobj->modelData->modelFrameGenerators.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->surfaceSkinIDs.Size() == 0 && modeldef == NAME_None)
{
mobj->hasmodel = mobj->modelData->hasModel;
mobj->modelData->modelIDs.Reset();
mobj->modelData->modelFrameGenerators.Reset();
mobj->modelData->skinIDs.Reset();
mobj->modelData->surfaceSkinIDs.Reset();
mobj->modelData->Destroy();

View File

@ -1369,6 +1369,7 @@ void DActorModelData::Serialize(FSerializer& arc)
("modelIDs", modelIDs)
("skinIDs", skinIDs)
("surfaceSkinIDs", surfaceSkinIDs)
("modelFrameGenerators", modelFrameGenerators)
("hasModel", hasModel);
}

View File

@ -278,15 +278,35 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
}
}
//[SM] - if we added any models for the frame to also render, then we also need to update modelsAmount for this smf
if (actor->modelData != nullptr)
{
if (tempsmf->modelsAmount < actor->modelData->modelIDs.Size())
{
tempsmf->modelsAmount = actor->modelData->modelIDs.Size();
while (tempsmf->modelframes.Size() < actor->modelData->modelIDs.Size()) tempsmf->modelframes.Push(-1);
while (smfNext->modelframes.Size() < actor->modelData->modelIDs.Size()) smfNext->modelframes.Push(-1);
}
}
for (int i = 0; i < tempsmf->modelsAmount; i++)
{
if (actor->modelData != nullptr)
{
if (i < (int)actor->modelData->modelIDs.Size())
{
if(actor->modelData->modelIDs[i] != -1)
if (actor->modelData->modelIDs[i] != -1)
tempsmf->modelIDs[i] = actor->modelData->modelIDs[i];
}
if (i < (int)actor->modelData->modelFrameGenerators.Size())
{
//[SM] - We will use this little snippet to allow a modder to specify a model index to clone. It's also pointless to clone something that clones something else in this case. And causes me headaches.
if (actor->modelData->modelFrameGenerators[i] >= 0 && smf->modelframes[i] != -1)
{
tempsmf->modelframes[i] = tempsmf->modelframes[actor->modelData->modelFrameGenerators[i]];
if (smfNext) smfNext->modelframes[i] = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]];
}
}
if (i < (int)actor->modelData->skinIDs.Size())
{
if (actor->modelData->skinIDs[i].isValid())

View File

@ -1132,7 +1132,7 @@ class Actor : Thinker native
native void A_SetBlend(color color1, double alpha, int tics, color color2 = 0, double alpha2 = 0.);
deprecated("2.3", "Use 'b<FlagName> = [true/false]' instead") native void A_ChangeFlag(string flagname, bool value);
native void A_ChangeCountFlags(int kill = FLAG_NO_CHANGE, int item = FLAG_NO_CHANGE, int secret = FLAG_NO_CHANGE);
action native void A_ChangeModel(name modeldef, int modelindex = 0, string modelpath = "", name model = "", int skinindex = 0, string skinpath = "", name skin = "", int flags = 0);
action native void A_ChangeModel(name modeldef, int modelindex = 0, string modelpath = "", name model = "", int skinindex = 0, string skinpath = "", name skin = "", int flags = 0, int generatorindex = -1);
void A_SetFriendly (bool set)
{