Initial Commit
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab31f5a16678ab042ae89fdbb0efec56
|
||||
folderAsset: yes
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc112bf254895114bb60868a302a3cf7
|
||||
folderAsset: yes
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 610ec45090eac884ba824be81ada42fb
|
||||
folderAsset: yes
|
||||
timeCreated: 1521277428
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public class BindSignalFromBinder<TObject, TSignal>
|
||||
{
|
||||
readonly BindStatement _bindStatement;
|
||||
readonly Func<TObject, Action<TSignal>> _methodGetter;
|
||||
readonly DiContainer _container;
|
||||
readonly SignalBindingBindInfo _signalBindInfo;
|
||||
|
||||
public BindSignalFromBinder(
|
||||
SignalBindingBindInfo signalBindInfo, BindStatement bindStatement, Func<TObject, Action<TSignal>> methodGetter,
|
||||
DiContainer container)
|
||||
{
|
||||
_signalBindInfo = signalBindInfo;
|
||||
_bindStatement = bindStatement;
|
||||
_methodGetter = methodGetter;
|
||||
_container = container;
|
||||
}
|
||||
|
||||
public SignalCopyBinder FromResolve()
|
||||
{
|
||||
return From(x => x.FromResolve().AsCached());
|
||||
}
|
||||
|
||||
public SignalCopyBinder FromResolveAll()
|
||||
{
|
||||
return From(x => x.FromResolveAll().AsCached());
|
||||
}
|
||||
|
||||
public SignalCopyBinder FromNew()
|
||||
{
|
||||
return From(x => x.FromNew().AsCached());
|
||||
}
|
||||
|
||||
public SignalCopyBinder From(Action<ConcreteBinderGeneric<TObject>> objectBindCallback)
|
||||
{
|
||||
Assert.That(!_bindStatement.HasFinalizer);
|
||||
_bindStatement.SetFinalizer(new NullBindingFinalizer());
|
||||
|
||||
var objectLookupId = Guid.NewGuid();
|
||||
|
||||
// Very important here that we use NoFlush otherwise the main binding will be finalized early
|
||||
var objectBinder = _container.BindNoFlush<TObject>().WithId(objectLookupId);
|
||||
|
||||
objectBindCallback(objectBinder);
|
||||
|
||||
// We need to do this to make sure SignalCallbackWithLookupWrapper does not have
|
||||
// generic types to avoid AOT issues
|
||||
Func<object, Action<object>> methodGetterMapper =
|
||||
obj => s => _methodGetter((TObject)obj)((TSignal)s);
|
||||
|
||||
var wrapperBinder = _container.Bind<IDisposable>()
|
||||
.To<SignalCallbackWithLookupWrapper>()
|
||||
.AsCached()
|
||||
.WithArguments(_signalBindInfo, typeof(TObject), objectLookupId, methodGetterMapper)
|
||||
.NonLazy();
|
||||
|
||||
var copyBinder = new SignalCopyBinder( wrapperBinder.BindInfo);
|
||||
// Make sure if they use one of the Copy/Move methods that it applies to both bindings
|
||||
copyBinder.AddCopyBindInfo(objectBinder.BindInfo);
|
||||
return copyBinder;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c779f758eaadfd54fb9c66f7acc75716
|
||||
timeCreated: 1521288279
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public class BindSignalIdToBinder<TSignal> : BindSignalToBinder<TSignal>
|
||||
{
|
||||
public BindSignalIdToBinder(DiContainer container, SignalBindingBindInfo signalBindInfo)
|
||||
: base(container, signalBindInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public BindSignalToBinder<TSignal> WithId(object identifier)
|
||||
{
|
||||
SignalBindInfo.Identifier = identifier;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecce6d44c178e564c8937125741f3c8c
|
||||
timeCreated: 1538401230
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public class BindSignalToBinder<TSignal>
|
||||
{
|
||||
DiContainer _container;
|
||||
BindStatement _bindStatement;
|
||||
SignalBindingBindInfo _signalBindInfo;
|
||||
|
||||
public BindSignalToBinder(DiContainer container, SignalBindingBindInfo signalBindInfo)
|
||||
{
|
||||
_container = container;
|
||||
|
||||
_signalBindInfo = signalBindInfo;
|
||||
// This will ensure that they finish the binding
|
||||
_bindStatement = container.StartBinding();
|
||||
}
|
||||
|
||||
protected SignalBindingBindInfo SignalBindInfo
|
||||
{
|
||||
get { return _signalBindInfo; }
|
||||
}
|
||||
|
||||
public SignalCopyBinder ToMethod(Action<TSignal> callback)
|
||||
{
|
||||
Assert.That(!_bindStatement.HasFinalizer);
|
||||
_bindStatement.SetFinalizer(new NullBindingFinalizer());
|
||||
|
||||
var bindInfo = _container.Bind<IDisposable>()
|
||||
.To<SignalCallbackWrapper>()
|
||||
.AsCached()
|
||||
// Note that there's a reason we don't just make SignalCallbackWrapper have a generic
|
||||
// argument for signal type - because when using struct type signals it throws
|
||||
// exceptions on AOT platforms
|
||||
.WithArguments(_signalBindInfo, (Action<object>)(o => callback((TSignal)o)))
|
||||
.NonLazy().BindInfo;
|
||||
|
||||
return new SignalCopyBinder(bindInfo);
|
||||
}
|
||||
|
||||
public SignalCopyBinder ToMethod(Action callback)
|
||||
{
|
||||
return ToMethod(signal => callback());
|
||||
}
|
||||
|
||||
public BindSignalFromBinder<TObject, TSignal> ToMethod<TObject>(Action<TObject, TSignal> handler)
|
||||
{
|
||||
return ToMethod<TObject>(x => (Action<TSignal>)(s => handler(x, s)));
|
||||
}
|
||||
|
||||
public BindSignalFromBinder<TObject, TSignal> ToMethod<TObject>(Func<TObject, Action> handlerGetter)
|
||||
{
|
||||
return ToMethod<TObject>(x => (Action<TSignal>)(s => handlerGetter(x)()));
|
||||
}
|
||||
|
||||
public BindSignalFromBinder<TObject, TSignal> ToMethod<TObject>(Func<TObject, Action<TSignal>> handlerGetter)
|
||||
{
|
||||
return new BindSignalFromBinder<TObject, TSignal>(
|
||||
_signalBindInfo, _bindStatement, handlerGetter, _container);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6df1bca64a984074fb4af41dc1d42a07
|
||||
timeCreated: 1521288279
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// Note that there's a reason we don't just have a generic
|
||||
// argument for signal type - because when using struct type signals it throws
|
||||
// exceptions on AOT platforms
|
||||
public class SignalCallbackWithLookupWrapper : IDisposable
|
||||
{
|
||||
readonly DiContainer _container;
|
||||
readonly SignalBus _signalBus;
|
||||
readonly Guid _lookupId;
|
||||
readonly Func<object, Action<object>> _methodGetter;
|
||||
readonly Type _objectType;
|
||||
readonly Type _signalType;
|
||||
readonly object _identifier;
|
||||
|
||||
public SignalCallbackWithLookupWrapper(
|
||||
SignalBindingBindInfo signalBindInfo,
|
||||
Type objectType,
|
||||
Guid lookupId,
|
||||
Func<object, Action<object>> methodGetter,
|
||||
SignalBus signalBus,
|
||||
DiContainer container)
|
||||
{
|
||||
_objectType = objectType;
|
||||
_signalType = signalBindInfo.SignalType;
|
||||
_identifier = signalBindInfo.Identifier;
|
||||
_container = container;
|
||||
_methodGetter = methodGetter;
|
||||
_signalBus = signalBus;
|
||||
_lookupId = lookupId;
|
||||
|
||||
signalBus.SubscribeId(signalBindInfo.SignalType, _identifier, OnSignalFired);
|
||||
}
|
||||
|
||||
void OnSignalFired(object signal)
|
||||
{
|
||||
var objects = _container.ResolveIdAll(_objectType, _lookupId);
|
||||
|
||||
for (int i = 0; i < objects.Count; i++)
|
||||
{
|
||||
_methodGetter(objects[i])(signal);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.UnsubscribeId(_signalType, _identifier, OnSignalFired);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b11a635fa1263c4f9a9a0d70d7efcf2
|
||||
timeCreated: 1521293791
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// Note that there's a reason we don't just have a generic
|
||||
// argument for signal type - because when using struct type signals it throws
|
||||
// exceptions on AOT platforms
|
||||
public class SignalCallbackWrapper : IDisposable
|
||||
{
|
||||
readonly SignalBus _signalBus;
|
||||
readonly Action<object> _action;
|
||||
readonly Type _signalType;
|
||||
readonly object _identifier;
|
||||
|
||||
public SignalCallbackWrapper(
|
||||
SignalBindingBindInfo bindInfo,
|
||||
Action<object> action,
|
||||
SignalBus signalBus)
|
||||
{
|
||||
_signalType = bindInfo.SignalType;
|
||||
_identifier = bindInfo.Identifier;
|
||||
_signalBus = signalBus;
|
||||
_action = action;
|
||||
|
||||
signalBus.SubscribeId(bindInfo.SignalType, _identifier, OnSignalFired);
|
||||
}
|
||||
|
||||
void OnSignalFired(object signal)
|
||||
{
|
||||
_action(signal);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_signalBus.UnsubscribeId(_signalType, _identifier, OnSignalFired);
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a8599dbdf9033e468671e40de134ccf
|
||||
timeCreated: 1521289018
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fe74811bfda2ef4ca9791eab479b27a
|
||||
folderAsset: yes
|
||||
timeCreated: 1521277428
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class DeclareSignalAsyncTickPriorityCopyBinder : SignalTickPriorityCopyBinder
|
||||
{
|
||||
public DeclareSignalAsyncTickPriorityCopyBinder(SignalDeclarationBindInfo signalBindInfo)
|
||||
: base(signalBindInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public SignalTickPriorityCopyBinder RunAsync()
|
||||
{
|
||||
SignalBindInfo.RunAsync = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SignalCopyBinder RunSync()
|
||||
{
|
||||
SignalBindInfo.RunAsync = false;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b81f91889a4f58f45a186d306ec19a76
|
||||
timeCreated: 1529046908
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class DeclareSignalIdRequireHandlerAsyncTickPriorityCopyBinder : DeclareSignalRequireHandlerAsyncTickPriorityCopyBinder
|
||||
{
|
||||
public DeclareSignalIdRequireHandlerAsyncTickPriorityCopyBinder(
|
||||
SignalDeclarationBindInfo signalBindInfo)
|
||||
: base(signalBindInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public DeclareSignalRequireHandlerAsyncTickPriorityCopyBinder WithId(object identifier)
|
||||
{
|
||||
SignalBindInfo.Identifier = identifier;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 183994f131b561a43a9967cceb7c949d
|
||||
timeCreated: 1538037476
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class DeclareSignalRequireHandlerAsyncTickPriorityCopyBinder : DeclareSignalAsyncTickPriorityCopyBinder
|
||||
{
|
||||
public DeclareSignalRequireHandlerAsyncTickPriorityCopyBinder(
|
||||
SignalDeclarationBindInfo signalBindInfo)
|
||||
: base(signalBindInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public DeclareSignalAsyncTickPriorityCopyBinder RequireSubscriber()
|
||||
{
|
||||
SignalBindInfo.MissingHandlerResponse = SignalMissingHandlerResponses.Throw;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeclareSignalAsyncTickPriorityCopyBinder OptionalSubscriber()
|
||||
{
|
||||
SignalBindInfo.MissingHandlerResponse = SignalMissingHandlerResponses.Ignore;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DeclareSignalAsyncTickPriorityCopyBinder OptionalSubscriberWithWarning()
|
||||
{
|
||||
SignalBindInfo.MissingHandlerResponse = SignalMissingHandlerResponses.Warn;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7cc67ec88be096e4a89e01987d671cb9
|
||||
timeCreated: 1529046908
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class SignalBindingBindInfo
|
||||
{
|
||||
public SignalBindingBindInfo(Type signalType)
|
||||
{
|
||||
SignalType = signalType;
|
||||
}
|
||||
|
||||
public object Identifier
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public Type SignalType
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 054ec2c1e404fd04f99dcab4d9012db2
|
||||
timeCreated: 1538401117
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class SignalDeclarationBindInfo
|
||||
{
|
||||
public SignalDeclarationBindInfo(Type signalType)
|
||||
{
|
||||
SignalType = signalType;
|
||||
}
|
||||
|
||||
public object Identifier
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public Type SignalType
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public bool RunAsync
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public int TickPriority
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public SignalMissingHandlerResponses MissingHandlerResponse
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e83db91ff836874fb4fcf3ae4e16f0b
|
||||
timeCreated: 1521277428
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class SignalCopyBinder
|
||||
{
|
||||
readonly List<BindInfo> _bindInfos;
|
||||
|
||||
public SignalCopyBinder()
|
||||
{
|
||||
_bindInfos = new List<BindInfo>();
|
||||
}
|
||||
|
||||
public SignalCopyBinder(BindInfo bindInfo)
|
||||
{
|
||||
_bindInfos = new List<BindInfo>
|
||||
{
|
||||
bindInfo
|
||||
};
|
||||
}
|
||||
|
||||
// This is used in cases where you have multiple bindings that depend on each other so should
|
||||
// be inherited together
|
||||
public void AddCopyBindInfo(BindInfo bindInfo)
|
||||
{
|
||||
_bindInfos.Add(bindInfo);
|
||||
}
|
||||
|
||||
public void CopyIntoAllSubContainers()
|
||||
{
|
||||
SetInheritanceMethod(BindingInheritanceMethods.CopyIntoAll);
|
||||
}
|
||||
|
||||
// Only copy the binding into children and not grandchildren
|
||||
public void CopyIntoDirectSubContainers()
|
||||
{
|
||||
SetInheritanceMethod(BindingInheritanceMethods.CopyDirectOnly);
|
||||
}
|
||||
|
||||
// Do not apply the binding on the current container
|
||||
public void MoveIntoAllSubContainers()
|
||||
{
|
||||
SetInheritanceMethod(BindingInheritanceMethods.MoveIntoAll);
|
||||
}
|
||||
|
||||
// Do not apply the binding on the current container
|
||||
public void MoveIntoDirectSubContainers()
|
||||
{
|
||||
SetInheritanceMethod(BindingInheritanceMethods.MoveDirectOnly);
|
||||
}
|
||||
|
||||
void SetInheritanceMethod(BindingInheritanceMethods method)
|
||||
{
|
||||
for (int i = 0; i < _bindInfos.Count; i++)
|
||||
{
|
||||
_bindInfos[i].BindingInheritanceMethod = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 604fe2d23cc79c7498be851b6970af1b
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
namespace Zenject
|
||||
{
|
||||
public static class SignalExtensions
|
||||
{
|
||||
public static SignalDeclarationBindInfo CreateDefaultSignalDeclarationBindInfo(DiContainer container, Type signalType)
|
||||
{
|
||||
return new SignalDeclarationBindInfo(signalType)
|
||||
{
|
||||
RunAsync = container.Settings.Signals.DefaultSyncMode == SignalDefaultSyncModes.Asynchronous,
|
||||
MissingHandlerResponse = container.Settings.Signals.MissingHandlerDefaultResponse,
|
||||
TickPriority = container.Settings.Signals.DefaultAsyncTickPriority
|
||||
};
|
||||
}
|
||||
|
||||
public static DeclareSignalIdRequireHandlerAsyncTickPriorityCopyBinder DeclareSignal(this DiContainer container, Type type)
|
||||
{
|
||||
var signalBindInfo = CreateDefaultSignalDeclarationBindInfo(container, type);
|
||||
|
||||
var bindInfo = container.Bind<SignalDeclaration>().AsCached()
|
||||
.WithArguments(signalBindInfo).WhenInjectedInto(typeof(SignalBus), typeof(SignalDeclarationAsyncInitializer)).BindInfo;
|
||||
|
||||
var signalBinder = new DeclareSignalIdRequireHandlerAsyncTickPriorityCopyBinder(signalBindInfo);
|
||||
signalBinder.AddCopyBindInfo(bindInfo);
|
||||
return signalBinder;
|
||||
}
|
||||
|
||||
public static DeclareSignalIdRequireHandlerAsyncTickPriorityCopyBinder DeclareSignal<TSignal>(this DiContainer container)
|
||||
{
|
||||
return container.DeclareSignal(typeof(TSignal));
|
||||
}
|
||||
|
||||
public static DeclareSignalIdRequireHandlerAsyncTickPriorityCopyBinder DeclareSignalWithInterfaces<TSignal>(this DiContainer container)
|
||||
{
|
||||
Type type = typeof(TSignal);
|
||||
|
||||
var declaration = container.DeclareSignal(type);
|
||||
|
||||
Type[] interfaces = type.GetInterfaces();
|
||||
int numOfInterfaces = interfaces.Length;
|
||||
for (int i = 0; i < numOfInterfaces; i++)
|
||||
{
|
||||
container.DeclareSignal(interfaces[i]);
|
||||
}
|
||||
|
||||
return declaration;
|
||||
}
|
||||
|
||||
public static BindSignalIdToBinder<TSignal> BindSignal<TSignal>(this DiContainer container)
|
||||
{
|
||||
var signalBindInfo = new SignalBindingBindInfo(typeof(TSignal));
|
||||
|
||||
return new BindSignalIdToBinder<TSignal>(container, signalBindInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca6f0ad40fd1abc4a8fb5e8a50134aa4
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
namespace Zenject
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class SignalTickPriorityCopyBinder : SignalCopyBinder
|
||||
{
|
||||
public SignalTickPriorityCopyBinder(
|
||||
SignalDeclarationBindInfo signalBindInfo)
|
||||
{
|
||||
SignalBindInfo = signalBindInfo;
|
||||
}
|
||||
|
||||
protected SignalDeclarationBindInfo SignalBindInfo
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public SignalCopyBinder WithTickPriority(int priority)
|
||||
{
|
||||
SignalBindInfo.TickPriority = priority;
|
||||
SignalBindInfo.RunAsync = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb1dbf2ad8637f340a532132f4555abd
|
||||
timeCreated: 1529046908
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModestTree;
|
||||
#if ZEN_SIGNALS_ADD_UNIRX
|
||||
using UniRx;
|
||||
#endif
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public class SignalDeclaration : ITickable, IDisposable
|
||||
{
|
||||
readonly List<SignalSubscription> _subscriptions = new List<SignalSubscription>();
|
||||
readonly List<object> _asyncQueue = new List<object>();
|
||||
readonly BindingId _bindingId;
|
||||
readonly SignalMissingHandlerResponses _missingHandlerResponses;
|
||||
readonly bool _isAsync;
|
||||
readonly ZenjectSettings.SignalSettings _settings;
|
||||
|
||||
#if ZEN_SIGNALS_ADD_UNIRX
|
||||
readonly Subject<object> _stream = new Subject<object>();
|
||||
#endif
|
||||
|
||||
public SignalDeclaration(
|
||||
SignalDeclarationBindInfo bindInfo,
|
||||
[InjectOptional]
|
||||
ZenjectSettings zenjectSettings)
|
||||
{
|
||||
zenjectSettings = zenjectSettings ?? ZenjectSettings.Default;
|
||||
_settings = zenjectSettings.Signals ?? ZenjectSettings.SignalSettings.Default;
|
||||
|
||||
_bindingId = new BindingId(bindInfo.SignalType, bindInfo.Identifier);
|
||||
_missingHandlerResponses = bindInfo.MissingHandlerResponse;
|
||||
_isAsync = bindInfo.RunAsync;
|
||||
TickPriority = bindInfo.TickPriority;
|
||||
}
|
||||
|
||||
#if ZEN_SIGNALS_ADD_UNIRX
|
||||
public IObservable<object> Stream
|
||||
{
|
||||
get { return _stream; }
|
||||
}
|
||||
#endif
|
||||
|
||||
public List<SignalSubscription> Subscriptions => _subscriptions;
|
||||
|
||||
public int TickPriority
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public bool IsAsync
|
||||
{
|
||||
get { return _isAsync; }
|
||||
}
|
||||
|
||||
public BindingId BindingId
|
||||
{
|
||||
get { return _bindingId; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_settings.RequireStrictUnsubscribe)
|
||||
{
|
||||
Assert.That(_subscriptions.IsEmpty(),
|
||||
"Found {0} signal handlers still added to declaration {1}", _subscriptions.Count, _bindingId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We can't rely entirely on the destruction order in Unity because of
|
||||
// the fact that OnDestroy is completely unpredictable.
|
||||
// So if you have a GameObjectContext at the root level in your scene, then it
|
||||
// might be destroyed AFTER the SceneContext. So if you have some signal declarations
|
||||
// in the scene context, they might get disposed before some of the subscriptions
|
||||
// so in this case you need to disconnect from the subscription so that it doesn't
|
||||
// try to remove itself after the declaration has been destroyed
|
||||
for (int i = 0; i < _subscriptions.Count; i++)
|
||||
{
|
||||
_subscriptions[i].OnDeclarationDespawned();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Fire(object signal)
|
||||
{
|
||||
Assert.That(signal.GetType().DerivesFromOrEqual(_bindingId.Type));
|
||||
|
||||
if (_isAsync)
|
||||
{
|
||||
_asyncQueue.Add(signal);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cache the callback list to allow handlers to be added from within callbacks
|
||||
using (var block = DisposeBlock.Spawn())
|
||||
{
|
||||
var subscriptions = block.SpawnList<SignalSubscription>();
|
||||
subscriptions.AddRange(_subscriptions);
|
||||
FireInternal(subscriptions, signal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FireInternal(List<SignalSubscription> subscriptions, object signal)
|
||||
{
|
||||
if (subscriptions.IsEmpty()
|
||||
#if ZEN_SIGNALS_ADD_UNIRX
|
||||
&& !_stream.HasObservers
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (_missingHandlerResponses == SignalMissingHandlerResponses.Warn)
|
||||
{
|
||||
Log.Warn("Fired signal '{0}' but no subscriptions found! If this is intentional then either add OptionalSubscriber() to the binding or change the default in ZenjectSettings", signal.GetType());
|
||||
}
|
||||
else if (_missingHandlerResponses == SignalMissingHandlerResponses.Throw)
|
||||
{
|
||||
throw Assert.CreateException(
|
||||
"Fired signal '{0}' but no subscriptions found! If this is intentional then either add OptionalSubscriber() to the binding or change the default in ZenjectSettings", signal.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < subscriptions.Count; i++)
|
||||
{
|
||||
var subscription = subscriptions[i];
|
||||
|
||||
// This is a weird check for the very rare case where an Unsubscribe is called
|
||||
// from within the same callback (see TestSignalsAdvanced.TestSubscribeUnsubscribeInsideHandler)
|
||||
if (_subscriptions.Contains(subscription))
|
||||
{
|
||||
subscription.Invoke(signal);
|
||||
}
|
||||
}
|
||||
|
||||
#if ZEN_SIGNALS_ADD_UNIRX
|
||||
_stream.OnNext(signal);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
Assert.That(_isAsync);
|
||||
|
||||
if (!_asyncQueue.IsEmpty())
|
||||
{
|
||||
// Cache the callback list to allow handlers to be added from within callbacks
|
||||
using (var block = DisposeBlock.Spawn())
|
||||
{
|
||||
var subscriptions = block.SpawnList<SignalSubscription>();
|
||||
subscriptions.AddRange(_subscriptions);
|
||||
|
||||
// Cache the signals so that if the signal is fired again inside the handler that it
|
||||
// is not executed until next frame
|
||||
var signals = block.SpawnList<object>();
|
||||
signals.AddRange(_asyncQueue);
|
||||
|
||||
_asyncQueue.Clear();
|
||||
|
||||
for (int i = 0; i < signals.Count; i++)
|
||||
{
|
||||
FireInternal(subscriptions, signals[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(SignalSubscription subscription)
|
||||
{
|
||||
Assert.That(!_subscriptions.Contains(subscription));
|
||||
_subscriptions.Add(subscription);
|
||||
}
|
||||
|
||||
public void Remove(SignalSubscription subscription)
|
||||
{
|
||||
_subscriptions.RemoveWithConfirm(subscription);
|
||||
}
|
||||
|
||||
public class Factory : PlaceholderFactory<SignalDeclarationBindInfo, SignalDeclaration>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1246007cc9cfbc04cb83b9bde4c34995
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public class SignalSubscription : IDisposable, IPoolable<Action<object>, SignalDeclaration>
|
||||
{
|
||||
readonly Pool _pool;
|
||||
|
||||
Action<object> _callback;
|
||||
SignalDeclaration _declaration;
|
||||
BindingId _signalId;
|
||||
|
||||
public SignalSubscription(Pool pool)
|
||||
{
|
||||
_pool = pool;
|
||||
|
||||
SetDefaults();
|
||||
}
|
||||
|
||||
public BindingId SignalId
|
||||
{
|
||||
get { return _signalId; }
|
||||
}
|
||||
|
||||
public void OnSpawned(
|
||||
Action<object> callback, SignalDeclaration declaration)
|
||||
{
|
||||
Assert.IsNull(_callback);
|
||||
_callback = callback;
|
||||
_declaration = declaration;
|
||||
// Cache this in case OnDeclarationDespawned is called
|
||||
_signalId = declaration.BindingId;
|
||||
|
||||
declaration.Add(this);
|
||||
}
|
||||
|
||||
public void OnDespawned()
|
||||
{
|
||||
if (_declaration != null)
|
||||
{
|
||||
_declaration.Remove(this);
|
||||
}
|
||||
|
||||
SetDefaults();
|
||||
}
|
||||
|
||||
void SetDefaults()
|
||||
{
|
||||
_callback = null;
|
||||
_declaration = null;
|
||||
_signalId = new BindingId();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Allow calling this twice since signals automatically unsubscribe in SignalBus.LateDispose
|
||||
// and so this causes issues if users also unsubscribe in a MonoBehaviour OnDestroy on a
|
||||
// root game object
|
||||
if (!_pool.InactiveItems.Contains(this))
|
||||
{
|
||||
_pool.Despawn(this);
|
||||
}
|
||||
}
|
||||
|
||||
// See comment in SignalDeclaration for why this exists
|
||||
public void OnDeclarationDespawned()
|
||||
{
|
||||
_declaration = null;
|
||||
}
|
||||
|
||||
public void Invoke(object signal)
|
||||
{
|
||||
_callback(signal);
|
||||
}
|
||||
|
||||
public class Pool : PoolableMemoryPool<Action<object>, SignalDeclaration, SignalSubscription>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26affab6a482d904580cce7f9f1a94f4
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
public struct SignalSubscriptionId : IEquatable<SignalSubscriptionId>
|
||||
{
|
||||
BindingId _signalId;
|
||||
object _callback;
|
||||
|
||||
public SignalSubscriptionId(BindingId signalId, object callback)
|
||||
{
|
||||
_signalId = signalId;
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
public BindingId SignalId
|
||||
{
|
||||
get { return _signalId; }
|
||||
}
|
||||
|
||||
public object Callback
|
||||
{
|
||||
get { return _callback; }
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked // Overflow is fine, just wrap
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 29 + _signalId.GetHashCode();
|
||||
hash = hash * 29 + _callback.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object that)
|
||||
{
|
||||
if (that is SignalSubscriptionId)
|
||||
{
|
||||
return Equals((SignalSubscriptionId)that);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(SignalSubscriptionId that)
|
||||
{
|
||||
return Equals(_signalId, that._signalId)
|
||||
&& Equals(Callback, that.Callback);
|
||||
}
|
||||
|
||||
public static bool operator == (SignalSubscriptionId left, SignalSubscriptionId right)
|
||||
{
|
||||
return left.Equals(right);
|
||||
}
|
||||
|
||||
public static bool operator != (SignalSubscriptionId left, SignalSubscriptionId right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ebf6df7998e59b4393ef46553665ba2
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ebb190b1462cf04478644ba25fb51df0
|
||||
folderAsset: yes
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,450 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ModestTree;
|
||||
#if ZEN_SIGNALS_ADD_UNIRX
|
||||
using UniRx;
|
||||
#endif
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public class SignalBus : ILateDisposable
|
||||
{
|
||||
readonly SignalSubscription.Pool _subscriptionPool;
|
||||
readonly Dictionary<BindingId, SignalDeclaration> _localDeclarationMap = new Dictionary<BindingId, SignalDeclaration>();
|
||||
readonly SignalBus _parentBus;
|
||||
readonly Dictionary<SignalSubscriptionId, SignalSubscription> _subscriptionMap = new Dictionary<SignalSubscriptionId, SignalSubscription>();
|
||||
readonly ZenjectSettings.SignalSettings _settings;
|
||||
readonly SignalDeclaration.Factory _signalDeclarationFactory;
|
||||
readonly DiContainer _container;
|
||||
|
||||
public SignalBus(
|
||||
[Inject(Source = InjectSources.Local)]
|
||||
List<SignalDeclaration> signalDeclarations,
|
||||
[Inject(Source = InjectSources.Parent, Optional = true)]
|
||||
SignalBus parentBus,
|
||||
[InjectOptional]
|
||||
ZenjectSettings zenjectSettings,
|
||||
SignalSubscription.Pool subscriptionPool,
|
||||
SignalDeclaration.Factory signalDeclarationFactory,
|
||||
DiContainer container)
|
||||
{
|
||||
_subscriptionPool = subscriptionPool;
|
||||
zenjectSettings = zenjectSettings ?? ZenjectSettings.Default;
|
||||
_settings = zenjectSettings.Signals ?? ZenjectSettings.SignalSettings.Default;
|
||||
_signalDeclarationFactory = signalDeclarationFactory;
|
||||
_container = container;
|
||||
|
||||
signalDeclarations.ForEach(x =>
|
||||
{
|
||||
if (!_localDeclarationMap.ContainsKey(x.BindingId))
|
||||
{
|
||||
_localDeclarationMap.Add(x.BindingId, x);
|
||||
}
|
||||
else _localDeclarationMap[x.BindingId].Subscriptions.AllocFreeAddRange(x.Subscriptions);
|
||||
});
|
||||
_parentBus = parentBus;
|
||||
}
|
||||
|
||||
public SignalBus ParentBus
|
||||
{
|
||||
get { return _parentBus; }
|
||||
}
|
||||
|
||||
public int NumSubscribers
|
||||
{
|
||||
get { return _subscriptionMap.Count; }
|
||||
}
|
||||
|
||||
|
||||
//Fires Signals with their interfaces
|
||||
public void AbstractFire<TSignal>() where TSignal : new() => AbstractFire(new TSignal());
|
||||
public void AbstractFire<TSignal>(TSignal signal) => AbstractFireId(null, signal);
|
||||
public void AbstractFireId<TSignal>(object identifier, TSignal signal)
|
||||
{
|
||||
// Do this before creating the signal so that it throws if the signal was not declared
|
||||
Type signalType = typeof(TSignal);
|
||||
InternalFire(signalType, signal, identifier, true);
|
||||
|
||||
Type[] interfaces = signalType.GetInterfaces();
|
||||
int numOfInterfaces = interfaces.Length;
|
||||
for (int i = 0; i < numOfInterfaces; i++)
|
||||
{
|
||||
InternalFire(interfaces[i], signal, identifier, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void LateDispose()
|
||||
{
|
||||
if (_settings.RequireStrictUnsubscribe)
|
||||
{
|
||||
if (!_subscriptionMap.IsEmpty())
|
||||
{
|
||||
throw Assert.CreateException(
|
||||
"Found subscriptions for signals '{0}' in SignalBus.LateDispose! Either add the explicit Unsubscribe or set SignalSettings.AutoUnsubscribeInDispose to true",
|
||||
_subscriptionMap.Values.Select(x => x.SignalId.ToString()).Join(", "));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var subscription in _subscriptionMap.Values)
|
||||
{
|
||||
subscription.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var declaration in _localDeclarationMap.Values)
|
||||
{
|
||||
declaration.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void FireId<TSignal>(object identifier, TSignal signal)
|
||||
{
|
||||
InternalFire(typeof(TSignal), signal, identifier, true);
|
||||
}
|
||||
|
||||
public void Fire<TSignal>(TSignal signal)
|
||||
{
|
||||
FireId<TSignal>(null, signal);
|
||||
}
|
||||
|
||||
public void FireId<TSignal>(object identifier)
|
||||
{
|
||||
InternalFire(typeof(TSignal), null, identifier, true);
|
||||
}
|
||||
|
||||
public void Fire<TSignal>()
|
||||
{
|
||||
FireId<TSignal>(null);
|
||||
}
|
||||
|
||||
public void FireId(object identifier, object signal)
|
||||
{
|
||||
InternalFire(signal.GetType(), signal, identifier, true);
|
||||
}
|
||||
|
||||
public void Fire(object signal)
|
||||
{
|
||||
FireId(null, signal);
|
||||
}
|
||||
|
||||
public bool IsSignalDeclared<TSignal>()
|
||||
{
|
||||
return IsSignalDeclared(typeof(TSignal), null);
|
||||
}
|
||||
|
||||
public bool IsSignalDeclared<TSignal>(object identifier)
|
||||
{
|
||||
return IsSignalDeclared(typeof(TSignal), identifier);
|
||||
}
|
||||
|
||||
public bool IsSignalDeclared(Type signalType)
|
||||
{
|
||||
return IsSignalDeclared(signalType, null);
|
||||
}
|
||||
|
||||
public bool IsSignalDeclared(Type signalType, object identifier)
|
||||
{
|
||||
var signalId = new BindingId(signalType, identifier);
|
||||
return GetDeclaration(signalId) != null;
|
||||
}
|
||||
|
||||
public void TryFireId<TSignal>(object identifier, TSignal signal)
|
||||
{
|
||||
InternalFire(typeof(TSignal), signal, identifier, false);
|
||||
}
|
||||
|
||||
public void TryFire<TSignal>(TSignal signal)
|
||||
{
|
||||
TryFireId<TSignal>(null, signal);
|
||||
}
|
||||
|
||||
public void TryFireId<TSignal>(object identifier)
|
||||
{
|
||||
InternalFire(typeof(TSignal), null, identifier, false);
|
||||
}
|
||||
|
||||
public void TryFire<TSignal>()
|
||||
{
|
||||
TryFireId<TSignal>(null);
|
||||
}
|
||||
|
||||
public void TryFireId(object identifier, object signal)
|
||||
{
|
||||
InternalFire(signal.GetType(), signal, identifier, false);
|
||||
}
|
||||
|
||||
public void TryFire(object signal)
|
||||
{
|
||||
TryFireId(null, signal);
|
||||
}
|
||||
|
||||
private void InternalFire(Type signalType, object signal, object identifier, bool requireDeclaration)
|
||||
{
|
||||
var signalId = new BindingId(signalType, identifier);
|
||||
|
||||
// Do this before creating the signal so that it throws if the signal was not declared
|
||||
var declaration = GetDeclaration(signalId);
|
||||
|
||||
if (declaration == null)
|
||||
{
|
||||
if (requireDeclaration)
|
||||
{
|
||||
throw Assert.CreateException("Fired undeclared signal '{0}'!", signalId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (signal == null)
|
||||
{
|
||||
signal = Activator.CreateInstance(signalType);
|
||||
}
|
||||
|
||||
declaration.Fire(signal);
|
||||
}
|
||||
}
|
||||
|
||||
#if ZEN_SIGNALS_ADD_UNIRX
|
||||
public IObservable<TSignal> GetStreamId<TSignal>(object identifier)
|
||||
{
|
||||
return GetStreamId(typeof(TSignal), identifier).Select(x => (TSignal)x);
|
||||
}
|
||||
|
||||
public IObservable<TSignal> GetStream<TSignal>()
|
||||
{
|
||||
return GetStreamId<TSignal>(null);
|
||||
}
|
||||
|
||||
public IObservable<object> GetStreamId(Type signalType, object identifier)
|
||||
{
|
||||
return GetDeclaration(new BindingId(signalType, identifier)).Stream;
|
||||
}
|
||||
|
||||
public IObservable<object> GetStream(Type signalType)
|
||||
{
|
||||
return GetStreamId(signalType, null);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void SubscribeId<TSignal>(object identifier, Action callback)
|
||||
{
|
||||
Action<object> wrapperCallback = args => callback();
|
||||
SubscribeInternal(typeof(TSignal), identifier, callback, wrapperCallback);
|
||||
}
|
||||
|
||||
public void Subscribe<TSignal>(Action callback)
|
||||
{
|
||||
SubscribeId<TSignal>(null, callback);
|
||||
}
|
||||
|
||||
public void SubscribeId<TSignal>(object identifier, Action<TSignal> callback)
|
||||
{
|
||||
Action<object> wrapperCallback = args => callback((TSignal)args);
|
||||
SubscribeInternal(typeof(TSignal), identifier, callback, wrapperCallback);
|
||||
}
|
||||
|
||||
public void Subscribe<TSignal>(Action<TSignal> callback)
|
||||
{
|
||||
SubscribeId<TSignal>(null, callback);
|
||||
}
|
||||
|
||||
public void SubscribeId(Type signalType, object identifier, Action<object> callback)
|
||||
{
|
||||
SubscribeInternal(signalType, identifier, callback, callback);
|
||||
}
|
||||
|
||||
public void Subscribe(Type signalType, Action<object> callback)
|
||||
{
|
||||
SubscribeId(signalType, null, callback);
|
||||
}
|
||||
|
||||
public void UnsubscribeId<TSignal>(object identifier, Action callback)
|
||||
{
|
||||
UnsubscribeId(typeof(TSignal), identifier, callback);
|
||||
}
|
||||
|
||||
public void Unsubscribe<TSignal>(Action callback)
|
||||
{
|
||||
UnsubscribeId<TSignal>(null, callback);
|
||||
}
|
||||
|
||||
public void UnsubscribeId(Type signalType, object identifier, Action callback)
|
||||
{
|
||||
UnsubscribeInternal(signalType, identifier, callback, true);
|
||||
}
|
||||
|
||||
public void Unsubscribe(Type signalType, Action callback)
|
||||
{
|
||||
UnsubscribeId(signalType, null, callback);
|
||||
}
|
||||
|
||||
public void UnsubscribeId(Type signalType, object identifier, Action<object> callback)
|
||||
{
|
||||
UnsubscribeInternal(signalType, identifier, callback, true);
|
||||
}
|
||||
|
||||
public void Unsubscribe(Type signalType, Action<object> callback)
|
||||
{
|
||||
UnsubscribeId(signalType, null, callback);
|
||||
}
|
||||
|
||||
public void UnsubscribeId<TSignal>(object identifier, Action<TSignal> callback)
|
||||
{
|
||||
UnsubscribeInternal(typeof(TSignal), identifier, callback, true);
|
||||
}
|
||||
|
||||
public void Unsubscribe<TSignal>(Action<TSignal> callback)
|
||||
{
|
||||
UnsubscribeId<TSignal>(null, callback);
|
||||
}
|
||||
|
||||
public void TryUnsubscribeId<TSignal>(object identifier, Action callback)
|
||||
{
|
||||
UnsubscribeInternal(typeof(TSignal), identifier, callback, false);
|
||||
}
|
||||
|
||||
public void TryUnsubscribe<TSignal>(Action callback)
|
||||
{
|
||||
TryUnsubscribeId<TSignal>(null, callback);
|
||||
}
|
||||
|
||||
public void TryUnsubscribeId(Type signalType, object identifier, Action callback)
|
||||
{
|
||||
UnsubscribeInternal(signalType, identifier, callback, false);
|
||||
}
|
||||
|
||||
public void TryUnsubscribe(Type signalType, Action callback)
|
||||
{
|
||||
TryUnsubscribeId(signalType, null, callback);
|
||||
}
|
||||
|
||||
public void TryUnsubscribeId(Type signalType, object identifier, Action<object> callback)
|
||||
{
|
||||
UnsubscribeInternal(signalType, identifier, callback, false);
|
||||
}
|
||||
|
||||
public void TryUnsubscribe(Type signalType, Action<object> callback)
|
||||
{
|
||||
TryUnsubscribeId(signalType, null, callback);
|
||||
}
|
||||
|
||||
public void TryUnsubscribeId<TSignal>(object identifier, Action<TSignal> callback)
|
||||
{
|
||||
UnsubscribeInternal(typeof(TSignal), identifier, callback, false);
|
||||
}
|
||||
|
||||
public void TryUnsubscribe<TSignal>(Action<TSignal> callback)
|
||||
{
|
||||
TryUnsubscribeId<TSignal>(null, callback);
|
||||
}
|
||||
|
||||
void UnsubscribeInternal(Type signalType, object identifier, object token, bool throwIfMissing)
|
||||
{
|
||||
UnsubscribeInternal(new BindingId(signalType, identifier), token, throwIfMissing);
|
||||
}
|
||||
|
||||
void UnsubscribeInternal(BindingId signalId, object token, bool throwIfMissing)
|
||||
{
|
||||
UnsubscribeInternal(
|
||||
new SignalSubscriptionId(signalId, token), throwIfMissing);
|
||||
}
|
||||
|
||||
void UnsubscribeInternal(SignalSubscriptionId id, bool throwIfMissing)
|
||||
{
|
||||
SignalSubscription subscription;
|
||||
|
||||
if (_subscriptionMap.TryGetValue(id, out subscription))
|
||||
{
|
||||
_subscriptionMap.RemoveWithConfirm(id);
|
||||
subscription.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (throwIfMissing)
|
||||
{
|
||||
throw Assert.CreateException(
|
||||
"Called unsubscribe for signal '{0}' but could not find corresponding subscribe. If this is intentional, call TryUnsubscribe instead.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SubscribeInternal(Type signalType, object identifier, object token, Action<object> callback)
|
||||
{
|
||||
SubscribeInternal(new BindingId(signalType, identifier), token, callback);
|
||||
}
|
||||
|
||||
void SubscribeInternal(BindingId signalId, object token, Action<object> callback)
|
||||
{
|
||||
SubscribeInternal(
|
||||
new SignalSubscriptionId(signalId, token), callback);
|
||||
}
|
||||
|
||||
void SubscribeInternal(SignalSubscriptionId id, Action<object> callback)
|
||||
{
|
||||
Assert.That(!_subscriptionMap.ContainsKey(id),
|
||||
"Tried subscribing to the same signal with the same callback on Zenject.SignalBus");
|
||||
|
||||
var declaration = GetDeclaration(id.SignalId);
|
||||
|
||||
if (declaration == null)
|
||||
{
|
||||
throw Assert.CreateException("Tried subscribing to undeclared signal '{0}'!", id.SignalId);
|
||||
}
|
||||
|
||||
var subscription = _subscriptionPool.Spawn(callback, declaration);
|
||||
|
||||
_subscriptionMap.Add(id, subscription);
|
||||
}
|
||||
|
||||
public void DeclareSignal<T>(
|
||||
object identifier = null, SignalMissingHandlerResponses? missingHandlerResponse = null, bool? forceAsync = null, int? asyncTickPriority = null)
|
||||
{
|
||||
DeclareSignal(typeof(T), identifier, missingHandlerResponse, forceAsync, asyncTickPriority);
|
||||
}
|
||||
|
||||
public void DeclareSignal(
|
||||
Type signalType, object identifier = null, SignalMissingHandlerResponses? missingHandlerResponse = null, bool? forceAsync = null, int? asyncTickPriority = null)
|
||||
{
|
||||
var bindInfo = SignalExtensions.CreateDefaultSignalDeclarationBindInfo(_container, signalType);
|
||||
|
||||
bindInfo.Identifier = identifier;
|
||||
|
||||
if (missingHandlerResponse.HasValue)
|
||||
{
|
||||
bindInfo.Identifier = missingHandlerResponse.Value;
|
||||
}
|
||||
|
||||
if (forceAsync.HasValue)
|
||||
{
|
||||
bindInfo.RunAsync = forceAsync.Value;
|
||||
}
|
||||
|
||||
if (asyncTickPriority.HasValue)
|
||||
{
|
||||
bindInfo.TickPriority = asyncTickPriority.Value;
|
||||
}
|
||||
|
||||
var declaration = _signalDeclarationFactory.Create(bindInfo);
|
||||
|
||||
_localDeclarationMap.Add(declaration.BindingId, declaration);
|
||||
}
|
||||
|
||||
SignalDeclaration GetDeclaration(BindingId signalId)
|
||||
{
|
||||
SignalDeclaration handler;
|
||||
|
||||
if (_localDeclarationMap.TryGetValue(signalId, out handler))
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
|
||||
if (_parentBus != null)
|
||||
{
|
||||
return _parentBus.GetDeclaration(signalId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d457d0e45e1d3c54f9bc2bc3aece1760
|
||||
timeCreated: 1521266917
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// Note that you only need to install this once
|
||||
public class SignalBusInstaller : Installer<SignalBusInstaller>
|
||||
{
|
||||
public override void InstallBindings()
|
||||
{
|
||||
Assert.That(!Container.HasBinding<SignalBus>(), "Detected multiple SignalBus bindings. SignalBusInstaller should only be installed once");
|
||||
|
||||
Container.BindInterfacesAndSelfTo<SignalBus>().AsSingle().CopyIntoAllSubContainers();
|
||||
|
||||
Container.BindInterfacesTo<SignalDeclarationAsyncInitializer>().AsSingle().CopyIntoAllSubContainers();
|
||||
|
||||
Container.BindMemoryPool<SignalSubscription, SignalSubscription.Pool>();
|
||||
|
||||
// Dispose last to ensure that we don't remove SignalSubscription before the user does
|
||||
Container.BindLateDisposableExecutionOrder<SignalBus>(-999);
|
||||
|
||||
Container.BindFactory<SignalDeclarationBindInfo, SignalDeclaration, SignalDeclaration.Factory>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2afd112e630107f458140fbe19d4e31c
|
||||
timeCreated: 1528988907
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// This class just exists to solve a circular dependency that would otherwise happen if we
|
||||
// attempted to inject TickableManager into either SignalDeclaration or SignalBus
|
||||
// And we need to directly depend on TickableManager because we need each SignalDeclaration
|
||||
// to have a unique tick priority
|
||||
public class SignalDeclarationAsyncInitializer : IInitializable
|
||||
{
|
||||
readonly LazyInject<TickableManager> _tickManager;
|
||||
readonly List<SignalDeclaration> _declarations;
|
||||
|
||||
public SignalDeclarationAsyncInitializer(
|
||||
[Inject(Source = InjectSources.Local)]
|
||||
List<SignalDeclaration> declarations,
|
||||
[Inject(Optional = true, Source = InjectSources.Local)]
|
||||
LazyInject<TickableManager> tickManager)
|
||||
{
|
||||
_declarations = declarations;
|
||||
_tickManager = tickManager;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
for (int i = 0; i < _declarations.Count; i++)
|
||||
{
|
||||
var declaration = _declarations[i];
|
||||
|
||||
if (declaration.IsAsync)
|
||||
{
|
||||
Assert.IsNotNull(_tickManager.Value, "TickableManager is required when using asynchronous signals");
|
||||
_tickManager.Value.Add(declaration, declaration.TickPriority);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8d0040c0a3734b49b26f7cdaa86c5e8
|
||||
timeCreated: 1529153251
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user