Example #1
0
        public void Dispose()
        {
            // If CurrentActivity isn't null, run OnActorDisposeOuter in case some cleanups are needed.
            // This should be done before the FrameEndTask to avoid dependency issues.
            if (CurrentActivity != null)
            {
                CurrentActivity.OnActorDisposeOuter(this);
            }

            // Allow traits/activities to prevent a race condition when they depend on disposing the actor (e.g. Transforms)
            WillDispose = true;

            World.AddFrameEndTask(w =>
            {
                if (Disposed)
                {
                    return;
                }

                if (IsInWorld)
                {
                    World.Remove(this);
                }

                foreach (var t in TraitsImplementing <INotifyActorDisposing>())
                {
                    t.Disposing(this);
                }

                World.TraitDict.RemoveActor(this);
                Disposed = true;

                if (luaInterface != null)
                {
                    luaInterface.Value.OnActorDestroyed();
                }
            });
        }
Example #2
0
        public void Destroy()
        {
            World.AddFrameEndTask(w =>
            {
                if (Destroyed)
                {
                    return;
                }

                if (IsInWorld)
                {
                    World.Remove(this);
                }

                World.traitDict.RemoveActor(this);
                Destroyed = true;

                if (luaInterface != null)
                {
                    luaInterface.Value.OnActorDestroyed();
                }
            });
        }
Example #3
0
        internal Actor(World world, string name, TypeDictionary initDict)
        {
            var init = new ActorInitializer(this, initDict);

            World   = world;
            ActorID = world.NextAID();
            if (initDict.Contains <OwnerInit>())
            {
                Owner = init.Get <OwnerInit, Player>();
            }

            if (name != null)
            {
                name = name.ToLowerInvariant();

                if (!world.Map.Rules.Actors.ContainsKey(name))
                {
                    throw new NotImplementedException("No rules definition for unit " + name);
                }

                Info = world.Map.Rules.Actors[name];
                foreach (var trait in Info.TraitsInConstructOrder())
                {
                    AddTrait(trait.Create(init));

                    // Some traits rely on properties provided by IOccupySpace in their initialization,
                    // so we must ready it now, we cannot wait until all traits have finished construction.
                    if (trait is IOccupySpaceInfo)
                    {
                        OccupiesSpace = Trait <IOccupySpace>();
                    }
                }
            }

            // PERF: Cache all these traits as soon as the actor is created. This is a fairly cheap one-off cost per
            // actor that allows us to provide some fast implementations of commonly used methods that are relied on by
            // performance-sensitive parts of the core game engine, such as pathfinding, visibility and rendering.
            EffectiveOwner      = TraitOrDefault <IEffectiveOwner>();
            facing              = TraitOrDefault <IFacing>();
            health              = TraitOrDefault <IHealth>();
            renderModifiers     = TraitsImplementing <IRenderModifier>().ToArray();
            renders             = TraitsImplementing <IRender>().ToArray();
            mouseBounds         = TraitsImplementing <IMouseBounds>().ToArray();
            visibilityModifiers = TraitsImplementing <IVisibilityModifier>().ToArray();
            defaultVisibility   = Trait <IDefaultVisibility>();
            tickIdles           = TraitsImplementing <INotifyIdle>().ToArray();
            Targetables         = TraitsImplementing <ITargetable>().ToArray();
            targetablePositions = TraitsImplementing <ITargetablePositions>().ToArray();
            world.AddFrameEndTask(w =>
            {
                // Caching this in a AddFrameEndTask, because trait construction order might cause problems if done directly at creation time.
                // All actors that can move or teleport should have IPositionable, if not it's pretty safe to assume the actor is completely immobile and
                // all targetable positions can be cached if all ITargetablePositions have no conditional requirements.
                if (!Info.HasTraitInfo <IPositionableInfo>() && targetablePositions.Any() && targetablePositions.All(tp => tp.AlwaysEnabled))
                {
                    staticTargetablePositions = targetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray();
                }
            });

            SyncHashes = TraitsImplementing <ISync>().Select(sync => new SyncHash(sync)).ToArray();
        }