// $Revision: 1.12 $ // Copyright (C) 1994 Taligent, Inc. All rights reserved. #ifndef TaligentSamples_UNIVERSESUBSYSTEM #include "UniverseSubsystem.h" #endif #ifndef TaligentSamples_CONCURRENTACTORS #include "ConcurrentActors.h" #endif #ifndef Taligent_COLLECTIONEXCEPTION #include #endif //============================================================================== // TUniverseActorNote MCollectibleDefinitionsMacro(TUniverseActorNote, kOriginalVersion); TUniverseActorNote::TUniverseActorNote(const TInterest& interest, TAbstractActor* actor) : TNotification(interest), fActor(actor) { } TUniverseActorNote::TUniverseActorNote(TInterest* interest, TAbstractActor* actor) : TNotification(*interest), fActor(actor) { delete interest; } TUniverseActorNote::TUniverseActorNote(const TUniverseActorNote& source) : TNotification(source), fActor(source.fActor) { } TUniverseActorNote::~TUniverseActorNote() { } TUniverseActorNote& TUniverseActorNote::operator=(const TUniverseActorNote& source) { if (&source != this) { TNotification::operator=(source); fActor = source.fActor; } return *this; } TStream& TUniverseActorNote::operator>>=(TStream& toStream) const { WriteVersion(toStream); TNotification::operator>>=(toStream); ::Flatten(fActor, toStream); return toStream; } TStream& TUniverseActorNote::operator<<=(TStream& fromStream) { ReadVersion(fromStream, kOriginalVersion, kOriginalVersion); TNotification::operator<<=(fromStream); ::Resurrect(fActor, fromStream); return fromStream; } bool TUniverseActorNote::IsEqual(const MCollectible* other) const { bool result(true); if (this == other) { result = true; } else if (!TNotification::IsEqual(other)) { result = false; } else { const TUniverseActorNote* otherTUniverseActorNote = (const TUniverseActorNote*)other; result = fActor == otherTUniverseActorNote->fActor; } return result; } long TUniverseActorNote::Hash() const { return 0; } TAbstractActor* TUniverseActorNote::GetActor() const { return fActor; } TUniverseActorNote::TUniverseActorNote() : TNotification(), fActor(NIL) { } //============================================================================== // TAbstractActor TaligentTypeExtensionMacro_Abstract(TAbstractActor) TAbstractActor::TAbstractActor() : MMoving(), MColliding(), MRefreshable(), fIsDeadAlready(false), fNotifier(), fLock() { } TAbstractActor::TAbstractActor(const TAbstractActor& source) : MMoving(source), MColliding(source), MRefreshable(source), fIsDeadAlready(false), fNotifier(), fLock() { } TAbstractActor::~TAbstractActor() { } TAbstractActor& TAbstractActor::operator=(const TAbstractActor& source) { if (&source != this) { MMoving::operator=(source); MColliding::operator=(source); MRefreshable::operator=(source); } return *this; } TStream& TAbstractActor::operator>>=(TStream& toStream) const { WriteVersion(toStream); return toStream; } TStream& TAbstractActor::operator<<=(TStream& fromStream) { VersionInfo info = ReadVersion(fromStream, kOriginalVersion, kOriginalVersion); return fromStream; } bool TAbstractActor::IsA(const TType& type) const { return type == StaticTypeInfo(TAbstractActor) || MColliding::IsA(type); } void TAbstractActor::PreMove(const TTime& interval) { Lock(); fCollisionCheckNeeded = false; MMoving::PreMove(interval); } void TAbstractActor::PostMove(const TTime& interval) { MMoving::PostMove(interval); if (fCollisionCheckNeeded) { NotifyCollisionPossible(); } Unlock(); } void TAbstractActor::PreRefresh(const TTime& interval) { Lock(); MRefreshable::PreRefresh(interval); } void TAbstractActor::PostRefresh(const TTime& interval) { MRefreshable::PostRefresh(interval); Unlock(); } TInterest* TAbstractActor::CreateUniverseAffectInterest() { static const TToken kInterestToken("TAbstractActor::CreateUniverseAffectInterest"); return new TInterest(&GetNotifier(), kInterestToken); } bool TAbstractActor::IsDead() const { return fIsDeadAlready; } void TAbstractActor::Lock() { fLock.Acquire(); } void TAbstractActor::Unlock() { fLock.Release(); } void TAbstractActor::SelfDestruct() { if (!IsDead()) { fIsDeadAlready = true; GetNotifier().Notify(TUniverseActorNote(CreateUniverseAffectInterest(), this)); } } void TAbstractActor::RegisterOffspring(TAbstractActor* offspring) { if (IsDead()) { delete offspring; } else { GetNotifier().Notify(TUniverseActorNote(CreateUniverseAffectInterest(), offspring)); } } void TAbstractActor::CollisionCheckNeeded() { if (!IsDead()) { fCollisionCheckNeeded = true; } } TNotifier& TAbstractActor::GetNotifier() const { return (TNotifier&)fNotifier; } void TAbstractActor::NotifyCollisionPossible() { MColliding::NotifyCollisionPossible(); } //============================================================================== // TActorEntry TActorEntry::TActorEntry(TAbstractActor* actor) : fActor(actor) { fActor->Lock(); } TActorEntry::~TActorEntry() { fActor->Unlock(); } //============================================================================== // TUniverseThread TUniverseThread::TUniverseThread(TUniverse* universe) : TBoundThreadProgram(), fUniverse(universe), fQueue(), fConnection(this, HandleNote) { fConnection.Connect(); } TUniverseThread::~TUniverseThread() { fConnection.RemoveAllInterests(); } void TUniverseThread::Watch(TAbstractActor* actor) { fConnection.AdoptInterest(actor->CreateUniverseAffectInterest()); } void TUniverseThread::Ignore(TAbstractActor& actor) { TInterest* interest = actor.CreateUniverseAffectInterest(); fConnection.RemoveInterest(*interest); delete interest; } void TUniverseThread::IgnoreAll() { fConnection.RemoveAllInterests(); } void TUniverseThread::BoundRun() { try { while (true) { TUniverseActorNote* affect = fQueue.RemoveNext(); TAbstractActor* actor = affect->GetActor(); if (actor->IsDead()) { fUniverse->OrphanActor(*actor); delete actor; } else { fUniverse->AdoptActor(actor); } delete affect; } } catch (TCollectionException& bob) { } } void TUniverseThread::BoundExit() { fQueue.Close(); } void TUniverseThread::HandleNote(const TNotification& noteIn) { TUniverseActorNote& note = (TUniverseActorNote&)noteIn; fQueue.Add((TUniverseActorNote*)::Copy(note)); } //============================================================================== // TUniverse TUniverse::TUniverse(TGrafPort* refreshPort, TDequeOf* actors, TDequeOf* behaviors, MRefreshable* background) : fBackground(background), fActors(actors), fBehaviors(behaviors), fRefreshThread(refreshPort), fMoverThread(), fUniverseAffectThread(this), fNotifier() { fRefreshThread.SetBackground(fBackground); TDequeOfIterator actorIterator(fActors); TAbstractActor* actor = actorIterator.First(); while (actor != NIL) { fRefreshThread.Add(actor); fMoverThread.Add(actor); fUniverseAffectThread.Watch(actor); ConnectToBehaviors(actor); actor = actorIterator.Next(); } } TUniverse::~TUniverse() { fMoverThread.Terminate(); fRefreshThread.Terminate(); fUniverseAffectThread.Terminate(); fUniverseAffectThread.IgnoreAll(); DisconnectAllBehaviors(); fMoverThread.RemoveAll(); fRefreshThread.RemoveAll(); } void TUniverse::AdoptActor(TAbstractActor* actor) { TPeriodicThreadEntry moveEntry(&fMoverThread); { TPeriodicThreadEntry refreshEntry(&fRefreshThread); fActors->AddLast(actor); ConnectToBehaviors(actor); fUniverseAffectThread.Watch(actor); fRefreshThread.Add(actor); fMoverThread.Add(actor); fNotifier.Notify(TUniverseActorNote(CreateAdoptInterest(), actor)); } } TAbstractActor* TUniverse::OrphanActor(TAbstractActor& actor) { TAbstractActor* result = NIL; TPeriodicThreadEntry moveEntry(&fMoverThread); { TPeriodicThreadEntry refreshEntry(&fRefreshThread); fMoverThread.Remove(actor); fRefreshThread.Remove(actor); fUniverseAffectThread.Ignore(actor); DisconnectFromBehaviors(actor); result = fActors->Remove(actor); fNotifier.Notify(TUniverseActorNote(CreateOrphanInterest(), &actor)); } return result; } void TUniverse::Start() { fRefreshThread.Start(); fUniverseAffectThread.Start(); fMoverThread.Start(); } void TUniverse::Stop() { fMoverThread.Terminate(); fUniverseAffectThread.Terminate(); fRefreshThread.Terminate(); } void TUniverse::Pause() { fMoverThread.Pause(); fRefreshThread.Pause(); } void TUniverse::Resume() { fRefreshThread.Resume(); fMoverThread.Resume(); } TInterest* TUniverse::CreateRefreshInterest() { return fRefreshThread.CreateRefreshInterest(); } TInterest* TUniverse::CreateAdoptInterest() { static const TToken kInterestToken("TUniverse::CreateAdoptInterest"); return new TInterest(&fNotifier, kInterestToken); } TInterest* TUniverse::CreateOrphanInterest() { static const TToken kInterestToken("TUniverse::CreateOrphanInterest"); return new TInterest(&fNotifier, kInterestToken); } void TUniverse::ConnectToBehaviors(TAbstractActor* actor) { TDequeOfIterator behaviorIterator(fBehaviors); TCollisionBehavior* behavior = behaviorIterator.First(); while (behavior != NIL) { behavior->ConnectTo(actor); behavior = behaviorIterator.Next(); } } void TUniverse::DisconnectFromBehaviors(TAbstractActor& actor) { TDequeOfIterator behaviorIterator(fBehaviors); TCollisionBehavior* behavior = behaviorIterator.First(); while (behavior != NIL) { behavior->DisconnectFrom(actor); behavior = behaviorIterator.Next(); } } void TUniverse::DisconnectAllBehaviors() { TDequeOfIterator actorIterator(fActors); TAbstractActor* actor = actorIterator.First(); while (actor != NIL) { DisconnectFromBehaviors(*actor); actor = actorIterator.Next(); } }