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(); } }); }
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(); } }); }
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(); }