Update Project
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
public struct BindingId : IEquatable<BindingId>
|
||||
{
|
||||
Type _type;
|
||||
object _identifier;
|
||||
|
||||
public BindingId(Type type, object identifier)
|
||||
{
|
||||
_type = type;
|
||||
_identifier = identifier;
|
||||
}
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get { return _type; }
|
||||
set { _type = value; }
|
||||
}
|
||||
|
||||
public object Identifier
|
||||
{
|
||||
get { return _identifier; }
|
||||
set { _identifier = value; }
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (_identifier == null)
|
||||
{
|
||||
return _type.PrettyName();
|
||||
}
|
||||
|
||||
return "{0} (ID: {1})".Fmt(_type, _identifier);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked // Overflow is fine, just wrap
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 29 + _type.GetHashCode();
|
||||
hash = hash * 29 + (_identifier == null ? 0 : _identifier.GetHashCode());
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
if (other is BindingId)
|
||||
{
|
||||
BindingId otherId = (BindingId)other;
|
||||
return otherId == this;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Equals(BindingId that)
|
||||
{
|
||||
return this == that;
|
||||
}
|
||||
|
||||
public static bool operator ==(BindingId left, BindingId right)
|
||||
{
|
||||
return left.Type == right.Type && Equals(left.Identifier, right.Identifier);
|
||||
}
|
||||
|
||||
public static bool operator !=(BindingId left, BindingId right)
|
||||
{
|
||||
return !left.Equals(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 05e8238358230bf4e9cbb692280d28f1
|
||||
timeCreated: 1461708048
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de4283f91e0232a4897afd2a0af141bc
|
||||
timeCreated: 1461708054
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// You can optionally inject this interface into your classes/factories
|
||||
// rather than using DiContainer which contains many methods you might not need
|
||||
public interface IInstantiator
|
||||
{
|
||||
// Use this method to create any non-monobehaviour
|
||||
// Any fields marked [Inject] will be set using the bindings on the container
|
||||
// Any methods marked with a [Inject] will be called
|
||||
// Any constructor parameters will be filled in with values from the container
|
||||
T Instantiate<T>();
|
||||
T Instantiate<T>(IEnumerable<object> extraArgs);
|
||||
|
||||
object Instantiate(Type concreteType);
|
||||
object Instantiate(Type concreteType, IEnumerable<object> extraArgs);
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
|
||||
// Add new component to existing game object and fill in its dependencies
|
||||
// NOTE: Gameobject here is not a prefab prototype, it is an instance
|
||||
TContract InstantiateComponent<TContract>(GameObject gameObject)
|
||||
where TContract : Component;
|
||||
TContract InstantiateComponent<TContract>(
|
||||
GameObject gameObject, IEnumerable<object> extraArgs)
|
||||
where TContract : Component;
|
||||
Component InstantiateComponent(
|
||||
Type componentType, GameObject gameObject);
|
||||
Component InstantiateComponent(
|
||||
Type componentType, GameObject gameObject, IEnumerable<object> extraArgs);
|
||||
|
||||
T InstantiateComponentOnNewGameObject<T>()
|
||||
where T : Component;
|
||||
T InstantiateComponentOnNewGameObject<T>(string gameObjectName)
|
||||
where T : Component;
|
||||
T InstantiateComponentOnNewGameObject<T>(IEnumerable<object> extraArgs)
|
||||
where T : Component;
|
||||
T InstantiateComponentOnNewGameObject<T>(string gameObjectName, IEnumerable<object> extraArgs)
|
||||
where T : Component;
|
||||
|
||||
// Create a new game object from a prefab and fill in dependencies for all children
|
||||
GameObject InstantiatePrefab(UnityEngine.Object prefab);
|
||||
GameObject InstantiatePrefab(
|
||||
UnityEngine.Object prefab, Transform parentTransform);
|
||||
GameObject InstantiatePrefab(
|
||||
UnityEngine.Object prefab, Vector3 position, Quaternion rotation, Transform parentTransform);
|
||||
|
||||
// Create a new game object from a resource path and fill in dependencies for all children
|
||||
GameObject InstantiatePrefabResource(string resourcePath);
|
||||
GameObject InstantiatePrefabResource(
|
||||
string resourcePath, Transform parentTransform);
|
||||
GameObject InstantiatePrefabResource(
|
||||
string resourcePath, Vector3 position, Quaternion rotation, Transform parentTransform);
|
||||
|
||||
// Same as InstantiatePrefab but returns a component after it's initialized
|
||||
// and optionally allows extra arguments for the given component type
|
||||
T InstantiatePrefabForComponent<T>(UnityEngine.Object prefab);
|
||||
T InstantiatePrefabForComponent<T>(
|
||||
UnityEngine.Object prefab, IEnumerable<object> extraArgs);
|
||||
T InstantiatePrefabForComponent<T>(
|
||||
UnityEngine.Object prefab, Transform parentTransform);
|
||||
T InstantiatePrefabForComponent<T>(
|
||||
UnityEngine.Object prefab, Transform parentTransform, IEnumerable<object> extraArgs);
|
||||
T InstantiatePrefabForComponent<T>(
|
||||
UnityEngine.Object prefab, Vector3 position, Quaternion rotation, Transform parentTransform);
|
||||
T InstantiatePrefabForComponent<T>(
|
||||
UnityEngine.Object prefab, Vector3 position, Quaternion rotation, Transform parentTransform, IEnumerable<object> extraArgs);
|
||||
object InstantiatePrefabForComponent(
|
||||
Type concreteType, UnityEngine.Object prefab, Transform parentTransform, IEnumerable<object> extraArgs);
|
||||
|
||||
// Same as InstantiatePrefabResource but returns a component after it's initialized
|
||||
// and optionally allows extra arguments for the given component type
|
||||
T InstantiatePrefabResourceForComponent<T>(string resourcePath);
|
||||
T InstantiatePrefabResourceForComponent<T>(
|
||||
string resourcePath, IEnumerable<object> extraArgs);
|
||||
T InstantiatePrefabResourceForComponent<T>(
|
||||
string resourcePath, Transform parentTransform);
|
||||
T InstantiatePrefabResourceForComponent<T>(
|
||||
string resourcePath, Transform parentTransform, IEnumerable<object> extraArgs);
|
||||
T InstantiatePrefabResourceForComponent<T>(
|
||||
string resourcePath, Vector3 position, Quaternion rotation, Transform parentTransform);
|
||||
T InstantiatePrefabResourceForComponent<T>(
|
||||
string resourcePath, Vector3 position, Quaternion rotation, Transform parentTransform, IEnumerable<object> extraArgs);
|
||||
object InstantiatePrefabResourceForComponent(
|
||||
Type concreteType, string resourcePath, Transform parentTransform, IEnumerable<object> extraArgs);
|
||||
|
||||
T InstantiateScriptableObjectResource<T>(string resourcePath)
|
||||
where T : ScriptableObject;
|
||||
T InstantiateScriptableObjectResource<T>(
|
||||
string resourcePath, IEnumerable<object> extraArgs)
|
||||
where T : ScriptableObject;
|
||||
object InstantiateScriptableObjectResource(
|
||||
Type scriptableObjectType, string resourcePath);
|
||||
object InstantiateScriptableObjectResource(
|
||||
Type scriptableObjectType, string resourcePath, IEnumerable<object> extraArgs);
|
||||
|
||||
GameObject CreateEmptyGameObject(string name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27acc83df7708be4185afec9bd506165
|
||||
timeCreated: 1523188912
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
// When the app starts up, typically there is a list of instances that need to be injected
|
||||
// The question is, what is the order that they should be injected? Originally we would
|
||||
// just iterate over the list and inject in whatever order they were in
|
||||
// What is better than that though, is to inject based on their dependency order
|
||||
// So if A depends on B then it would be nice if B was always injected before A
|
||||
// That way, in [Inject] methods for A, A can access members on B knowing that it's
|
||||
// already been initialized.
|
||||
// So in order to do this, we add the initial pool of instances to this class then
|
||||
// notify this class whenever an instance is resolved via a FromInstance binding
|
||||
// That way we can lazily call inject on-demand whenever the instance is requested
|
||||
[NoReflectionBaking]
|
||||
public class LazyInstanceInjector
|
||||
{
|
||||
readonly DiContainer _container;
|
||||
readonly HashSet<object> _instancesToInject = new HashSet<object>();
|
||||
|
||||
public LazyInstanceInjector(DiContainer container)
|
||||
{
|
||||
_container = container;
|
||||
}
|
||||
|
||||
public IEnumerable<object> Instances
|
||||
{
|
||||
get { return _instancesToInject; }
|
||||
}
|
||||
|
||||
public void AddInstance(object instance)
|
||||
{
|
||||
_instancesToInject.Add(instance);
|
||||
}
|
||||
|
||||
public void AddInstances(IEnumerable<object> instances)
|
||||
{
|
||||
_instancesToInject.UnionWith(instances);
|
||||
}
|
||||
|
||||
public void LazyInject(object instance)
|
||||
{
|
||||
if (_instancesToInject.Remove(instance))
|
||||
{
|
||||
_container.Inject(instance);
|
||||
}
|
||||
}
|
||||
|
||||
public void LazyInjectAll()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
using (ProfileBlock.Start("Zenject.LazyInstanceInjector.LazyInjectAll"))
|
||||
#endif
|
||||
{
|
||||
var tempList = new List<object>();
|
||||
|
||||
while (!_instancesToInject.IsEmpty())
|
||||
{
|
||||
tempList.Clear();
|
||||
tempList.AddRange(_instancesToInject);
|
||||
|
||||
foreach (var instance in tempList)
|
||||
{
|
||||
// We use LazyInject instead of calling _container.inject directly
|
||||
// Because it might have already been lazily injected
|
||||
// as a result of a previous call to inject
|
||||
LazyInject(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7bd2a03033e83a4c9dab4d27166b412
|
||||
timeCreated: 1476651829
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject.Internal
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class LookupId
|
||||
{
|
||||
public IProvider Provider;
|
||||
public BindingId BindingId;
|
||||
|
||||
public LookupId()
|
||||
{
|
||||
}
|
||||
|
||||
public LookupId(IProvider provider, BindingId bindingId)
|
||||
{
|
||||
Assert.IsNotNull(provider);
|
||||
Assert.IsNotNull(bindingId);
|
||||
|
||||
Provider = provider;
|
||||
BindingId = bindingId;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 23 + Provider.GetHashCode();
|
||||
hash = hash * 23 + BindingId.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Provider = null;
|
||||
BindingId.Type = null;
|
||||
BindingId.Identifier = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75d6ff51a82574249bd77fb5fd40d948
|
||||
timeCreated: 1535860932
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ModestTree;
|
||||
|
||||
namespace Zenject.Internal
|
||||
{
|
||||
[NoReflectionBaking]
|
||||
public class SingletonMarkRegistry
|
||||
{
|
||||
readonly HashSet<Type> _boundSingletons = new HashSet<Type>();
|
||||
readonly HashSet<Type> _boundNonSingletons = new HashSet<Type>();
|
||||
|
||||
public void MarkNonSingleton(Type type)
|
||||
{
|
||||
Assert.That(!_boundSingletons.Contains(type),
|
||||
"Found multiple creation bindings for type '{0}' in addition to AsSingle. The AsSingle binding must be the definitive creation binding. If this is intentional, use AsCached instead of AsSingle.", type);
|
||||
_boundNonSingletons.Add(type);
|
||||
}
|
||||
|
||||
public void MarkSingleton(Type type)
|
||||
{
|
||||
bool added = _boundSingletons.Add(type);
|
||||
Assert.That(added, "Attempted to use AsSingle multiple times for type '{0}'. As of Zenject 6+, AsSingle as can no longer be used for the same type across different bindings. See the upgrade guide for details.", type);
|
||||
|
||||
Assert.That(!_boundNonSingletons.Contains(type),
|
||||
"Found multiple creation bindings for type '{0}' in addition to AsSingle. The AsSingle binding must be the definitive creation binding. If this is intentional, use AsCached instead of AsSingle.", type);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3844511961cf2ee40948fbe1569a2f31
|
||||
timeCreated: 1520759760
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
#if !NOT_UNITY3D
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
namespace Zenject
|
||||
{
|
||||
public enum ValidationErrorResponses
|
||||
{
|
||||
Log,
|
||||
Throw
|
||||
}
|
||||
|
||||
public enum RootResolveMethods
|
||||
{
|
||||
NonLazyOnly,
|
||||
All
|
||||
}
|
||||
|
||||
public enum SignalDefaultSyncModes
|
||||
{
|
||||
Synchronous,
|
||||
Asynchronous
|
||||
}
|
||||
|
||||
public enum SignalMissingHandlerResponses
|
||||
{
|
||||
Ignore,
|
||||
Throw,
|
||||
Warn
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[ZenjectAllowDuringValidation]
|
||||
[NoReflectionBaking]
|
||||
public class ZenjectSettings
|
||||
{
|
||||
public static ZenjectSettings Default = new ZenjectSettings();
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
bool _ensureDeterministicDestructionOrderOnApplicationQuit;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
bool _displayWarningWhenResolvingDuringInstall;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
RootResolveMethods _validationRootResolveMethod;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
ValidationErrorResponses _validationErrorResponse;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
SignalSettings _signalSettings;
|
||||
|
||||
public ZenjectSettings(
|
||||
ValidationErrorResponses validationErrorResponse,
|
||||
RootResolveMethods validationRootResolveMethod = RootResolveMethods.NonLazyOnly,
|
||||
bool displayWarningWhenResolvingDuringInstall = true,
|
||||
bool ensureDeterministicDestructionOrderOnApplicationQuit = false,
|
||||
SignalSettings signalSettings = null)
|
||||
{
|
||||
_validationErrorResponse = validationErrorResponse;
|
||||
_validationRootResolveMethod = validationRootResolveMethod;
|
||||
_displayWarningWhenResolvingDuringInstall = displayWarningWhenResolvingDuringInstall;
|
||||
_ensureDeterministicDestructionOrderOnApplicationQuit =ensureDeterministicDestructionOrderOnApplicationQuit;
|
||||
_signalSettings = signalSettings ?? SignalSettings.Default;
|
||||
}
|
||||
|
||||
// Need to define an emtpy constructor since this is created by unity serialization
|
||||
// even if the above constructor has defaults for all
|
||||
public ZenjectSettings()
|
||||
: this(ValidationErrorResponses.Log)
|
||||
{
|
||||
}
|
||||
|
||||
public SignalSettings Signals
|
||||
{
|
||||
get { return _signalSettings; }
|
||||
}
|
||||
|
||||
// Setting this to Log can be more useful because it will print out
|
||||
// multiple validation errors at once so you can fix multiple problems before
|
||||
// attempting validation again
|
||||
public ValidationErrorResponses ValidationErrorResponse
|
||||
{
|
||||
get { return _validationErrorResponse; }
|
||||
}
|
||||
|
||||
// Settings this to true will ensure that every binding in the container can be
|
||||
// instantiated with all its dependencies, and not just those bindings that will be
|
||||
// constructed as part of the object graph generated from the nonlazy bindings
|
||||
public RootResolveMethods ValidationRootResolveMethod
|
||||
{
|
||||
get { return _validationRootResolveMethod; }
|
||||
}
|
||||
|
||||
public bool DisplayWarningWhenResolvingDuringInstall
|
||||
{
|
||||
get { return _displayWarningWhenResolvingDuringInstall; }
|
||||
}
|
||||
|
||||
// When this is set to true and the application is exitted, all the scenes will be
|
||||
// destroyed in the reverse order in which they were loaded, and then the project context
|
||||
// will be destroyed last
|
||||
// When this is set to false (the default) the order that this occurs in is not predictable
|
||||
// It is set to false by default because manually destroying objects during OnApplicationQuit
|
||||
// event can cause crashes on android (see github issue #468)
|
||||
public bool EnsureDeterministicDestructionOrderOnApplicationQuit
|
||||
{
|
||||
get { return _ensureDeterministicDestructionOrderOnApplicationQuit; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SignalSettings
|
||||
{
|
||||
public static SignalSettings Default = new SignalSettings();
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
SignalDefaultSyncModes _defaultSyncMode;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
SignalMissingHandlerResponses _missingHandlerDefaultResponse;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
bool _requireStrictUnsubscribe;
|
||||
|
||||
#if !NOT_UNITY3D
|
||||
[SerializeField]
|
||||
#endif
|
||||
int _defaultAsyncTickPriority;
|
||||
|
||||
public SignalSettings(
|
||||
SignalDefaultSyncModes defaultSyncMode,
|
||||
SignalMissingHandlerResponses missingHandlerDefaultResponse = SignalMissingHandlerResponses.Warn,
|
||||
bool requireStrictUnsubscribe = false,
|
||||
// Run right after all the unspecified tick priorities so that the effects of the
|
||||
// signal are handled during the same frame when they are triggered
|
||||
int defaultAsyncTickPriority = 1)
|
||||
{
|
||||
_defaultSyncMode = defaultSyncMode;
|
||||
_missingHandlerDefaultResponse = missingHandlerDefaultResponse;
|
||||
_requireStrictUnsubscribe = requireStrictUnsubscribe;
|
||||
_defaultAsyncTickPriority = defaultAsyncTickPriority;
|
||||
}
|
||||
|
||||
// Need to define an emtpy constructor since this is created by unity serialization
|
||||
// even if the above constructor has defaults for all
|
||||
public SignalSettings()
|
||||
: this(SignalDefaultSyncModes.Synchronous)
|
||||
{
|
||||
}
|
||||
|
||||
public int DefaultAsyncTickPriority
|
||||
{
|
||||
get { return _defaultAsyncTickPriority; }
|
||||
}
|
||||
|
||||
public SignalDefaultSyncModes DefaultSyncMode
|
||||
{
|
||||
get { return _defaultSyncMode; }
|
||||
}
|
||||
|
||||
public SignalMissingHandlerResponses MissingHandlerDefaultResponse
|
||||
{
|
||||
get { return _missingHandlerDefaultResponse; }
|
||||
}
|
||||
|
||||
public bool RequireStrictUnsubscribe
|
||||
{
|
||||
get { return _requireStrictUnsubscribe; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1581703805dca9046a9197095cbbf3d1
|
||||
timeCreated: 1527493251
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user