Added support for client-side Behaviors

This commit is contained in:
Boondorl 2025-07-08 02:52:17 -04:00 committed by Ricardo Luís Vaz Silva
commit a73d9f6e8f
5 changed files with 33 additions and 6 deletions

View file

@ -762,7 +762,7 @@ public:
DVisualThinker* VisualThinkerHead = nullptr;
// links to global game objects
TArray<DBehavior*> ActorBehaviors;
TArray<DBehavior*> ActorBehaviors, ClientSideActorBehaviors;
TArray<TObjPtr<AActor *>> CorpseQueue;
TObjPtr<DFraggleThinker *> FraggleScriptThinker = MakeObjPtr<DFraggleThinker*>(nullptr);
TObjPtr<DACSThinker*> ACSThinker = MakeObjPtr<DACSThinker*>(nullptr);
@ -780,7 +780,10 @@ public:
if (b.Level == nullptr)
{
b.Level = this;
ActorBehaviors.Push(&b);
if (b.IsClientside())
ClientSideActorBehaviors.Push(&b);
else
ActorBehaviors.Push(&b);
}
}
@ -789,7 +792,10 @@ public:
if (b.Level == this)
{
b.Level = nullptr;
ActorBehaviors.Delete(ActorBehaviors.Find(&b));
if (b.IsClientside())
ClientSideActorBehaviors.Delete(ClientSideActorBehaviors.Find(&b));
else
ActorBehaviors.Delete(ActorBehaviors.Find(&b));
}
}

View file

@ -387,6 +387,7 @@ void FLevelLocals::ClearLevelData(bool fullgc)
levelMesh = nullptr;
VisualThinkerHead = nullptr;
ActorBehaviors.Clear();
ClientSideActorBehaviors.Clear();
if (screen)
screen->SetAABBTree(nullptr);
}

View file

@ -539,6 +539,8 @@ DBehavior* AActor::AddBehavior(PClass& type)
return nullptr;
b->Owner = this;
b->ObjectFlags |= (ObjectFlags & (OF_ClientSide | OF_Transient));
Behaviors[type.TypeName] = b;
Level->AddActorBehavior(*b);
IFOVERRIDENVIRTUALPTRNAME(b, NAME_Behavior, Initialize)
@ -653,6 +655,9 @@ void AActor::MoveBehaviors(AActor& from)
if (&from == this)
return;
if (IsClientside() != from.IsClientside())
I_Error("Cannot move Behaviors between client-side and world Actors");
// Clean these up properly before transferring.
ClearBehaviors();

View file

@ -446,9 +446,10 @@ public:
Reinit();
}
DBehaviorIterator(const FLevelLocals& level, PClass* type, PClass* ownerType)
DBehaviorIterator(const FLevelLocals& level, PClass* type, PClass* ownerType, bool clientSide)
{
for (auto& b : level.ActorBehaviors)
auto& list = clientSide ? level.ClientSideActorBehaviors : level.ActorBehaviors;
for (auto& b : list)
{
if (ownerType != nullptr && !b->Owner->IsKindOf(ownerType))
continue;
@ -498,7 +499,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBehaviorIterator, CreateFrom, CreateBehaviorItFro
static DBehaviorIterator* CreateBehaviorIt(PClass* type, PClass* ownerType)
{
return Create<DBehaviorIterator>(*primaryLevel, type, ownerType);
return Create<DBehaviorIterator>(*primaryLevel, type, ownerType, false);
}
DEFINE_ACTION_FUNCTION_NATIVE(DBehaviorIterator, Create, CreateBehaviorIt)
@ -509,6 +510,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBehaviorIterator, Create, CreateBehaviorIt)
ACTION_RETURN_OBJECT(CreateBehaviorIt(type, ownerType));
}
static DBehaviorIterator* CreateClientSideBehaviorIt(PClass* type, PClass* ownerType)
{
return Create<DBehaviorIterator>(*primaryLevel, type, ownerType, true);
}
DEFINE_ACTION_FUNCTION_NATIVE(DBehaviorIterator, CreateClientSide, CreateClientSideBehaviorIt)
{
PARAM_PROLOGUE;
PARAM_CLASS(type, DBehavior);
PARAM_CLASS(ownerType, AActor);
ACTION_RETURN_OBJECT(CreateClientSideBehaviorIt(type, ownerType));
}
static DBehavior* NextBehavior(DBehaviorIterator* self)
{
return self->Next();

View file

@ -88,6 +88,7 @@ class BehaviorIterator native abstract final version("4.15.1")
{
native static BehaviorIterator CreateFrom(Actor mobj, class<Behavior> type = null);
native static BehaviorIterator Create(class<Behavior> type = null, class<Actor> ownerType = null);
native static BehaviorIterator CreateClientSide(class<Behavior> type = null, class<Actor> ownerType = null);
native Behavior Next();
native void Reinit();