internal void Created() { created = true; foreach (var t in TraitsImplementing <INotifyCreated>()) { t.Created(this); } // The initial activity should run before any activities queued by INotifyCreated.Created // However, we need to know which traits are enabled (via conditions), so wait for after the calls and insert the activity as the first ICreationActivity creationActivity = null; foreach (var ica in TraitsImplementing <ICreationActivity>()) { if (!ica.IsTraitEnabled()) { continue; } if (creationActivity != null) { throw new InvalidOperationException("More than one enabled ICreationActivity trait: {0} and {1}".F(creationActivity.GetType().Name, ica.GetType().Name)); } var activity = ica.GetCreationActivity(); if (activity == null) { continue; } creationActivity = ica; activity.Queue(CurrentActivity); CurrentActivity = activity; } }
internal void Initialize(bool addToWorld = true) { created = true; // Make sure traits are usable for condition notifiers foreach (var t in TraitsImplementing <INotifyCreated>()) { t.Created(this); } var allObserverNotifiers = new HashSet <VariableObserverNotifier>(); foreach (var provider in TraitsImplementing <IObservesVariables>()) { foreach (var variableUser in provider.GetVariableObservers()) { allObserverNotifiers.Add(variableUser.Notifier); foreach (var variable in variableUser.Variables) { var cs = conditionStates.GetOrAdd(variable); cs.Notifiers.Add(variableUser.Notifier); // Initialize conditions that have not yet been granted to 0 // NOTE: Some conditions may have already been granted by INotifyCreated calling GrantCondition, // and we choose to assign the token count to safely cover both cases instead of adding an if branch. conditionCache[variable] = cs.Tokens.Count; } } } // Update all traits with their initial condition state foreach (var notify in allObserverNotifiers) { notify(this, readOnlyConditionCache); } // 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 (setStaticTargetablePositions) { staticTargetablePositions = enabledTargetablePositions.SelectMany(tp => tp.TargetablePositions(this)).ToArray(); } // TODO: Other traits may need initialization after being notified of initial condition state. // TODO: A post condition initialization notification phase may allow queueing activities instead. // The initial activity should run before any activities queued by INotifyCreated.Created // However, we need to know which traits are enabled (via conditions), so wait for after the calls and insert the activity as the first ICreationActivity creationActivity = null; foreach (var ica in TraitsImplementing <ICreationActivity>()) { if (!ica.IsTraitEnabled()) { continue; } if (creationActivity != null) { throw new InvalidOperationException("More than one enabled ICreationActivity trait: {0} and {1}".F(creationActivity.GetType().Name, ica.GetType().Name)); } var activity = ica.GetCreationActivity(); if (activity == null) { continue; } creationActivity = ica; activity.Queue(CurrentActivity); CurrentActivity = activity; } if (addToWorld) { World.Add(this); } }