Merge remote-tracking branch 'gzdoom/staging'

This commit is contained in:
Magnus Norddahl 2024-01-02 17:10:47 +01:00
commit 73ada7f84b
214 changed files with 23523 additions and 1206 deletions

View file

@ -926,6 +926,11 @@ static DObject *BuiltinNewDoom(PClass *cls, int outerside, int backwardscompatib
ThrowAbortException(X_OTHER, "Cannot create actors with 'new'");
return nullptr;
}
if (cls->IsDescendantOf(NAME_VisualThinker)) // Same for VisualThinkers.
{
ThrowAbortException(X_OTHER, "Cannot create VisualThinker or inheriting classes with 'new'. Use 'VisualThinker.Spawn' instead.");
return nullptr;
}
if ((vm_warnthinkercreation || !backwardscompatible) && cls->IsDescendantOf(NAME_Thinker))
{
// This must output a diagnostic warning
@ -967,3 +972,349 @@ void SetDoomCompileEnvironment()
compileEnvironment.CheckCustomGlobalFunctions = ResolveGlobalCustomFunction;
compileEnvironment.CustomBuiltinNew = "BuiltinNewDoom";
}
//==========================================================================
//
// FxCastForEachLoop
//
//==========================================================================
class FxCastForEachLoop : public FxTypedForEachLoop
{
public:
using FxTypedForEachLoop::FxTypedForEachLoop;
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
FxExpression *FxCastForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(Expr, ctx);
if(varName == NAME_None)
{
ScriptPosition.Message(MSG_ERROR, "missing var for foreach(Type var : it )");
delete this;
return nullptr;
}
PType * varType = nullptr;
PClass * itType = ((PObjectPointer*)Expr->ValueType)->PointedClass();
FName fieldName = NAME_None;
if(itType->TypeName == NAME_ActorIterator)
{
fieldName = "Actor";
}
else if(itType->TypeName == NAME_ThinkerIterator)
{
fieldName = "Thinker";
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - 'it' must be an actor or thinker iterator, but is a %s",Expr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
if(className != NAME_None)
{
fieldName = className;
}
PClass * varTypeClass = PClass::FindClass(fieldName);
varType = varTypeClass->VMType;
if(!varType)
{
ScriptPosition.Message(MSG_ERROR, "foreach(Type var : it ) - could not find class '%s'",className.GetChars());
delete this;
return nullptr;
}
varType = NewPointer(varType, false);
/*
{
CastType var;
ActorIterator|ThinkerIterator @it = expr;
while(var = CastType(@it.Next()))
body
}
*/
auto block = new FxCompoundStatement(ScriptPosition);
block->Add(new FxLocalVariableDeclaration(varType, varName, nullptr, 0, ScriptPosition));
block->Add(new FxLocalVariableDeclaration(Expr->ValueType, "@it", Expr, 0, ScriptPosition));
auto inner_block = new FxCompoundStatement(ScriptPosition);
FxExpression * nextCallCast = new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition);
if(className != NAME_None)
{
nextCallCast = new FxDynamicCast(varTypeClass, nextCallCast);
}
block->Add(new FxWhileLoop(new FxAssign(new FxIdentifier(varName, ScriptPosition), nextCallCast), Code, ScriptPosition));
Expr = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
//==========================================================================
//
// FxBlockIteratorForEachLoop
//
//==========================================================================
class FxBlockIteratorForEachLoop : public FxThreeArgForEachLoop
{
public:
using FxThreeArgForEachLoop::FxThreeArgForEachLoop;
FxExpression *Resolve(FCompileContext&);
//ExpEmit Emit(VMFunctionBuilder *build); This node is transformed, so it won't ever be emitted itself
};
FxExpression *FxBlockIteratorForEachLoop::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(BlockIteratorExpr, ctx);
if(!(BlockIteratorExpr->ValueType->isObjectPointer()))
{
ScriptPosition.Message(MSG_ERROR, "foreach( v, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
else if(varVarName == NAME_None)
{
ScriptPosition.Message(MSG_ERROR, "missing var for foreach( v, p, f : b )");
delete this;
return nullptr;
}
PType * varType = nullptr;
PClass * itType = ((PObjectPointer*)BlockIteratorExpr->ValueType)->PointedClass();
FName fieldName = NAME_None;
if(itType->TypeName == NAME_BlockThingsIterator)
{
fieldName = "Thing";
}
else if(itType->TypeName == NAME_BlockLinesIterator)
{
fieldName = "CurLine";
}
else
{
ScriptPosition.Message(MSG_ERROR, "foreach( t, p, f : b ) - 'b' must be a block things or block lines iterator, but is a %s",BlockIteratorExpr->ValueType->DescriptiveName());
delete this;
return nullptr;
}
auto var = itType->FindSymbol(fieldName, false);
if(var && var->IsKindOf(RUNTIME_CLASS(PField)))
{
varType = static_cast<PField*>(var)->Type;
}
/*
{
Line|Actor var;
Vector3 pos;
int flags;
BlockLinesIterator|BlockThingsIterator @it = expr;
while(@it.Next())
{
var = @it.CurLine|@it.Thing;
pos = @it.position;
flags = @it.portalflags;
body
}
}
*/
auto block = new FxCompoundStatement(ScriptPosition);
block->Add(new FxLocalVariableDeclaration(varType, varVarName, nullptr, 0, ScriptPosition));
if(posVarName != NAME_None)
{
block->Add(new FxLocalVariableDeclaration(TypeVector3, posVarName, nullptr, 0, ScriptPosition));
}
if(flagsVarName != NAME_None)
{
block->Add(new FxLocalVariableDeclaration(TypeSInt32, flagsVarName, nullptr, 0, ScriptPosition));
}
block->Add(new FxLocalVariableDeclaration(BlockIteratorExpr->ValueType, "@it", BlockIteratorExpr, 0, ScriptPosition));
auto inner_block = new FxCompoundStatement(ScriptPosition);
inner_block->Add(new FxAssign(new FxIdentifier(varVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), fieldName, ScriptPosition), true));
if(posVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(posVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "position", ScriptPosition), true));
}
if(flagsVarName != NAME_None)
{
inner_block->Add(new FxAssign(new FxIdentifier(flagsVarName, ScriptPosition), new FxMemberIdentifier(new FxIdentifier("@it", ScriptPosition), "portalflags", ScriptPosition), true));
}
inner_block->Add(Code);
block->Add(new FxWhileLoop(new FxMemberFunctionCall(new FxIdentifier("@it", ScriptPosition), "Next", {}, ScriptPosition), inner_block, ScriptPosition));
BlockIteratorExpr = Code = nullptr;
delete this;
return block->Resolve(ctx);
}
bool IsGameSpecificForEachLoop(FxForEachLoop * loop)
{
auto * vt = loop->Array->ValueType;
return (vt->isObjectPointer() && (
((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_BlockLinesIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_BlockThingsIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ActorIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ThinkerIterator
));
}
FxExpression * ResolveGameSpecificForEachLoop(FxForEachLoop * loop)
{
FName cname = ((PObjectPointer*)loop->Array->ValueType)->PointedClass()->TypeName;
assert(loop->Array->ValueType->isObjectPointer());
if(cname == NAME_BlockLinesIterator || cname == NAME_BlockThingsIterator)
{
auto blockIt = new FxBlockIteratorForEachLoop(loop->loopVarName, NAME_None, NAME_None, loop->Array, loop->Code, loop->ScriptPosition);
loop->Array = loop->Code = nullptr;
delete loop;
return blockIt;
}
else if(cname == NAME_ActorIterator || cname == NAME_ThinkerIterator)
{
auto castIt = new FxCastForEachLoop(NAME_None, loop->loopVarName, loop->Array, loop->Code, loop->ScriptPosition);
loop->Array = loop->Code = nullptr;
delete loop;
return castIt;
}
else
{
delete loop;
return nullptr;
}
}
bool HasGameSpecificTwoArgForEachLoopTypeNames()
{
return true;
}
const char * GetGameSpecificTwoArgForEachLoopTypeNames()
{
return "a BlockLinesIterator, a BlockThingsIterator,";
}
bool IsGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop * loop)
{
return (loop->MapExpr->ValueType->isObjectPointer()
&& (((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator
|| ((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator));
}
FxExpression * ResolveGameSpecificTwoArgForEachLoop(FxTwoArgForEachLoop * loop)
{
assert(loop->MapExpr->ValueType->isObjectPointer());
assert(((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)loop->MapExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator);
auto blockIt = new FxBlockIteratorForEachLoop(loop->keyVarName, loop->valueVarName, NAME_None, loop->MapExpr, loop->Code, loop->ScriptPosition);
loop->MapExpr = loop->Code = nullptr;
delete loop;
return blockIt;
}
bool HasGameSpecificThreeArgForEachLoopTypeNames()
{
return true;
}
const char * GetGameSpecificThreeArgForEachLoopTypeNames()
{
return "a BlockLinesIterator or a BlockThingsIterator";
}
bool IsGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop * loop)
{
return (loop->BlockIteratorExpr->ValueType->isObjectPointer()
&& (((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator
|| ((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator));
}
FxExpression * ResolveGameSpecificThreeArgForEachLoop(FxThreeArgForEachLoop * loop)
{
assert(loop->BlockIteratorExpr->ValueType->isObjectPointer());
assert(((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockLinesIterator || ((PObjectPointer*)loop->BlockIteratorExpr->ValueType)->PointedClass()->TypeName == NAME_BlockThingsIterator);
auto blockIt = new FxBlockIteratorForEachLoop(loop->varVarName, loop->posVarName, loop->flagsVarName, loop->BlockIteratorExpr, loop->Code, loop->ScriptPosition);
loop->BlockIteratorExpr = loop->Code = nullptr;
delete loop;
return blockIt;
}
bool HasGameSpecificTypedForEachLoopTypeNames()
{
return true;
}
const char * GetGameSpecificTypedForEachLoopTypeNames()
{
return "an ActorIterator or a ThinkerIterator";
}
bool IsGameSpecificTypedForEachLoop(FxTypedForEachLoop * loop)
{
auto * vt = loop->Expr->ValueType;
return (vt->isObjectPointer() && (
((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ActorIterator
|| ((PObjectPointer*)vt)->PointedClass()->TypeName == NAME_ThinkerIterator
));
}
FxExpression * ResolveGameSpecificTypedForEachLoop(FxTypedForEachLoop * loop)
{
assert(loop->Expr->ValueType->isObjectPointer());
assert(((PObjectPointer*)loop->Expr->ValueType)->PointedClass()->TypeName == NAME_ActorIterator || ((PObjectPointer*)loop->Expr->ValueType)->PointedClass()->TypeName == NAME_ThinkerIterator);
FxExpression * castIt = new FxCastForEachLoop(loop->className, loop->varName, loop->Expr, loop->Code, loop->ScriptPosition);
loop->Expr = loop->Code = nullptr;
delete loop;
return castIt;
}

View file

@ -477,7 +477,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
{
FArgumentList args;
args.Push(exp);
exp = new FxFunctionCall(NAME_ResolveState, NAME_None, args, sc);
exp = new FxFunctionCall(NAME_ResolveState, NAME_None, std::move(args), sc);
}
sc.MustGetToken(')');
return exp;
@ -512,7 +512,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
ParseFunctionParameters(sc, cls, args, func, "", nullptr);
}
// FxVMFunctionCall cannot be used here as it lacks some important checks
return new FxFunctionCall(identifier, NAME_None, args, sc);
return new FxFunctionCall(identifier, NAME_None, std::move(args), sc);
}
}
@ -543,7 +543,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
while (sc.CheckToken(','));
sc.MustGetToken(')');
}
return new FxFunctionCall(identifier, NAME_None, args, sc);
return new FxFunctionCall(identifier, NAME_None, std::move(args), sc);
}
}
else

View file

@ -578,7 +578,7 @@ FxExpression* ParseAction(FScanner &sc, FState state, FString statestring, Bagga
{
FArgumentList args;
ParseFunctionParameters(sc, bag.Info, args, afd, statestring, &bag.statedef);
call = new FxFunctionCall(symname, NAME_None, args, sc);
call = new FxFunctionCall(symname, NAME_None, std::move(args), sc);
return call;
}
sc.ScriptError("Invalid parameter '%s'\n", sc.String);

View file

@ -351,6 +351,7 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(MF9, DOSHADOWBLOCK, AActor, flags9),
DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9),
DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9),
DEFINE_FLAG(MF9, DECOUPLEDANIMATIONS, AActor, flags9),
// Effect flags
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
@ -377,6 +378,8 @@ static FFlagDef ActorFlagDefs[]=
DEFINE_FLAG(RF, NOSPRITESHADOW, AActor, renderflags),
DEFINE_FLAG(RF2, INVISIBLEINMIRRORS, AActor, renderflags2),
DEFINE_FLAG(RF2, ONLYVISIBLEINMIRRORS, AActor, renderflags2),
DEFINE_FLAG(RF2, BILLBOARDFACECAMERA, AActor, renderflags2),
DEFINE_FLAG(RF2, BILLBOARDNOFACECAMERA, AActor, renderflags2),
// Bounce flags
DEFINE_FLAG2(BOUNCE_Walls, BOUNCEONWALLS, AActor, BounceFlags),
@ -645,6 +648,15 @@ static int propcmp(const void * a, const void * b)
//==========================================================================
void InitImports();
struct UserInfoCVarNamePlayer
{
FBaseCVar** addr;
FString name;
int pnum;
};
TArray<UserInfoCVarNamePlayer> LoadGameUserInfoCVars;
void InitThingdef()
{
// Some native types need size and serialization information added before the scripts get compiled.
@ -802,6 +814,79 @@ void InitThingdef()
auto fspp = NewStruct("FSpawnParticleParams", nullptr);
fspp->Size = sizeof(FSpawnParticleParams);
fspp->Align = alignof(FSpawnParticleParams);
auto cvst = NewStruct("CVar", nullptr, true);
NewPointer(cvst, false)->InstallHandlers(
[](FSerializer &arc, const char *key, const void *addr)
{
const FBaseCVar * self = *(const FBaseCVar**)addr;
if(self)
{
arc.BeginObject(key);
if(self->pnum != -1)
{
int32_t pnum = self->pnum;
FName name = self->userinfoName;
arc("name", name);
arc("player", pnum);
}
else
{
FString name = self->GetName();
arc("name", name);
}
arc.EndObject();
}
},
[](FSerializer &arc, const char *key, void *addr)
{
FBaseCVar ** self = (FBaseCVar**)addr;
FString name;
arc.BeginObject(key);
arc("name", name);
FBaseCVar * backing = FindCVar(name.GetChars(), nullptr);
if(!backing)
{
I_Error("Attempt to load pointer to inexisted CVar '%s'", name.GetChars());
}
else if((backing->GetFlags() & (CVAR_USERINFO|CVAR_IGNORE)) == CVAR_USERINFO)
{
if(int pnum; arc.ReadOptionalInt("player", pnum))
{
*self = nullptr;
LoadGameUserInfoCVars.Push({self, name, pnum}); // this needs to be done later, since userinfo isn't loaded yet
arc.EndObject();
return true;
}
}
*self = backing;
arc.EndObject();
return true;
}
);
}
void SetupLoadingCVars()
{
LoadGameUserInfoCVars.Clear();
}
void FinishLoadingCVars()
{
for(UserInfoCVarNamePlayer &cvar : LoadGameUserInfoCVars)
{
(*cvar.addr) = GetCVar(cvar.pnum, cvar.name.GetChars());
}
}
void SynthesizeFlagFields()

View file

@ -747,8 +747,8 @@ DEFINE_PROPERTY(translation, L, Actor)
for(int i = 1; i < PROP_PARM_COUNT; i++)
{
PROP_STRING_PARM(str, i);
int tnum;
if (i== 1 && PROP_PARM_COUNT == 2 && (tnum = R_FindCustomTranslation(str)) != -1)
FTranslationID tnum;
if (i== 1 && PROP_PARM_COUNT == 2 && (tnum = R_FindCustomTranslation(str)) != INVALID_TRANSLATION)
{
defaults->Translation = tnum;
return;
@ -789,7 +789,7 @@ DEFINE_PROPERTY(bloodcolor, C, Actor)
defaults->BloodColor = color;
defaults->BloodColor.a = 255; // a should not be 0.
defaults->BloodTranslation = TRANSLATION(TRANSLATION_Blood, CreateBloodTranslation(color));
defaults->BloodTranslation = CreateBloodTranslation(color);
}
//==========================================================================

View file

@ -2864,7 +2864,7 @@ DEFINE_FIELD_X(Sector, sector_t, SoundTarget)
DEFINE_FIELD_X(Sector, sector_t, special)
DEFINE_FIELD_X(Sector, sector_t, lightlevel)
DEFINE_FIELD_X(Sector, sector_t, seqType)
DEFINE_FIELD_X(Sector, sector_t, sky)
DEFINE_FIELD_NAMED_X(Sector, sector_t, skytransfer, sky)
DEFINE_FIELD_X(Sector, sector_t, SeqName)
DEFINE_FIELD_X(Sector, sector_t, centerspot)
DEFINE_FIELD_X(Sector, sector_t, validcount)