Beispiel #1
0
        ///<summary>Registers a callback to the dependent soul that only occurs if the necessary soul doesn't die first, ensuring everything is cleaned up properly.</summary>
        public static RegistrationRemover DependentRegister(this ISoul soul, Action action, ISoul necessarySoul) {
            if (soul == null) throw new ArgumentNullException("soul");
            if (action == null) throw new ArgumentNullException("action");
            if (necessarySoul == null) throw new ArgumentNullException("necessarySoul");

            // when the necessary soul is the same soul as the dependent soul, assume the callback invocation will beat the registration removal
            if (ReferenceEquals(soul, necessarySoul))
                necessarySoul = ImmortalSoul.Instance;

            // avoid wrapping when possible
            if (necessarySoul.Phase == Phase.Dead)
                return EmptyRemover;
            if (soul.Phase != Phase.Mortal) {
                action();
                return EmptyRemover;
            }
            if (necessarySoul.Phase == Phase.Immortal)
                return soul.Register(action);

            return soul.InterdependentRegister(
                () => {
                    action();
                    return true;
                },
                necessarySoul,
                () => necessarySoul.Phase == Phase.Dead);
        }
Beispiel #2
0
        ///<summary>Registers callbacks to each soul, ensuring everything is cleaned up properly upon completion.</summary>
        public static RegistrationRemover InterdependentRegister(this ISoul soul1, Func<bool> tryComplete1, ISoul soul2, Func<bool> tryComplete2) {
            if (soul1 == null) throw new ArgumentNullException("soul1");
            if (tryComplete1 == null) throw new ArgumentNullException("tryComplete1");
            if (soul2 == null) throw new ArgumentNullException("soul2");
            if (tryComplete2 == null) throw new ArgumentNullException("tryComplete2");

            // forward declare the second registration canceller, so it can be referenced by the first registration
            RegistrationRemover cancelRegistration2 = null;
            var callCount = 0;
            Action skipOnceCancelRegistration2 = () => {
                if (Interlocked.Increment(ref callCount) == 2 && cancelRegistration2 != null)
                    cancelRegistration2();
            };

            // register the callbacks, linking their cancellation to each other
            var cancelRegistration1 = soul1.Register(() => { if (tryComplete1()) skipOnceCancelRegistration2(); });
            cancelRegistration2 = soul2.Register(() => { if (tryComplete2()) cancelRegistration1(); });
            
            // now that cancelRegistration2 has been initialized, we can allow it to be run
            skipOnceCancelRegistration2();

            // outside can force cleanup
            return () => {
                cancelRegistration1();
                cancelRegistration2();
            };
        }
Beispiel #3
0
        void IBootable.Launch()
        {
            _This    = _Binder.Bind <IPlayer>(this);
            _Chatter = _Room.RegistChatter(this);
            _Chatters.Items.Clear();

            _Room.Chatters.Supply   += _Add;
            _Room.Chatters.Unsupply += _Leave;
        }
Beispiel #4
0
 public CollapsingSoul(ISoul subSoul) {
     this._subSoul = subSoul;
     
     // flatten multiple levels of wrapping
     var r = subSoul as CollapsingSoul;
     if (r != null) this._subSoul = r._subSoul;
     
     // ensure collapse occurs once the sub soul becomes fixed
     Register(() => TryOptimize());
 }
Beispiel #5
0
        private Phase TryOptimize() {
            var phase = _subSoul.Phase;
            if (_collapsed) return phase; // already optimized
            if (phase == Phase.Mortal) return phase; // can't optimize yet

            // the following is idempotent, so it's fine if multiple writers race
            _collapsed = true;
            _subSoul = Phase.AsPermanentSoul();
            return phase;
        }
Beispiel #6
0
        ///<summary>Returns a lifetime for the given soul, collapsing it to a simpler soul when possible.</summary>
        public static Lifetime AsCollapsingLifetime(this ISoul soul)
        {
            // avoid any wrapping if possible
            var p = soul.Phase;

            if (p != Phase.Mortal)
            {
                return(p.AsPermanentLifetime());
            }

            return(new Lifetime(new CollapsingSoul(soul)));
        }
Beispiel #7
0
        public CollapsingSoul(ISoul subSoul)
        {
            _subSoul = subSoul;

            // flatten multiple levels of wrapping
            if (subSoul is CollapsingSoul cS)
            {
                _subSoul = cS._subSoul;
            }

            // ensure collapse occurs once the sub soul becomes fixed
            Register(() => tryOptimize());
        }
Beispiel #8
0
        ///<summary>Registers callbacks to each soul, ensuring everything is cleaned up properly upon completion.</summary>
        public static RegistrationRemover InterdependentRegister(this ISoul soul1, Func <bool> tryComplete1, ISoul soul2, Func <bool> tryComplete2)
        {
            if (soul1 == null)
            {
                throw new ArgumentNullException("soul1");
            }
            if (tryComplete1 == null)
            {
                throw new ArgumentNullException("tryComplete1");
            }
            if (soul2 == null)
            {
                throw new ArgumentNullException("soul2");
            }
            if (tryComplete2 == null)
            {
                throw new ArgumentNullException("tryComplete2");
            }

            // forward declare the second registration canceller, so it can be referenced by the first registration
            RegistrationRemover cancelRegistration2 = null;
            var    callCount = 0;
            Action skipOnceCancelRegistration2 = () => {
                if (Interlocked.Increment(ref callCount) == 2 && cancelRegistration2 != null)
                {
                    cancelRegistration2();
                }
            };

            // register the callbacks, linking their cancellation to each other
            var cancelRegistration1 = soul1.Register(() => { if (tryComplete1())
                                                             {
                                                                 skipOnceCancelRegistration2();
                                                             }
                                                     });

            cancelRegistration2 = soul2.Register(() => { if (tryComplete2())
                                                         {
                                                             cancelRegistration1();
                                                         }
                                                 });

            // now that cancelRegistration2 has been initialized, we can allow it to be run
            skipOnceCancelRegistration2();

            // outside can force cleanup
            return(() => {
                cancelRegistration1();
                cancelRegistration2();
            });
        }
Beispiel #9
0
        public CollapsingSoul(ISoul subSoul)
        {
            this._subSoul = subSoul;

            // flatten multiple levels of wrapping
            var r = subSoul as CollapsingSoul;

            if (r != null)
            {
                this._subSoul = r._subSoul;
            }

            // ensure collapse occurs once the sub soul becomes fixed
            Register(() => TryOptimize());
        }
Beispiel #10
0
        private Phase TryOptimize()
        {
            var phase = _subSoul.Phase;

            if (_collapsed)
            {
                return(phase);            // already optimized
            }
            if (phase == Phase.Mortal)
            {
                return(phase);                       // can't optimize yet
            }
            // the following is idempotent, so it's fine if multiple writers race
            _collapsed = true;
            _subSoul   = Phase.AsPermanentSoul();
            return(phase);
        }
Beispiel #11
0
        private void _Unbind(ISoul soul)
        {
            SoulProxy soulInfo;

            //Regulus.Utility.Log.Instance.WriteInfoImmediate($"unbind i:{soul.Instance.GetHashCode()} t:{soul.Instance.GetType()} id:{soul.Id}.");
            if (!_Souls.TryRemove(soul.Id, out soulInfo))
            {
                throw new Exception($"can't find the soul {soul.Id} to delete.");
            }
            soulInfo.Release();

            soulInfo.SupplySoulEvent   -= _PropertyBind;
            soulInfo.UnsupplySoulEvent -= _PropertyUnbind;


            _UnloadSoul(soulInfo.InterfaceId, soulInfo.Id);
            _IdLandlord.Return(soulInfo.Id);
        }
Beispiel #12
0
        ///<summary>Combines two souls by using a custom function to combine their phases.</summary>
        public static ISoul Combine(this ISoul soul1, ISoul soul2, Func <Phase, Phase, Phase> phaseCombiner)
        {
            Func <Phase> getPhase = () => phaseCombiner(soul1.Phase, soul2.Phase);

            return(new AnonymousSoul(
                       getPhase,
                       action => {
                Func <bool> tryComplete = () => {
                    var hasPhase = getPhase() != Phase.Mortal;
                    if (hasPhase)
                    {
                        action();
                    }
                    return hasPhase;
                };
                return soul1.InterdependentRegister(tryComplete, soul2, tryComplete);
            }));
        }
Beispiel #13
0
        ///<summary>Registers a callback to the dependent soul that only occurs if the necessary soul doesn't die first, ensuring everything is cleaned up properly.</summary>
        public static RegistrationRemover DependentRegister(this ISoul soul, Action action, ISoul necessarySoul)
        {
            if (soul == null)
            {
                throw new ArgumentNullException("soul");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }
            if (necessarySoul == null)
            {
                throw new ArgumentNullException("necessarySoul");
            }

            // when the necessary soul is the same soul as the dependent soul, assume the callback invocation will beat the registration removal
            if (ReferenceEquals(soul, necessarySoul))
            {
                necessarySoul = ImmortalSoul.Instance;
            }

            // avoid wrapping when possible
            if (necessarySoul.Phase == Phase.Dead)
            {
                return(EmptyRemover);
            }
            if (soul.Phase != Phase.Mortal)
            {
                action();
                return(EmptyRemover);
            }
            if (necessarySoul.Phase == Phase.Immortal)
            {
                return(soul.Register(action));
            }

            return(soul.InterdependentRegister(
                       () => {
                action();
                return true;
            },
                       necessarySoul,
                       () => necessarySoul.Phase == Phase.Dead));
        }
Beispiel #14
0
        static async Task Summon(Soul soul, string[] args = null)
        {
            try
            {
                ISoul soulHost = soul switch
                {
                    Soul.Anubis => new AnubisSoul(),
                    Soul.Horus => new HorusSoul(),
                    _ => throw new UnknownSoulException()
                };
                tcsSummon = new TaskCompletionSource();
                Speak($"{soul} has been summoned");
                soulHost.WaitForCommand(args);
                await tcsSummon.Task;
            }
            catch (UnknownSoulException)
            {
                Speak("Soul is not known or cannot be summoned");
            }
            catch (TaskCanceledException)
            {
                tcsSummon = null;
                var response = Ask($"{soul} dismissed. Do you want to summon {soul} again?", true);

                if (response == "y")
                {
                    await Summon(soul);
                }
            }
            catch (SummonFailedException ex)
            {
                Speak($"{soul} was unable to executed your command: {ex.Message}");
                var response = Ask($"Do you want to summon {soul} again?", true);

                if (response == "y")
                {
                    await Summon(soul);
                }
            }
        }
Beispiel #15
0
 void IBinder.Unbind(ISoul soul)
 {
     _Unbind(soul);
 }
Beispiel #16
0
 ///<summary>Combines two souls by using a custom function to combine their phases.</summary>
 public static ISoul Combine(this ISoul soul1, ISoul soul2, Func<Phase, Phase, Phase> phaseCombiner) {
     Func<Phase> getPhase = () => phaseCombiner(soul1.Phase, soul2.Phase);
     return new AnonymousSoul(
         getPhase,
         action => {
             Func<bool> tryComplete = () => {
                 var hasPhase = getPhase() != Phase.Mortal;
                 if (hasPhase) action();
                 return hasPhase;
             };
             return soul1.InterdependentRegister(tryComplete, soul2, tryComplete);
         });
 }
Beispiel #17
0
 void IBootable.Launch()
 {
     _Login = _Binder.Bind <ILogin>(this);
 }
Beispiel #18
0
 internal Lifetime(ISoul soul)
 {
     _defSoul = soul;
 }
Beispiel #19
0
 internal Lifetime(ISoul soul)
 {
     this._defSoul = soul;
 }