Database Improvements
Brought in all the myriad improvements to the database tools from the Stream Pixels project Added configurable nested entry grouping
This commit is contained in:
parent
526a737a4d
commit
968783bf9c
37 changed files with 865 additions and 580 deletions
|
|
@ -60,6 +60,7 @@
|
|||
<Compile Include="Assets\Scripts\ServerShared\Behaviors\HaulingController.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\NIH\LinqFaster\Reverse.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Cooldown.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\CultCache\RethinkConnection.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\NIH\LiteNetLib\Utils\NtpPacket.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\OrbitalEntity.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\ActionCollection.cs" />
|
||||
|
|
@ -140,7 +141,7 @@
|
|||
<Compile Include="Assets\Scripts\ServerShared\NIH\LinqFaster\Utils\ComparerMagic.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Behaviors\VelocityLimit.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Heat.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\CultCache\Extensions.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\CultCache\ReflectionExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Behaviors\InstantWeapon.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Behaviors\Visibility.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\NIH\LinqFaster\Repeat.cs" />
|
||||
|
|
@ -195,7 +196,6 @@
|
|||
<Compile Include="Assets\Scripts\ServerShared\NIH\LinqFaster\Where.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\NIH\LinqFaster\Min.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Behaviors\ParticleEffect.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\CultCache\MathExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Agents\Tasks\Mining.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\NIH\MIConvexHull\Vertex2.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\Sector.cs" />
|
||||
|
|
@ -250,6 +250,9 @@
|
|||
<Compile Include="Assets\Scripts\ServerShared\NIH\LinqFaster\SequenceEqual.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\NIH\LinqFaster\Skip.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\ItemManager.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\BezierCurve.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\CultCache\CollectionExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\ServerShared\EnumDictionary.cs" />
|
||||
<None Include="Assets\Scripts\ServerShared\NIH\LinqFaster\readme.txt" />
|
||||
<None Include="Assets\Scripts\ServerShared\Aetheria.Shared.Unity.asmdef" />
|
||||
<Reference Include="System.Threading.Tasks.Extensions">
|
||||
|
|
@ -646,6 +649,10 @@
|
|||
<Project>{4d885cb7-1f9e-abb3-b070-7265b432ecda}</Project>
|
||||
<Name>UniRx</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="RethinkDB.csproj">
|
||||
<Project>{f2483ebc-e82f-a58f-b987-c7502f9ab5d9}</Project>
|
||||
<Name>RethinkDB</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ public class AetheriaDatabaseView : DatabaseListView
|
|||
data => data.HardpointType,
|
||||
type => Enum.GetName(typeof(HardpointType), type),
|
||||
(data, type) => data.Hardpoint = type),
|
||||
// new DatabaseEntryGroup<GearData, Guid>(
|
||||
// data => data.Manufacturer,
|
||||
// factionID => cultCache.Get<Faction>(factionID).ShortName,
|
||||
// (data, faction) => data.Manufacturer = faction),
|
||||
new DatabaseEntryGroup<GearData, Guid>(
|
||||
data => data.Manufacturer,
|
||||
factionID => factionID == Guid.Empty ? "Default" : cultCache.Get<Faction>(factionID).ShortName,
|
||||
(data, faction) => data.Manufacturer = faction),
|
||||
new DatabaseEntryGroup<HullData, HullType>(
|
||||
data => data.HullType,
|
||||
type => Enum.GetName(typeof(HullType), type),
|
||||
|
|
|
|||
|
|
@ -25,16 +25,19 @@ public class DatabaseInspector : EditorWindow
|
|||
// Singleton to avoid multiple instances of window.
|
||||
private static DatabaseInspector _instance;
|
||||
public static DatabaseInspector Instance => _instance ? _instance : GetWindow<DatabaseInspector>();
|
||||
|
||||
private Vector2 _view;
|
||||
private const int width = 150;
|
||||
private GUIStyle _warning;
|
||||
private HashSet<int> _listItemFoldouts = new HashSet<int>();
|
||||
private Material _schematicMat;
|
||||
private Dictionary<(Type targetType, HashSet<Type> attributes), (object instance, Type type)> _inspectors =
|
||||
new Dictionary<(Type targetType, HashSet<Type> attributes), (object instance, Type type)>();
|
||||
private static bool _listItemStyle;
|
||||
public static GUIStyle ListItemStyle => (_listItemStyle = !_listItemStyle) ? DatabaseListView.ListStyleEven : DatabaseListView.ListStyleOdd;
|
||||
|
||||
private Dictionary<Type, Type> _genericInspectors = new Dictionary<Type, Type>();
|
||||
public const int Width = 150;
|
||||
|
||||
private Vector2 _view;
|
||||
private GUIStyle _warning;
|
||||
private List<(Type targetType, HashSet<Type> attributes, Type inspectorType, object instance)> _inspectors =
|
||||
new List<(Type targetType, HashSet<Type> attributes, Type inspectorType, object instance)>();
|
||||
|
||||
private List<(Type targetType, HashSet<Type> attributes, Type inspectorType, Dictionary<Type, object> instances)> _genericInspectors =
|
||||
new List<(Type targetType, HashSet<Type> attributes, Type inspectorType, Dictionary<Type, object> instances)>();
|
||||
private HashSet<object> _foldouts = new HashSet<object>();
|
||||
|
||||
public Color LabelColor => EditorGUIUtility.isProSkin ? Color.white : Color.black;
|
||||
|
||||
|
|
@ -57,105 +60,138 @@ public class DatabaseInspector : EditorWindow
|
|||
{
|
||||
if (genericArguments[0].ContainsGenericParameters)
|
||||
{
|
||||
_genericInspectors.Add(genericArguments[0].GetGenericTypeDefinition(), type);
|
||||
_genericInspectors.Add((
|
||||
genericArguments[0].GetGenericTypeDefinition(),
|
||||
new HashSet<Type>(genericArguments.Skip(1)),
|
||||
type,
|
||||
new Dictionary<Type, object>()
|
||||
));
|
||||
}
|
||||
else
|
||||
{
|
||||
_inspectors.Add((genericArguments[0], new HashSet<Type>(genericArguments.Skip(1))), (Activator.CreateInstance(type), type));
|
||||
_inspectors.Add((
|
||||
genericArguments[0],
|
||||
new HashSet<Type>(genericArguments.Skip(1)),
|
||||
type,
|
||||
Activator.CreateInstance(type)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Inspect(object obj, bool inspectablesOnly = false)
|
||||
public void Inspect(object obj, bool inspectablesOnly = true)
|
||||
{
|
||||
foreach (var field in obj.GetType().GetFields().OrderBy(f=>f.GetCustomAttribute<KeyAttribute>()?.IntKey ?? 0))
|
||||
{
|
||||
Inspect(obj, field, inspectablesOnly);
|
||||
}
|
||||
|
||||
// if (obj is EquippableItemData equippableItemData)
|
||||
// {
|
||||
// var restricted = false;
|
||||
// var doubleRestricted = false;
|
||||
// HullType type = HullType.Ship;
|
||||
// foreach (var behavior in equippableItemData.Behaviors)
|
||||
// {
|
||||
// var restriction = behavior.GetType().GetCustomAttribute<EntityTypeRestrictionAttribute>();
|
||||
// if (restriction != null)
|
||||
// {
|
||||
// if (restricted && restriction.Type != type)
|
||||
// doubleRestricted = true;
|
||||
// restricted = true;
|
||||
// type = restriction.Type;
|
||||
// }
|
||||
// }
|
||||
// if(doubleRestricted)
|
||||
// GUILayout.Label("ITEM UNEQUIPPABLE: BEHAVIOR HULL TYPE CONFLICT", _warning);
|
||||
// else if (restricted)
|
||||
// GUILayout.Label($"Item restricted by behavior to hull type {Enum.GetName(typeof(HullType), type)}", EditorStyles.boldLabel);
|
||||
// }
|
||||
}
|
||||
|
||||
public void Inspect(object obj, FieldInfo field, bool inspectablesOnly = false)
|
||||
public void Inspect(object obj, FieldInfo field, bool inspectablesOnly = true)
|
||||
{
|
||||
var inspectable = field.GetCustomAttribute<InspectableAttribute>();
|
||||
if (inspectable == null && inspectablesOnly) return;
|
||||
|
||||
var attributes = field.GetCustomAttributes(false);
|
||||
|
||||
var type = field.FieldType;
|
||||
var value = field.GetValue(obj);
|
||||
|
||||
field.SetValue(obj, InspectMember(field.Name.SplitCamelCase(), value, obj, type, false, attributes));
|
||||
}
|
||||
|
||||
if (type.IsGenericType)
|
||||
public object InspectMember(string label, object value, object parent, Type type, bool suppressContainer = false, params object[] attributes)
|
||||
{
|
||||
var style = _listItemStyle;
|
||||
object GetAttribute(Type attributeType)
|
||||
{
|
||||
var genericTypeDefinition = type.GetGenericTypeDefinition();
|
||||
if(_genericInspectors.ContainsKey(genericTypeDefinition))
|
||||
{
|
||||
var genericInspectorGenericType = _genericInspectors[genericTypeDefinition];
|
||||
var genericInspectorType = genericInspectorGenericType.MakeGenericType(type.GenericTypeArguments[0]);
|
||||
var genericInspector = Activator.CreateInstance(genericInspectorType);
|
||||
var parameters = new[] {field.Name.SplitCamelCase(), field.GetValue(obj), obj, this};
|
||||
field.SetValue(obj, genericInspectorType.GetMethod("Inspect").Invoke(genericInspector, parameters));
|
||||
return;
|
||||
}
|
||||
return attributes.FirstOrDefault(attributeType.IsInstanceOfType);
|
||||
}
|
||||
var potentialInspectors = _inspectors.Keys
|
||||
|
||||
if (value == null && type != typeof(string) && !(type.IsInterface || type.IsAbstract)) value = Activator.CreateInstance(type);
|
||||
|
||||
var potentialInspectors = _inspectors
|
||||
.Where(pi =>
|
||||
pi.targetType == type &&
|
||||
pi.attributes.All(attributeType => field.GetCustomAttribute(attributeType) != null));
|
||||
pi.attributes.All(attributeType => GetAttribute(attributeType) != null));
|
||||
if (potentialInspectors.Any())
|
||||
{
|
||||
var preferredInspector = potentialInspectors.MaxBy(i => i.attributes.Count);
|
||||
var parameters = new[] {field.Name.SplitCamelCase(), field.GetValue(obj), obj, this}
|
||||
.Concat(preferredInspector.attributes.Select<Type, object>(attributeType => field.GetCustomAttribute(attributeType)))
|
||||
var parameters = new[] {label, value, parent, this}
|
||||
.Concat(preferredInspector.attributes.Select(GetAttribute))
|
||||
.ToArray();
|
||||
field.SetValue(obj, _inspectors[preferredInspector].type.GetMethod("Inspect").Invoke(_inspectors[preferredInspector].instance, parameters));
|
||||
value = preferredInspector.inspectorType.GetMethod("Inspect").Invoke(preferredInspector.instance, parameters);
|
||||
_listItemStyle = style;
|
||||
return value;
|
||||
}
|
||||
else if (type.IsEnum)
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
var isflags = type.GetCustomAttributes<FlagsAttribute>().Any();
|
||||
var names = Enum.GetNames(field.FieldType);
|
||||
field.SetValue(obj,
|
||||
InspectEnum(field.Name.SplitCamelCase(), (int) field.GetValue(obj), isflags ? names.Skip(1).ToArray() : names, isflags));
|
||||
var names = Enum.GetNames(type);
|
||||
value = InspectEnum(label, (int) value, isflags ? names.Skip(1).ToArray() : names, isflags);
|
||||
_listItemStyle = style;
|
||||
return value;
|
||||
}
|
||||
else if (type.GetCustomAttribute<InspectableAttribute>() != null)
|
||||
|
||||
if (type.GetCustomAttribute<InspectableAttribute>() != null)
|
||||
{
|
||||
Space();
|
||||
if(!suppressContainer)
|
||||
GUILayout.BeginVertical(GUI.skin.box);
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
LabelField(field.Name.SplitCamelCase(), EditorStyles.boldLabel);
|
||||
if (type.IsInterface)
|
||||
if(!suppressContainer)
|
||||
{
|
||||
var subTypes = type.GetAllInterfaceClasses();
|
||||
if (Foldout(_foldouts.Contains(value), label, true, EditorStyles.boldLabel))
|
||||
_foldouts.Add(value);
|
||||
else _foldouts.Remove(value);
|
||||
}
|
||||
if (type.IsInterface || type.IsAbstract)
|
||||
{
|
||||
var subTypes = type.GetAllChildClasses().Where(t=>!(t.IsInterface || t.IsAbstract)).ToArray();
|
||||
var selected = value != null ? Array.IndexOf(subTypes, value.GetType()) + 1 : 0;
|
||||
var newSelection = Popup(selected,
|
||||
subTypes.Select(t => t.Name.SplitCamelCase()).Prepend("None").ToArray());
|
||||
if(newSelection != selected)
|
||||
field.SetValue(obj, value = newSelection==0?null:Activator.CreateInstance(subTypes[newSelection-1]));
|
||||
} else if(value == null) field.SetValue(obj, value = Activator.CreateInstance(type));
|
||||
if (newSelection != selected)
|
||||
value = newSelection == 0 ? null : Activator.CreateInstance(subTypes[newSelection - 1]);
|
||||
}
|
||||
else if (value == null) value = Activator.CreateInstance(type);
|
||||
}
|
||||
if(value != null) Inspect(field.GetValue(obj), inspectablesOnly);
|
||||
|
||||
if (value != null && (_foldouts.Contains(value) || suppressContainer)) Inspect(value);
|
||||
if(!suppressContainer)
|
||||
GUILayout.EndVertical();
|
||||
_listItemStyle = style;
|
||||
return value;
|
||||
}
|
||||
else Debug.Log($"Field \"{field.Name}\" has unknown type {field.FieldType.Name}. No inspector was generated.");
|
||||
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var genericTypeDefinition = type.GetGenericTypeDefinition();
|
||||
var potentialGenericInspectors = _genericInspectors
|
||||
.Where(pi =>
|
||||
pi.targetType == genericTypeDefinition &&
|
||||
pi.attributes.All(attributeType => GetAttribute(attributeType) != null));
|
||||
if (potentialGenericInspectors.Any())
|
||||
{
|
||||
var genericTypeArguments = type.GenericTypeArguments;
|
||||
var preferredInspector = potentialGenericInspectors.MaxBy(i => i.attributes.Count);
|
||||
var genericInspectorType = preferredInspector.inspectorType.MakeGenericType(genericTypeArguments);
|
||||
if (!preferredInspector.instances.ContainsKey(genericInspectorType))
|
||||
preferredInspector.instances[genericInspectorType] =
|
||||
Activator.CreateInstance(genericInspectorType);
|
||||
var parameters = new[] {label, value, parent, this};
|
||||
value = genericInspectorType.GetMethod("Inspect").Invoke(preferredInspector.instances[genericInspectorType], parameters);
|
||||
_listItemStyle = style;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"Field \"{label}\" has unknown type {type.Name}. No inspector was generated.");
|
||||
|
||||
_listItemStyle = style;
|
||||
return value;
|
||||
}
|
||||
|
||||
public int InspectEnum(string label, int value, string[] enumOptions, bool flags)
|
||||
|
|
@ -164,13 +200,13 @@ public class DatabaseInspector : EditorWindow
|
|||
{
|
||||
Space();
|
||||
LabelField(label, EditorStyles.boldLabel);
|
||||
using (var v = new VerticalScope(GUI.skin.box))
|
||||
using (new VerticalScope(GUI.skin.box))
|
||||
{
|
||||
for (var i = 0; i < enumOptions.Length; i++)
|
||||
{
|
||||
using (var h = new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(enumOptions[i], GUILayout.Width(width));
|
||||
GUILayout.Label(enumOptions[i], GUILayout.Width(Width));
|
||||
var set = Toggle(1 << i == (1 << i & value));
|
||||
if (set)
|
||||
value |= 1 << i;
|
||||
|
|
@ -184,7 +220,7 @@ public class DatabaseInspector : EditorWindow
|
|||
|
||||
using (var h = new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
GUILayout.Label(label, GUILayout.Width(Width));
|
||||
return Popup(value, enumOptions);
|
||||
}
|
||||
}
|
||||
|
|
@ -212,7 +248,8 @@ public class DatabaseInspector : EditorWindow
|
|||
|
||||
// Serialize inspected object so we can check whether it has actually changed
|
||||
RegisterResolver.Register();
|
||||
var previousBytes = MessagePackSerializer.Serialize(entry);
|
||||
var previousBytes = MessagePackSerializer.Serialize<DatabaseEntry>(entry);
|
||||
var previousHash = previousBytes.GetHashSHA1();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
|
|
@ -224,7 +261,7 @@ public class DatabaseInspector : EditorWindow
|
|||
// Debug.Log(entry.ToJson());
|
||||
if (GUILayout.Button("Delete Entry"))
|
||||
{
|
||||
CultCache.Delete(entry);
|
||||
CultCache.Remove(entry);
|
||||
entry = null;
|
||||
return;
|
||||
}
|
||||
|
|
@ -243,11 +280,12 @@ public class DatabaseInspector : EditorWindow
|
|||
LabelField(dataEntry.ID.ToString());
|
||||
}
|
||||
|
||||
Inspect(entry, true);
|
||||
_listItemStyle = false;
|
||||
Inspect(entry);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
if(!previousBytes.ByteEquals(MessagePackSerializer.Serialize(entry)))
|
||||
if(previousHash != MessagePackSerializer.Serialize(entry).GetHashSHA1())
|
||||
CultCache.Add(entry);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ public abstract class DatabaseListView : EditorWindow
|
|||
|
||||
protected CultCache cultCache;
|
||||
private static DatabaseInspector _inspector;
|
||||
private Type[] _entryTypes;
|
||||
private bool[] _typeFoldouts;
|
||||
private Dictionary<string, (bool foldout, (Type entryType, bool foldout)[] types)> _tables;
|
||||
//private Type[] _entryTypes;
|
||||
private Type[] _globalTypes;
|
||||
private string _connectionString;
|
||||
private Vector2 _view;
|
||||
private RethinkQueryStatus _queryStatus;
|
||||
|
|
@ -70,6 +71,7 @@ public abstract class DatabaseListView : EditorWindow
|
|||
|
||||
public override int HashGroup(object o)
|
||||
{
|
||||
return o.GetHashCode();
|
||||
if (o is K k) return k.GetHashCode();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -94,8 +96,7 @@ public abstract class DatabaseListView : EditorWindow
|
|||
public Color LabelColor => EditorGUIUtility.isProSkin ? Color.white : Color.black;
|
||||
|
||||
private bool _listItemStyle;
|
||||
public GUIStyle ListItemStyle =>
|
||||
(_listItemStyle = !_listItemStyle) ? ListStyleEven : ListStyleOdd;
|
||||
public GUIStyle ListItemStyle => (_listItemStyle = !_listItemStyle) ? ListStyleEven : ListStyleOdd;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
|
|
@ -114,19 +115,22 @@ public abstract class DatabaseListView : EditorWindow
|
|||
|
||||
cultCache.OnDataUpdateLocal += _ => Repaint();
|
||||
cultCache.OnDataInsertLocal += _ => Repaint();
|
||||
cultCache.OnDataDeleteLocal += _ => Repaint();
|
||||
cultCache.OnDataRemoveLocal += _ => Repaint();
|
||||
cultCache.OnDataUpdateRemote += _ => EditorDispatcher.Dispatch(Repaint);
|
||||
cultCache.OnDataInsertRemote += _ => EditorDispatcher.Dispatch(Repaint);
|
||||
cultCache.OnDataDeleteRemote += _ => EditorDispatcher.Dispatch(Repaint);
|
||||
cultCache.OnDataRemoveRemote += _ => EditorDispatcher.Dispatch(Repaint);
|
||||
|
||||
DatabaseInspector.CultCache = cultCache;
|
||||
_inspector = DatabaseInspector.Instance;
|
||||
_inspector.Show();
|
||||
|
||||
_entryTypes = typeof(DatabaseEntry).GetAllChildClasses()
|
||||
.Where(t => t.GetCustomAttribute<InspectableAttribute>() != null).ToArray();
|
||||
|
||||
_typeFoldouts = new bool[_entryTypes.Length];
|
||||
_globalTypes = typeof(DatabaseEntry).GetAllChildClasses()
|
||||
.Where(t => t.GetCustomAttribute<InspectableAttribute>() != null && t.GetCustomAttribute<GlobalSettingsAttribute>() != null).ToArray();
|
||||
_tables = typeof(DatabaseEntry).GetAllChildClasses()
|
||||
.Where(t => t.GetCustomAttribute<InspectableAttribute>() != null && t.GetCustomAttribute<GlobalSettingsAttribute>() == null)
|
||||
.GroupBy(t=>t.GetCustomAttribute<RethinkTableAttribute>()?.TableName ??
|
||||
(t.GetCustomAttribute<ExternalEntryAttribute>() != null ? "External" : "Default"))
|
||||
.ToDictionary(group=>group.Key, group=> (false, group.Select(t=>(t, false)).ToArray()));
|
||||
|
||||
if (EditorPrefs.HasKey("RethinkDB.URL"))
|
||||
_connectionString = EditorPrefs.GetString("RethinkDB.URL");
|
||||
|
|
@ -154,7 +158,7 @@ public abstract class DatabaseListView : EditorWindow
|
|||
// Indicate that we don't accept drags ourselves
|
||||
DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
|
||||
|
||||
using (var h = new HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
_connectionString = TextField(_connectionString);
|
||||
if (GUILayout.Button("Connect"))
|
||||
|
|
@ -163,13 +167,8 @@ public abstract class DatabaseListView : EditorWindow
|
|||
JsonKnownTypesSettingsManager.RegisterTypeAssembly<ItemData>();
|
||||
_queryStatus = RethinkConnection.RethinkConnect(cultCache, _connectionString, DatabaseName);
|
||||
}
|
||||
// if (GUILayout.Button("Connect All"))
|
||||
// {
|
||||
// EditorPrefs.SetString("RethinkDB.URL", _connectionString);
|
||||
// _queryStatus = RethinkConnection.RethinkConnect(_databaseCache, _connectionString, true, false);
|
||||
// }
|
||||
}
|
||||
using (var h = new HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
//_fileName = TextField(_fileName);
|
||||
if (GUILayout.Button("Save"))
|
||||
|
|
@ -201,110 +200,132 @@ public abstract class DatabaseListView : EditorWindow
|
|||
GUI.skin.scrollView,
|
||||
GUILayout.Width(EditorGUIUtility.currentViewWidth),
|
||||
GUILayout.ExpandHeight(true));
|
||||
|
||||
for (var i = 0; i < _entryTypes.Length; i++)
|
||||
{
|
||||
using (var h = new HorizontalScope(ListItemStyle))
|
||||
{
|
||||
_typeFoldouts[i] = Foldout(_typeFoldouts[i],
|
||||
((NameAttribute) _entryTypes[i].GetCustomAttribute(typeof(NameAttribute)))?.Name ?? FormatTypeName(_entryTypes[i].Name),
|
||||
true);
|
||||
}
|
||||
|
||||
if (_typeFoldouts[i])
|
||||
foreach (var globalType in _globalTypes)
|
||||
{
|
||||
var globalEntry = cultCache.GetGlobal(globalType);
|
||||
var style = ListItemStyle;
|
||||
var selected = SelectedItem == globalEntry.ID;
|
||||
using (new HorizontalScope(selected?SelectedStyle:style))
|
||||
{
|
||||
// TODO: NESTED GROUPS!
|
||||
var entries = cultCache.GetAll(_entryTypes[i])
|
||||
.OrderBy(entry => entry is INamedEntry namedEntry ? namedEntry.EntryName : entry.ID.ToString());
|
||||
var grouper = Groupers.FirstOrDefault(g => g.CanGroup(_entryTypes[i]));
|
||||
if (grouper != null)
|
||||
using (var h = new HorizontalScope())
|
||||
{
|
||||
var groups = entries.GroupBy(o => grouper.SelectGroup(o));
|
||||
foreach (var group in groups)
|
||||
if (h.rect.Contains(currentEvent.mousePosition))
|
||||
{
|
||||
var groupHash = grouper.HashGroup(group.Key);
|
||||
var groupName = grouper.GetGroupName(group.Key);
|
||||
if (currentEventType == EventType.MouseUp)
|
||||
Select(globalEntry);
|
||||
}
|
||||
|
||||
GUILayout.Label(globalType.Name.SplitCamelCase(), selected ? EditorStyles.whiteLabel : GUI.skin.label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayGroup(Type entryType, IEnumerable<DatabaseEntry> entries, IEnumerable<DatabaseEntryGroup> nestedGroups, int indent = 2, Action<DatabaseEntry> activatePreviousGroups = null, string previousGroupNames = "")
|
||||
{
|
||||
var grouper = nestedGroups.FirstOrDefault();
|
||||
if (grouper != null)
|
||||
{
|
||||
var groups = entries.GroupBy(o => grouper.SelectGroup(o));
|
||||
foreach (var group in groups)
|
||||
{
|
||||
//var groupHash = grouper.HashGroup(group.Key);
|
||||
var groupName = grouper.GetGroupName(group.Key);
|
||||
var groupHash = groupName.GetHashCode();
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
{
|
||||
GUILayout.Space(indent*10);
|
||||
if (Foldout(_groupFoldouts.Contains(groupHash), FormatTypeName(groupName), true))
|
||||
_groupFoldouts.Add(groupHash);
|
||||
else _groupFoldouts.Remove(groupHash);
|
||||
}
|
||||
|
||||
if (_groupFoldouts.Contains(groupHash))
|
||||
{
|
||||
Action<DatabaseEntry> activate = entry =>
|
||||
{
|
||||
activatePreviousGroups?.Invoke(entry);
|
||||
grouper.Activate(entry, group.Key);
|
||||
};
|
||||
|
||||
DisplayGroup(entryType, group, nestedGroups.Skip(1), indent + 1, activate, $"{groupName} {previousGroupNames}");
|
||||
|
||||
using (var h = new HorizontalScope(ListItemStyle))
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
if (Foldout(_groupFoldouts.Contains(groupHash), FormatTypeName(groupName), true))
|
||||
_groupFoldouts.Add(groupHash);
|
||||
else _groupFoldouts.Remove(groupHash);
|
||||
}
|
||||
|
||||
if (_groupFoldouts.Contains(groupHash))
|
||||
{
|
||||
int index = 0;
|
||||
foreach (var entry in group)
|
||||
{
|
||||
index++;
|
||||
var style = ListItemStyle;
|
||||
var selected = SelectedItem == entry.ID;
|
||||
using (new HorizontalScope(selected?SelectedStyle:style))
|
||||
{
|
||||
using (var h = new HorizontalScope())
|
||||
{
|
||||
if (h.rect.Contains(currentEvent.mousePosition))
|
||||
{
|
||||
if (currentEventType == EventType.MouseDrag)
|
||||
{
|
||||
DragAndDrop.PrepareStartDrag();
|
||||
DragAndDrop.SetGenericData("Item", entry.ID);
|
||||
DragAndDrop.StartDrag("Database Item");
|
||||
}
|
||||
else if (currentEventType == EventType.MouseUp)
|
||||
Select(entry);
|
||||
}
|
||||
|
||||
GUILayout.Space(20);
|
||||
GUILayout.Label((entry as INamedEntry)?.EntryName ?? index.ToString(), selected ? EditorStyles.whiteLabel : GUI.skin.label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (var h = new HorizontalScope(ListItemStyle))
|
||||
{
|
||||
if(GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
|
||||
CreateItem(_entryTypes[i], entry => grouper.Activate(entry, group.Key));
|
||||
GUILayout.Space(20);
|
||||
GUILayout.Label($"New {groupName}");
|
||||
}
|
||||
if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
|
||||
CreateItem(entryType, activate);
|
||||
GUILayout.Space((indent+1)*10);
|
||||
GUILayout.Label($"Create {groupName} {previousGroupNames}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = 0;
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
int index = 0;
|
||||
foreach (var entry in entries)
|
||||
index++;
|
||||
var style = ListItemStyle;
|
||||
var selected = SelectedItem == entry.ID;
|
||||
using (var h = new HorizontalScope(selected ? SelectedStyle : style))
|
||||
{
|
||||
index++;
|
||||
var style = ListItemStyle;
|
||||
var selected = SelectedItem == entry.ID;
|
||||
using (var h = new HorizontalScope(selected?SelectedStyle:style))
|
||||
if (h.rect.Contains(currentEvent.mousePosition))
|
||||
{
|
||||
if (h.rect.Contains(currentEvent.mousePosition))
|
||||
if (currentEventType == EventType.MouseDrag)
|
||||
{
|
||||
if (currentEventType == EventType.MouseDrag)
|
||||
{
|
||||
DragAndDrop.PrepareStartDrag();
|
||||
DragAndDrop.SetGenericData("Item", entry.ID);
|
||||
DragAndDrop.StartDrag("Database Item");
|
||||
}
|
||||
else if (currentEventType == EventType.MouseUp)
|
||||
Select(entry);
|
||||
DragAndDrop.PrepareStartDrag();
|
||||
DragAndDrop.SetGenericData("Item", entry.ID);
|
||||
DragAndDrop.StartDrag("Database Item");
|
||||
}
|
||||
GUILayout.Space(10);
|
||||
GUILayout.Label((entry as INamedEntry)?.EntryName ?? index.ToString(), selected ? EditorStyles.whiteLabel : GUI.skin.label);
|
||||
else if (currentEventType == EventType.MouseUp)
|
||||
Select(entry);
|
||||
}
|
||||
|
||||
GUILayout.Space(indent*10);
|
||||
GUILayout.Label((entry as INamedEntry)?.EntryName ?? index.ToString(),
|
||||
selected ? EditorStyles.whiteLabel : GUI.skin.label);
|
||||
}
|
||||
}
|
||||
|
||||
using (var h = new HorizontalScope(ListItemStyle))
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var table in _tables.Keys.ToArray())
|
||||
{
|
||||
var (tableFoldout, _) = _tables[table];
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
{
|
||||
_tables[table] = (Foldout(tableFoldout = _tables[table].foldout, table, true), _tables[table].types);
|
||||
}
|
||||
|
||||
if (tableFoldout)
|
||||
{
|
||||
for (var i = 0; i < _tables[table].types.Length; i++)
|
||||
{
|
||||
if(GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
|
||||
CreateItem(_entryTypes[i]);
|
||||
GUILayout.Space(10);
|
||||
GUILayout.Label($"New {_entryTypes[i].Name}");
|
||||
var (entryType, typeFoldout) = _tables[table].types[i];
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
{
|
||||
GUILayout.Space(10);
|
||||
_tables[table].types[i] = (entryType, typeFoldout = Foldout(typeFoldout,
|
||||
((NameAttribute) entryType.GetCustomAttribute(typeof(NameAttribute)))?.Name ?? FormatTypeName(entryType.Name),
|
||||
true));
|
||||
}
|
||||
|
||||
if (typeFoldout)
|
||||
{
|
||||
var entries = cultCache.GetAll(entryType)
|
||||
.OrderBy(entry => entry is INamedEntry namedEntry ? namedEntry.EntryName : entry.ID.ToString());
|
||||
var groupers = Groupers.Where(g => g.CanGroup(entryType));
|
||||
DisplayGroup(entryType, entries, groupers);
|
||||
|
||||
using (var h = new HorizontalScope(ListItemStyle))
|
||||
{
|
||||
if (GUI.Button(h.rect, GUIContent.none, GUIStyle.none))
|
||||
CreateItem(entryType);
|
||||
GUILayout.Space(20);
|
||||
GUILayout.Label($"Create {FormatTypeName(entryType.Name)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -312,7 +333,7 @@ public abstract class DatabaseListView : EditorWindow
|
|||
EndScrollView();
|
||||
}
|
||||
|
||||
private string FormatTypeName(string typeName)
|
||||
public static string FormatTypeName(string typeName)
|
||||
{
|
||||
return (typeName.EndsWith("Data")
|
||||
? typeName.Substring(0, typeName.Length - 4)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public class AnimationCurveFloat4Inspector : BaseInspector<float4[]>
|
|||
var val = value != null && value.Length > 0
|
||||
? value.ToCurve()
|
||||
: new AnimationCurve();
|
||||
using (var h = new EditorGUILayout.HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
val = CurveField(val, Color.yellow, new Rect(0, 0, 1, 1));
|
||||
|
|
@ -22,6 +22,25 @@ public class AnimationCurveFloat4Inspector : BaseInspector<float4[]>
|
|||
}
|
||||
}
|
||||
|
||||
public class BezierCurveInspector : BaseInspector<BezierCurve>
|
||||
{
|
||||
public override BezierCurve Inspect(string label, BezierCurve value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
var val = value != null && value.Keys != null && value.Keys.Length > 0
|
||||
? value.ToCurve()
|
||||
: new AnimationCurve();
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
val = CurveField(val, Color.yellow, new Rect(0, 0, 1, 1));
|
||||
}
|
||||
|
||||
value.Keys = val.keys.Select(k => float4(k.time, k.value, k.inTangent, k.outTangent)).ToArray();
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public class AnimationCurveInspect : BaseInspector<AnimationCurve>
|
||||
{
|
||||
public override AnimationCurve Inspect(string label, AnimationCurve value, object parent, DatabaseInspector inspectorWindow)
|
||||
|
|
|
|||
|
|
@ -8,32 +8,35 @@ public class DatabaseLinkInspector : BaseInspector<Guid, InspectableDatabaseLink
|
|||
{
|
||||
public override Guid Inspect(string label, Guid value, object parent, DatabaseInspector inspectorWindow, InspectableDatabaseLinkAttribute link)
|
||||
{
|
||||
LabelField(label, EditorStyles.boldLabel);
|
||||
var valueEntry = DatabaseInspector.CultCache.Get(value);
|
||||
using (var h = new HorizontalScope(GUI.skin.box))
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label((valueEntry as INamedEntry)?.EntryName ?? valueEntry?.ID.ToString() ?? $"Assign a {link.EntryType.Name} by dragging from the list panel.");
|
||||
|
||||
if (h.rect.Contains(Event.current.mousePosition) && (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform))
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
var valueEntry = DatabaseInspector.CultCache.Get(value);
|
||||
using (var h = new HorizontalScope(GUI.skin.box))
|
||||
{
|
||||
var guid = (Guid) DragAndDrop.GetGenericData("Item");
|
||||
var dragEntry = DatabaseInspector.CultCache.Get(guid);
|
||||
var dragValid = dragEntry != null && link.EntryType.IsInstanceOfType(dragEntry) && dragEntry != valueEntry;
|
||||
if(Event.current.type == EventType.DragUpdated)
|
||||
DragAndDrop.visualMode = dragValid ? DragAndDropVisualMode.Copy : DragAndDropVisualMode.Rejected;
|
||||
else if(Event.current.type == EventType.DragPerform)
|
||||
GUILayout.Label((valueEntry as INamedEntry)?.EntryName ?? valueEntry?.ID.ToString() ?? $"Drag and drop: {DatabaseListView.FormatTypeName(link.EntryType.Name)}");
|
||||
|
||||
if (h.rect.Contains(Event.current.mousePosition) && (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform))
|
||||
{
|
||||
if (dragValid)
|
||||
var guid = (Guid) DragAndDrop.GetGenericData("Item");
|
||||
var dragEntry = DatabaseInspector.CultCache.Get(guid);
|
||||
var dragValid = dragEntry != null && link.EntryType.IsInstanceOfType(dragEntry) && dragEntry != valueEntry;
|
||||
if(Event.current.type == EventType.DragUpdated)
|
||||
DragAndDrop.visualMode = dragValid ? DragAndDropVisualMode.Copy : DragAndDropVisualMode.Rejected;
|
||||
else if(Event.current.type == EventType.DragPerform)
|
||||
{
|
||||
DragAndDrop.AcceptDrag();
|
||||
GUI.changed = true;
|
||||
return guid;
|
||||
if (dragValid)
|
||||
{
|
||||
DragAndDrop.AcceptDrag();
|
||||
GUI.changed = true;
|
||||
return guid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("-", GUILayout.Width((EditorGUIUtility.singleLineHeight - 3)*2), GUILayout.Height(EditorGUIUtility.singleLineHeight-3)))
|
||||
{
|
||||
return Guid.Empty;
|
||||
if (GUILayout.Button("-", GUILayout.Width((EditorGUIUtility.singleLineHeight - 3)*2), GUILayout.Height(EditorGUIUtility.singleLineHeight-3)))
|
||||
{
|
||||
return Guid.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,13 +49,19 @@ public class DatabaseLinkObjectInspector<T> : BaseInspector<DatabaseLink<T>> whe
|
|||
public override DatabaseLink<T> Inspect(string label, DatabaseLink<T> value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
if (value == null)
|
||||
value = new DatabaseLink<T>{Cache = DatabaseInspector.CultCache};
|
||||
LabelField(label, EditorStyles.boldLabel);
|
||||
var valueEntry = value.Value;
|
||||
using (var h = new HorizontalScope(GUI.skin.box))
|
||||
value = new DatabaseLink<T>();
|
||||
|
||||
if(!string.IsNullOrEmpty(label))
|
||||
{
|
||||
GUILayout.Label((valueEntry as INamedEntry)?.EntryName ?? valueEntry?.ID.ToString() ?? $"Assign a {typeof(T).Name} by dragging from the list panel.");
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
}
|
||||
|
||||
var valueEntry = value.Value;
|
||||
using (var h = string.IsNullOrEmpty(label) ? new HorizontalScope() : new HorizontalScope(GUI.skin.box))
|
||||
{
|
||||
GUILayout.Label((valueEntry as INamedEntry)?.EntryName ?? valueEntry?.ID.ToString() ?? $"Drag and drop: {DatabaseListView.FormatTypeName(typeof(T).Name)}");
|
||||
|
||||
if (h.rect.Contains(Event.current.mousePosition) && (Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform))
|
||||
{
|
||||
var guid = (Guid) DragAndDrop.GetGenericData("Item");
|
||||
|
|
@ -70,11 +79,21 @@ public class DatabaseLinkObjectInspector<T> : BaseInspector<DatabaseLink<T>> whe
|
|||
}
|
||||
}
|
||||
}
|
||||
if (GUILayout.Button("-", GUILayout.Width((EditorGUIUtility.singleLineHeight - 3)*2), GUILayout.Height(EditorGUIUtility.singleLineHeight-3)))
|
||||
if(value.LinkID != Guid.Empty)
|
||||
{
|
||||
value.LinkID = Guid.Empty;
|
||||
if (GUILayout.Button("-",
|
||||
GUILayout.Width((EditorGUIUtility.singleLineHeight - 3) * 2),
|
||||
GUILayout.Height(EditorGUIUtility.singleLineHeight - 3)))
|
||||
{
|
||||
value.LinkID = Guid.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!string.IsNullOrEmpty(label))
|
||||
{
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
|
@ -92,11 +111,9 @@ public class DatabaseLinkListInspector : BaseInspector<List<Guid>, InspectableDa
|
|||
DatabaseInspector inspectorWindow,
|
||||
InspectableDatabaseLinkAttribute link)
|
||||
{
|
||||
Space();
|
||||
LabelField(label, EditorStyles.boldLabel);
|
||||
|
||||
using (var v = new VerticalScope(GUI.skin.box))
|
||||
{
|
||||
GUILayout.Label(label, EditorStyles.boldLabel);
|
||||
if (value.Count == 0)
|
||||
{
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
|
|
|
|||
|
|
@ -7,10 +7,6 @@ using static UnityEditor.EditorGUILayout;
|
|||
|
||||
public class FloatDictionaryInspector : BaseInspector<Dictionary<Guid, float>, InspectableDatabaseLinkAttribute>
|
||||
{
|
||||
private bool _listItemStyle;
|
||||
public GUIStyle ListItemStyle =>
|
||||
(_listItemStyle = !_listItemStyle) ? DatabaseListView.ListStyleEven : DatabaseListView.ListStyleOdd;
|
||||
|
||||
public override Dictionary<Guid, float> Inspect(string label,
|
||||
Dictionary<Guid, float> value,
|
||||
object parent,
|
||||
|
|
@ -24,14 +20,14 @@ public class FloatDictionaryInspector : BaseInspector<Dictionary<Guid, float>, I
|
|||
{
|
||||
if (value.Count == 0)
|
||||
{
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
using (new HorizontalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
GUILayout.Label("Drag from list to add item");
|
||||
}
|
||||
}
|
||||
foreach (var ingredient in value.ToArray())
|
||||
{
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
using (new HorizontalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
var entry = DatabaseInspector.CultCache.Get(ingredient.Key);
|
||||
if (entry == null)
|
||||
|
|
@ -79,10 +75,6 @@ public class FloatDictionaryInspector : BaseInspector<Dictionary<Guid, float>, I
|
|||
|
||||
public class RangedFloatDictionaryInspector : BaseInspector<Dictionary<Guid, float>, InspectableDatabaseLinkAttribute, RangedFloatAttribute>
|
||||
{
|
||||
private bool _listItemStyle;
|
||||
public GUIStyle ListItemStyle =>
|
||||
(_listItemStyle = !_listItemStyle) ? DatabaseListView.ListStyleEven : DatabaseListView.ListStyleOdd;
|
||||
|
||||
public override Dictionary<Guid, float> Inspect(string label,
|
||||
Dictionary<Guid, float> value,
|
||||
object parent,
|
||||
|
|
@ -97,14 +89,14 @@ public class RangedFloatDictionaryInspector : BaseInspector<Dictionary<Guid, flo
|
|||
{
|
||||
if (value.Count == 0)
|
||||
{
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
using (new HorizontalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
GUILayout.Label("Drag from list to add item");
|
||||
}
|
||||
}
|
||||
foreach (var ingredient in value.ToArray())
|
||||
{
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
using (new HorizontalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
var entry = DatabaseInspector.CultCache.Get(ingredient.Key);
|
||||
if (entry == null)
|
||||
|
|
@ -152,10 +144,6 @@ public class RangedFloatDictionaryInspector : BaseInspector<Dictionary<Guid, flo
|
|||
|
||||
public class IntDictionaryInspector : BaseInspector<Dictionary<Guid, int>, InspectableDatabaseLinkAttribute>
|
||||
{
|
||||
private bool _listItemStyle;
|
||||
public GUIStyle ListItemStyle =>
|
||||
(_listItemStyle = !_listItemStyle) ? DatabaseListView.ListStyleEven : DatabaseListView.ListStyleOdd;
|
||||
|
||||
public override Dictionary<Guid, int> Inspect(string label,
|
||||
Dictionary<Guid, int> value,
|
||||
object parent,
|
||||
|
|
@ -169,14 +157,14 @@ public class IntDictionaryInspector : BaseInspector<Dictionary<Guid, int>, Inspe
|
|||
{
|
||||
if (value.Count == 0)
|
||||
{
|
||||
using (var h = new HorizontalScope(ListItemStyle))
|
||||
using (var h = new HorizontalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
GUILayout.Label("Drag from list to add item");
|
||||
}
|
||||
}
|
||||
foreach (var ingredient in value.ToArray())
|
||||
{
|
||||
using (var h = new HorizontalScope(ListItemStyle))
|
||||
using (var h = new HorizontalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
var entry = DatabaseInspector.CultCache.Get(ingredient.Key);
|
||||
if (entry == null)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using static Unity.Mathematics.math;
|
||||
using static UnityEditor.EditorGUILayout;
|
||||
|
||||
public class EnumInspector<T> : BaseInspector<List<T>, InspectableEnumValuesAttribute>
|
||||
{
|
||||
public override List<T> Inspect(string label, List<T> list, object parent, DatabaseInspector inspectorWindow, InspectableEnumValuesAttribute attribute)
|
||||
{
|
||||
var names = Enum.GetNames(attribute.EnumType);
|
||||
list ??= new List<T>();
|
||||
|
||||
while(list.Count < names.Length) list.Add(Activator.CreateInstance<T>());
|
||||
while(list.Count > names.Length) list.RemoveAt(list.Count-1);
|
||||
|
||||
for (var i = 0; i < names.Length; i++)
|
||||
inspectorWindow.InspectMember(names[i], list[i], parent, typeof(T));
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
public class EnumDictionaryInspector<E, T> : BaseInspector<EnumDictionary<E, T>> where E : Enum
|
||||
{
|
||||
private static HashSet<object> _foldouts = new HashSet<object>();
|
||||
|
||||
public override EnumDictionary<E, T> Inspect(string label, EnumDictionary<E, T> dict, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
var names = Enum.GetNames(typeof(E));
|
||||
if (dict == null || dict.Values.Length != names.Length)
|
||||
{
|
||||
var newValue = new T[names.Length];
|
||||
if(dict != null && dict.Values.Length > 0)
|
||||
Array.Copy(dict.Values, newValue, min(dict.Values.Length, newValue.Length));
|
||||
dict.Values = newValue;
|
||||
}
|
||||
|
||||
using (new VerticalScope(GUI.skin.box))
|
||||
{
|
||||
if (Foldout(_foldouts.Contains(dict), label, true, EditorStyles.boldLabel))
|
||||
_foldouts.Add(dict);
|
||||
else _foldouts.Remove(dict);
|
||||
if(_foldouts.Contains(dict))
|
||||
{
|
||||
for (var i = 0; i < names.Length; i++)
|
||||
{
|
||||
using (new VerticalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
dict.Values[i] = (T) inspectorWindow.InspectMember(names[i], dict.Values[i], parent, typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: da1b15e5564747958639c8f959226c74
|
||||
timeCreated: 1617335525
|
||||
|
|
@ -14,13 +14,13 @@ public class FloatInspector : BaseInspector<float>
|
|||
}
|
||||
}
|
||||
|
||||
public class RangedFloatInspector : BaseInspector<float, RangedFloatInspectableAttribute>
|
||||
public class RangedFloatInspector : BaseInspector<float, InspectableRangedFloatAttribute>
|
||||
{
|
||||
public override float Inspect(string label,
|
||||
float value,
|
||||
object parent,
|
||||
DatabaseInspector inspectorWindow,
|
||||
RangedFloatInspectableAttribute attribute)
|
||||
InspectableRangedFloatAttribute attribute)
|
||||
{
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ public class IntInspector : BaseInspector<int>
|
|||
}
|
||||
}
|
||||
|
||||
public class RangedIntInspector : BaseInspector<int, RangedIntInspectableAttribute>
|
||||
public class RangedIntInspector : BaseInspector<int, InspectableRangedIntAttribute>
|
||||
{
|
||||
public override int Inspect(string label, int value, object parent, DatabaseInspector inspectorWindow, RangedIntInspectableAttribute attribute)
|
||||
public override int Inspect(string label, int value, object parent, DatabaseInspector inspectorWindow, InspectableRangedIntAttribute attribute)
|
||||
{
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,46 +9,49 @@ using static UnityEditor.EditorGUILayout;
|
|||
|
||||
public class ListInspector<T> : BaseInspector<List<T>>
|
||||
{
|
||||
private bool _listItemStyle;
|
||||
private static HashSet<int> _listItemFoldouts = new HashSet<int>();
|
||||
public GUIStyle ListItemStyle =>
|
||||
(_listItemStyle = !_listItemStyle) ? DatabaseListView.ListStyleEven : DatabaseListView.ListStyleOdd;
|
||||
private static HashSet<object> _foldouts = new HashSet<object>();
|
||||
|
||||
public override List<T> Inspect(string label, List<T> list, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
var listType = typeof(T);
|
||||
if (listType.GetCustomAttribute<InspectableAttribute>() != null)
|
||||
var inspectable = listType.GetCustomAttribute<InspectableAttribute>();
|
||||
// if (listType.GetCustomAttribute<InspectableAttribute>() != null)
|
||||
// {
|
||||
//Space();
|
||||
using (new VerticalScope(GUI.skin.box))
|
||||
{
|
||||
Space();
|
||||
using (new VerticalScope(GUI.skin.box))
|
||||
if (list == null)
|
||||
{
|
||||
if (list == null)
|
||||
list = new List<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
var sorted = true;
|
||||
var order = int.MinValue;
|
||||
foreach(var element in list)
|
||||
{
|
||||
list = new List<T>();
|
||||
if (element == null)
|
||||
{
|
||||
list.Remove(element);
|
||||
return list;
|
||||
}
|
||||
var elementType = element.GetType();
|
||||
var elementOrder = elementType.GetCustomAttribute<OrderAttribute>()?.Order ?? 0;
|
||||
if (elementOrder < order)
|
||||
sorted = false;
|
||||
order = elementOrder;
|
||||
}
|
||||
else
|
||||
|
||||
if (!sorted)
|
||||
{
|
||||
var sorted = true;
|
||||
var order = int.MinValue;
|
||||
foreach(var element in list)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
list.Remove(element);
|
||||
return list;
|
||||
}
|
||||
var elementType = element.GetType();
|
||||
var elementOrder = elementType.GetCustomAttribute<OrderAttribute>()?.Order ?? 0;
|
||||
if (elementOrder < order)
|
||||
sorted = false;
|
||||
order = elementOrder;
|
||||
}
|
||||
|
||||
if (!sorted)
|
||||
{
|
||||
list.Sort((x, y) => (x.GetType().GetCustomAttribute<OrderAttribute>()?.Order ?? 0).CompareTo(y.GetType().GetCustomAttribute<OrderAttribute>()?.Order ?? 0));
|
||||
}
|
||||
list.Sort((x, y) => (x.GetType().GetCustomAttribute<OrderAttribute>()?.Order ?? 0).CompareTo(y.GetType().GetCustomAttribute<OrderAttribute>()?.Order ?? 0));
|
||||
}
|
||||
}
|
||||
if (Foldout(_foldouts.Contains(list), label, true, EditorStyles.boldLabel))
|
||||
_foldouts.Add(list);
|
||||
else _foldouts.Remove(list);
|
||||
if (_foldouts.Contains(list))
|
||||
{
|
||||
foreach (var o in list)
|
||||
{
|
||||
if (o == null)
|
||||
|
|
@ -64,78 +67,65 @@ public class ListInspector<T> : BaseInspector<List<T>>
|
|||
GUI.backgroundColor = tint.TintColor.ToColor();
|
||||
}
|
||||
|
||||
using (new VerticalScope(ListItemStyle))
|
||||
using (new VerticalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
//if (listType.IsInterface)
|
||||
if(Foldout(_listItemFoldouts.Contains(o.GetHashCode()), o.ToString(), true))
|
||||
_listItemFoldouts.Add(o.GetHashCode());
|
||||
else
|
||||
_listItemFoldouts.Remove(o.GetHashCode());
|
||||
|
||||
if (inspectable != null)
|
||||
{
|
||||
if (Foldout(_foldouts.Contains(o), o.ToString(), true, EditorStyles.boldLabel))
|
||||
_foldouts.Add(o);
|
||||
else
|
||||
_foldouts.Remove(o);
|
||||
}
|
||||
else inspectorWindow.InspectMember("", o, parent, listType, true);
|
||||
|
||||
// var rect = GetControlRect(false,
|
||||
// GUILayout.Width(EditorGUIUtility.singleLineHeight));
|
||||
// GUI.DrawTexture(rect, Icons.Instance.minus, ScaleMode.StretchToFill, true, 1,
|
||||
// LabelColor, 0, 0);
|
||||
if (GUILayout.Button("-", GUILayout.Width((EditorGUIUtility.singleLineHeight - 3)*2), GUILayout.Height(EditorGUIUtility.singleLineHeight-3)))
|
||||
{
|
||||
list.Remove(o);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(_listItemFoldouts.Contains(o.GetHashCode()))
|
||||
{
|
||||
Space();
|
||||
|
||||
inspectorWindow.Inspect(o, true);
|
||||
}
|
||||
if(inspectable != null && _foldouts.Contains(o))
|
||||
inspectorWindow.InspectMember("", o, parent, o.GetType(), true);
|
||||
}
|
||||
|
||||
if(_tinted)
|
||||
GUI.backgroundColor = originalColor;
|
||||
}
|
||||
using (new HorizontalScope(ListItemStyle))
|
||||
using (new HorizontalScope(DatabaseInspector.ListItemStyle))
|
||||
{
|
||||
GUILayout.Label($"Add new {listType.Name}", GUILayout.ExpandWidth(true));
|
||||
GUILayout.Label($"Add new {listType.GetFullName()}", GUILayout.ExpandWidth(true));
|
||||
// var rect = GetControlRect(false, GUILayout.Width(EditorGUIUtility.singleLineHeight));
|
||||
// GUI.DrawTexture(rect, Icons.Instance.plus, ScaleMode.StretchToFill, true, 1, LabelColor, 0, 0);
|
||||
if (GUILayout.Button("+", GUILayout.Width((EditorGUIUtility.singleLineHeight - 3)*2), GUILayout.Height(EditorGUIUtility.singleLineHeight-3)))
|
||||
{
|
||||
if (listType.IsInterface)
|
||||
if (listType.IsAbstract || listType.IsInterface)
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
foreach (var childType in listType.GetAllInterfaceClasses())
|
||||
foreach (var childType in listType.GetAllChildClasses().Where(t=>!t.IsAbstract && !t.IsInterface))
|
||||
{
|
||||
menu.AddItem(new GUIContent(childType.Name), false, () =>
|
||||
{
|
||||
list.Add((T)Activator.CreateInstance(childType));
|
||||
});
|
||||
}
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
else if (listType.IsAbstract)
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
foreach (var childType in listType.GetAllChildClasses().Where(t=>!t.IsAbstract))
|
||||
{
|
||||
menu.AddItem(new GUIContent(childType.Name), false, () =>
|
||||
{
|
||||
list.Add((T)Activator.CreateInstance(childType));
|
||||
var o = (T) Activator.CreateInstance(childType);
|
||||
_foldouts.Add(o);
|
||||
list.Add(o);
|
||||
});
|
||||
}
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(Activator.CreateInstance<T>());
|
||||
var o = Activator.CreateInstance<T>();
|
||||
_foldouts.Add(o);
|
||||
list.Add(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else Debug.Log($"Field \"{label}\" is a list of non-Inspectable type {listType.Name}. No inspector was generated.");
|
||||
// }
|
||||
// else Debug.Log($"Field \"{label}\" is a list of non-Inspectable type {listType.Name}. No inspector was generated.");
|
||||
|
||||
return list;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ using UnityEditor;
|
|||
using UnityEngine;
|
||||
using static UnityEditor.EditorGUILayout;
|
||||
|
||||
|
||||
public class Float2Inspector : BaseInspector<float2>
|
||||
{
|
||||
public override float2 Inspect(string label, float2 value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
GUILayout.Label("X", GUILayout.Width(labelWidth));
|
||||
|
|
@ -24,7 +23,7 @@ public class Float3Inspector : BaseInspector<float3>
|
|||
{
|
||||
public override float3 Inspect(string label, float3 value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
GUILayout.Label("X", GUILayout.Width(labelWidth));
|
||||
|
|
@ -38,11 +37,23 @@ public class Float3Inspector : BaseInspector<float3>
|
|||
}
|
||||
}
|
||||
|
||||
public class Float3ColorInspector : BaseInspector<float3, InspectableColorAttribute>
|
||||
{
|
||||
public override float3 Inspect(string label, float3 value, object parent, DatabaseInspector inspectorWindow, InspectableColorAttribute attribute)
|
||||
{
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
return ColorField(value.ToColor()).ToFloat3();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Float4Inspector : BaseInspector<float4>
|
||||
{
|
||||
public override float4 Inspect(string label, float4 value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
GUILayout.Label("X", GUILayout.Width(labelWidth));
|
||||
|
|
@ -58,11 +69,23 @@ public class Float4Inspector : BaseInspector<float4>
|
|||
}
|
||||
}
|
||||
|
||||
public class Float4ColorInspector : BaseInspector<float4, InspectableColorAttribute>
|
||||
{
|
||||
public override float4 Inspect(string label, float4 value, object parent, DatabaseInspector inspectorWindow, InspectableColorAttribute attribute)
|
||||
{
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
return ColorField(value.ToColor()).ToFloat4();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Int2Inspector : BaseInspector<int2>
|
||||
{
|
||||
public override int2 Inspect(string label, int2 value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
GUILayout.Label("X", GUILayout.Width(labelWidth));
|
||||
|
|
@ -86,7 +109,7 @@ public class Int3Inspector : BaseInspector<int3>
|
|||
{
|
||||
public override int3 Inspect(string label, int3 value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
GUILayout.Label("X", GUILayout.Width(labelWidth));
|
||||
|
|
@ -104,7 +127,7 @@ public class Int4Inspector : BaseInspector<int4>
|
|||
{
|
||||
public override int4 Inspect(string label, int4 value, object parent, DatabaseInspector inspectorWindow)
|
||||
{
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
using (new HorizontalScope())
|
||||
{
|
||||
GUILayout.Label(label, GUILayout.Width(width));
|
||||
GUILayout.Label("X", GUILayout.Width(labelWidth));
|
||||
|
|
|
|||
|
|
@ -39,7 +39,15 @@ public static class UnityExtensions
|
|||
{
|
||||
return new AnimationCurve(keys.Select(v => new Keyframe(v.x, v.y, v.z, v.w)).ToArray());
|
||||
}
|
||||
|
||||
public static AnimationCurve ToCurve(this BezierCurve curve)
|
||||
{
|
||||
return new AnimationCurve(curve.Keys.Select(v => new Keyframe(v.x, v.y, v.z, v.w)).ToArray());
|
||||
}
|
||||
|
||||
public static Color ToColor(this float3 v) => new Color(v.x,v.y,v.z);
|
||||
public static float3 ToFloat3(this Color c) => float3(c.r,c.g,c.b);
|
||||
|
||||
public static Color ToColor(this float4 v) => new Color(v.x,v.y,v.z, v.w);
|
||||
public static float4 ToFloat4(this Color c) => float4(c.r, c.g, c.b, c.a);
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
"MessagePack",
|
||||
"Unity.Mathematics",
|
||||
"UniRx",
|
||||
"CultCache"
|
||||
"RethinkDB"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
|
|
|||
|
|
@ -4,26 +4,6 @@
|
|||
|
||||
using System;
|
||||
|
||||
public class NameAttribute : Attribute
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public NameAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class OrderAttribute : Attribute
|
||||
{
|
||||
public int Order;
|
||||
|
||||
public OrderAttribute(int order)
|
||||
{
|
||||
Order = order;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class EntityTypeRestrictionAttribute : Attribute
|
||||
{
|
||||
|
|
|
|||
|
|
@ -178,8 +178,8 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior
|
|||
|
||||
public override void Activate()
|
||||
{
|
||||
// if(CanFire)
|
||||
// Trigger();
|
||||
// base.Activate();
|
||||
if(CanFire)
|
||||
Trigger();
|
||||
base.Activate();
|
||||
}
|
||||
}
|
||||
|
|
@ -15,8 +15,8 @@ public class SensorData : BehaviorData
|
|||
[Inspectable, JsonProperty("sensitivity"), Key(3), RuntimeInspectable]
|
||||
public PerformanceStat Sensitivity = new PerformanceStat();
|
||||
|
||||
[InspectableAnimationCurve, JsonProperty("sensitivityCurve"), Key(4), RuntimeInspectable]
|
||||
public float4[] SensitivityCurve;
|
||||
[InspectableAnimationCurve, JsonProperty("sensCurve"), Key(4), RuntimeInspectable]
|
||||
public BezierCurve SensitivityCurve;
|
||||
|
||||
[Inspectable, JsonProperty("pingBoost"), Key(5), RuntimeInspectable]
|
||||
public PerformanceStat PingBoost;
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ public abstract class WeaponData : BehaviorData
|
|||
[Inspectable, JsonProperty("damage"), Key(2), RuntimeInspectable]
|
||||
public PerformanceStat Damage = new PerformanceStat();
|
||||
|
||||
[RangedFloatInspectable(0,1), JsonProperty("penetration"), Key(3), RuntimeInspectable]
|
||||
[InspectableRangedFloat(0,1), JsonProperty("penetration"), Key(3), RuntimeInspectable]
|
||||
public PerformanceStat Penetration = new PerformanceStat();
|
||||
|
||||
[RangedFloatInspectable(0,1), JsonProperty("damageSpread"), Key(4)]
|
||||
[InspectableRangedFloat(0,1), JsonProperty("damageSpread"), Key(4)]
|
||||
public PerformanceStat DamageSpread = new PerformanceStat();
|
||||
|
||||
[Inspectable, JsonProperty("minRange"), Key(5), RuntimeInspectable]
|
||||
|
|
@ -35,8 +35,8 @@ public abstract class WeaponData : BehaviorData
|
|||
[Inspectable, JsonProperty("range"), Key(6), RuntimeInspectable]
|
||||
public PerformanceStat Range = new PerformanceStat();
|
||||
|
||||
[InspectableAnimationCurve, JsonProperty("damageRange"), Key(7), RuntimeInspectable]
|
||||
public float4[] DamageCurve;
|
||||
[InspectableAnimationCurve, JsonProperty("damageCurve"), Key(7), RuntimeInspectable]
|
||||
public BezierCurve DamageCurve;
|
||||
|
||||
[InspectablePrefab, JsonProperty("effect"), Key(8)]
|
||||
public string EffectPrefab;
|
||||
|
|
|
|||
123
Assets/Scripts/ServerShared/BezierCurve.cs
Normal file
123
Assets/Scripts/ServerShared/BezierCurve.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
using System;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using Unity.Mathematics;
|
||||
using static Unity.Mathematics.math;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class BezierCurve
|
||||
{
|
||||
[JsonProperty("keys"), Key(0)] public float4[] Keys;
|
||||
|
||||
[IgnoreMember] private int2 _cachedIndices;
|
||||
|
||||
// Integrate area under curve between start and end time
|
||||
public float IntegrateCurve(float startTime, float endTime, int steps)
|
||||
{
|
||||
return Integrate(Evaluate, startTime, endTime, steps);
|
||||
}
|
||||
|
||||
// Integrate function f(x) using the trapezoidal rule between x=x_low..x_high
|
||||
public static float Integrate(Func<float, float> f, float x_low, float x_high, int N_steps)
|
||||
{
|
||||
float h = (x_high - x_low) / N_steps;
|
||||
float res = (f(x_low) + f(x_high)) / 2;
|
||||
for (int i = 1; i < N_steps; i++)
|
||||
{
|
||||
res += f(x_low + i * h);
|
||||
}
|
||||
return h * res;
|
||||
}
|
||||
|
||||
// public static float Screen(float a, float b)
|
||||
// {
|
||||
// return 1 - (1 - a)*(1 - b);
|
||||
// }
|
||||
|
||||
public float Evaluate(float time)
|
||||
{
|
||||
// Clamp time
|
||||
time = clamp(time, Keys[0].x, Keys[Keys.Length - 1].x);
|
||||
|
||||
FindSurroundingKeyframes(time, Keys);
|
||||
return HermiteInterpolate(time, Keys[_cachedIndices.x], Keys[_cachedIndices.y]);
|
||||
}
|
||||
|
||||
void FindSurroundingKeyframes(float time, float4[] curve)
|
||||
{
|
||||
// Check that time is within cached keyframe time
|
||||
if (time >= curve[_cachedIndices.x].x &&
|
||||
time <= curve[_cachedIndices.y].x)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Fall back to using dichotomic search.
|
||||
var length = curve.Length;
|
||||
int half;
|
||||
int middle;
|
||||
int first = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
half = length >> 1;
|
||||
middle = first + half;
|
||||
|
||||
if (time < curve[middle].x)
|
||||
{
|
||||
length = half;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = middle + 1;
|
||||
length = length - half - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If not within range, we pick the last element twice.
|
||||
var indices = int2(first - 1, min(curve.Length - 1, first));
|
||||
_cachedIndices = indices;
|
||||
}
|
||||
|
||||
float HermiteInterpolate(float time, in float4 leftKeyframe, in float4 rightKeyframe)
|
||||
{
|
||||
// Handle stepped curve.
|
||||
if (isinf(leftKeyframe.w) || isinf(rightKeyframe.z))
|
||||
{
|
||||
return leftKeyframe.y;
|
||||
}
|
||||
|
||||
float dx = rightKeyframe.x - leftKeyframe.x;
|
||||
float m0;
|
||||
float m1;
|
||||
float t;
|
||||
if (dx != 0.0f)
|
||||
{
|
||||
t = (time - leftKeyframe.x) / dx;
|
||||
m0 = leftKeyframe.w * dx;
|
||||
m1 = rightKeyframe.z * dx;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = 0.0f;
|
||||
m0 = 0;
|
||||
m1 = 0;
|
||||
}
|
||||
|
||||
return HermiteInterpolate(t, leftKeyframe.y, m0, m1, rightKeyframe.y);
|
||||
}
|
||||
|
||||
static float HermiteInterpolate(float t, float p0, float m0, float m1, float p1)
|
||||
{
|
||||
// Unrolled the equations to avoid precision issue.
|
||||
// (2 * t^3 -3 * t^2 +1) * p0 + (t^3 - 2 * t^2 + t) * m0 + (-2 * t^3 + 3 * t^2) * p1 + (t^3 - t^2) * m1
|
||||
|
||||
var a = 2.0f * p0 + m0 - 2.0f * p1 + m1;
|
||||
var b = -3.0f * p0 - 2.0f * m0 + 3.0f * p1 - m1;
|
||||
var c = m0;
|
||||
var d = p0;
|
||||
|
||||
return t * (t * (a * t + b) + c) + d;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/ServerShared/BezierCurve.cs.meta
Normal file
11
Assets/Scripts/ServerShared/BezierCurve.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cdb4803cfcd147f40a7dbb0343aebedf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
using System;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class GlobalSettingsAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ExternalEntryAttribute : Attribute { }
|
||||
|
||||
|
|
@ -8,15 +11,6 @@ public class InspectableAttribute : Attribute { }
|
|||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public abstract class PreferredInspectorAttribute : InspectableAttribute { }
|
||||
|
||||
public class InspectableUnityObjectAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public Type ObjectType;
|
||||
|
||||
public InspectableUnityObjectAttribute(Type type)
|
||||
{
|
||||
ObjectType = type;
|
||||
}
|
||||
}
|
||||
public class InspectableTextAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectablePrefabAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableTextureAttribute : PreferredInspectorAttribute { }
|
||||
|
|
@ -25,6 +19,16 @@ public class InspectableTemperatureAttribute : PreferredInspectorAttribute { }
|
|||
public class InspectableAnimationCurveAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableColorAttribute : PreferredInspectorAttribute { }
|
||||
|
||||
public class InspectableEnumValuesAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public Type EnumType;
|
||||
|
||||
public InspectableEnumValuesAttribute(Type enumType)
|
||||
{
|
||||
EnumType = enumType;
|
||||
}
|
||||
}
|
||||
|
||||
public class InspectableDatabaseLinkAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly Type EntryType;
|
||||
|
|
@ -35,22 +39,22 @@ public class InspectableDatabaseLinkAttribute : PreferredInspectorAttribute
|
|||
}
|
||||
}
|
||||
|
||||
public class RangedFloatInspectableAttribute : PreferredInspectorAttribute
|
||||
public class InspectableRangedFloatAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly float Min, Max;
|
||||
|
||||
public RangedFloatInspectableAttribute(float min, float max)
|
||||
public InspectableRangedFloatAttribute(float min, float max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
}
|
||||
|
||||
public class RangedIntInspectableAttribute : PreferredInspectorAttribute
|
||||
public class InspectableRangedIntAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly int Min, Max;
|
||||
|
||||
public RangedIntInspectableAttribute(int min, int max)
|
||||
public InspectableRangedIntAttribute(int min, int max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
|
|
@ -107,4 +111,24 @@ public class RethinkTableAttribute : Attribute
|
|||
{
|
||||
TableName = tableName;
|
||||
}
|
||||
}
|
||||
|
||||
public class NameAttribute : Attribute
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public NameAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class OrderAttribute : Attribute
|
||||
{
|
||||
public int Order;
|
||||
|
||||
public OrderAttribute(int order)
|
||||
{
|
||||
Order = order;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
public static class CollectionExtensions
|
||||
{
|
||||
// https://stackoverflow.com/a/800469
|
||||
public static string GetHashSHA1(this byte[] data)
|
||||
{
|
||||
using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider())
|
||||
{
|
||||
return string.Concat(sha1.ComputeHash(data).Select(x => x.ToString("X2")));
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/3188835
|
||||
public static T MaxBy<T, U>(this IEnumerable<T> items, Func<T, U> selector)
|
||||
{
|
||||
if (!items.Any())
|
||||
{
|
||||
throw new InvalidOperationException("Empty input sequence");
|
||||
}
|
||||
|
||||
var comparer = Comparer<U>.Default;
|
||||
T maxItem = items.First();
|
||||
U maxValue = selector(maxItem);
|
||||
|
||||
foreach (T item in items.Skip(1))
|
||||
{
|
||||
// Get the value of the item and compare it to the current max.
|
||||
U value = selector(item);
|
||||
if (comparer.Compare(value, maxValue) > 0)
|
||||
{
|
||||
maxValue = value;
|
||||
maxItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
return maxItem;
|
||||
}
|
||||
|
||||
public static T MinBy<T, U>(this IEnumerable<T> items, Func<T, U> selector)
|
||||
{
|
||||
if (!items.Any())
|
||||
{
|
||||
throw new InvalidOperationException("Empty input sequence");
|
||||
}
|
||||
|
||||
var comparer = Comparer<U>.Default;
|
||||
T maxItem = items.First();
|
||||
U maxValue = selector(maxItem);
|
||||
|
||||
foreach (T item in items.Skip(1))
|
||||
{
|
||||
// Get the value of the item and compare it to the current max.
|
||||
U value = selector(item);
|
||||
if (comparer.Compare(value, maxValue) < 0)
|
||||
{
|
||||
maxValue = value;
|
||||
maxItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
return maxItem;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eed05df00a9a6b84292c81be1662a66e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -14,10 +14,10 @@ public class CultCache
|
|||
{
|
||||
public event Action<DatabaseEntry> OnDataInsertLocal;
|
||||
public event Action<DatabaseEntry> OnDataUpdateLocal;
|
||||
public event Action<DatabaseEntry> OnDataDeleteLocal;
|
||||
public event Action<DatabaseEntry> OnDataRemoveLocal;
|
||||
public event Action<DatabaseEntry> OnDataInsertRemote;
|
||||
public event Action<DatabaseEntry> OnDataUpdateRemote;
|
||||
public event Action<DatabaseEntry> OnDataDeleteRemote;
|
||||
public event Action<DatabaseEntry> OnDataRemoveRemote;
|
||||
|
||||
private readonly object addLock = new object();
|
||||
|
||||
|
|
@ -26,6 +26,7 @@ public class CultCache
|
|||
|
||||
private readonly Dictionary<Guid, DatabaseEntry> _entries = new Dictionary<Guid, DatabaseEntry>();
|
||||
|
||||
private readonly Dictionary<Type, DatabaseEntry> _globals = new Dictionary<Type, DatabaseEntry>();
|
||||
private readonly Dictionary<Type, HashSet<DatabaseEntry>> _types = new Dictionary<Type, HashSet<DatabaseEntry>>();
|
||||
|
||||
private readonly Dictionary<Type, (DirectoryInfo directory, List<Guid> entries)> _externalTypes = new Dictionary<Type, (DirectoryInfo directory, List<Guid> entries)>();
|
||||
|
|
@ -48,6 +49,7 @@ public class CultCache
|
|||
|
||||
public CultCache(string filePath)
|
||||
{
|
||||
DatabaseLinkBase.Cache = this;
|
||||
RegisterResolver.Register();
|
||||
_filePath = filePath;
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
|
|
@ -61,6 +63,7 @@ public class CultCache
|
|||
var linkFields = type.GetFields().Where(f => f.FieldType.IsAssignableToGenericType(typeof(DatabaseLink<>))).ToArray();
|
||||
if(linkFields.Length > 0)
|
||||
_linkFields[type] = linkFields;
|
||||
|
||||
if (type.GetCustomAttribute<ExternalEntryAttribute>() != null)
|
||||
{
|
||||
var typeDirectory = dataDirectory.CreateSubdirectory(type.Name);
|
||||
|
|
@ -79,6 +82,12 @@ public class CultCache
|
|||
}
|
||||
}
|
||||
else _types[type] = new HashSet<DatabaseEntry>();
|
||||
|
||||
if (type.GetCustomAttribute<GlobalSettingsAttribute>() != null)
|
||||
{
|
||||
_globals[type] = null;
|
||||
Add(Activator.CreateInstance(type) as DatabaseEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,19 +99,9 @@ public class CultCache
|
|||
{
|
||||
var exists = _entries.ContainsKey(entry.ID);
|
||||
|
||||
// If an external entry is added, store it separately
|
||||
var type = entry.GetType();
|
||||
if (_linkFields.ContainsKey(type))
|
||||
{
|
||||
foreach (var linkField in _linkFields[type])
|
||||
{
|
||||
var link = (DatabaseLinkBase) linkField.GetValue(entry);
|
||||
if (link != null)
|
||||
{
|
||||
link.Cache = this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If an external entry is added, store it separately
|
||||
if (_externalTypes.ContainsKey(type))
|
||||
{
|
||||
if (_externalEntries.ContainsKey(entry.ID))
|
||||
|
|
@ -119,6 +118,16 @@ public class CultCache
|
|||
}
|
||||
else
|
||||
{
|
||||
if (_globals.ContainsKey(type))
|
||||
{
|
||||
if(_globals[type]!=null)
|
||||
{
|
||||
Remove(_globals[type], remote);
|
||||
exists = true;
|
||||
}
|
||||
_globals[type] = entry;
|
||||
}
|
||||
|
||||
_entries[entry.ID] = entry;
|
||||
_types[type].Add(entry);
|
||||
foreach (var parentType in type.GetParentTypes())
|
||||
|
|
@ -146,6 +155,9 @@ public class CultCache
|
|||
}
|
||||
}
|
||||
|
||||
public bool IsExternal(DatabaseEntry entry) => _externalTypes.ContainsKey(entry.GetType());
|
||||
public bool IsGlobal(DatabaseEntry entry) => _globals.ContainsKey(entry.GetType());
|
||||
|
||||
public void AddAll(IEnumerable<DatabaseEntry> entries, bool remote = false)
|
||||
{
|
||||
foreach (var entry in entries)
|
||||
|
|
@ -178,6 +190,17 @@ public class CultCache
|
|||
return Get(guid) as T;
|
||||
}
|
||||
|
||||
public DatabaseEntry GetGlobal(Type type)
|
||||
{
|
||||
if (_globals.ContainsKey(type)) return _globals[type];
|
||||
return null;
|
||||
}
|
||||
|
||||
public T GetGlobal<T>() where T : DatabaseEntry
|
||||
{
|
||||
return GetGlobal(typeof(T)) as T;
|
||||
}
|
||||
|
||||
public IEnumerable<DatabaseEntry> GetAll(Type type)
|
||||
{
|
||||
if (_externalTypes.ContainsKey(type))
|
||||
|
|
@ -197,14 +220,19 @@ public class CultCache
|
|||
return !_types.ContainsKey(type) ? Enumerable.Empty<T>() : _types[type].Cast<T>();
|
||||
}
|
||||
|
||||
public void Delete(DatabaseEntry entry, bool remote = false)
|
||||
public void Remove(DatabaseEntry entry, bool remote = false)
|
||||
{
|
||||
_entries.Remove(entry.ID);
|
||||
foreach (var parentType in entry.GetType().GetParentTypes())
|
||||
{
|
||||
if(_types.ContainsKey(parentType))
|
||||
_types[parentType].Remove(entry);
|
||||
}
|
||||
|
||||
if (remote)
|
||||
OnDataDeleteRemote?.Invoke(entry);
|
||||
OnDataRemoveRemote?.Invoke(entry);
|
||||
else
|
||||
OnDataDeleteLocal?.Invoke(entry);
|
||||
OnDataRemoveLocal?.Invoke(entry);
|
||||
}
|
||||
|
||||
public void Load()
|
||||
|
|
|
|||
|
|
@ -55,6 +55,17 @@ public abstract class DatabaseEntry
|
|||
{
|
||||
[JsonProperty("id"), Key(0)]
|
||||
public Guid ID = Guid.NewGuid();
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ID.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is DatabaseEntry entry) return entry.ID == ID;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
|
|
@ -71,5 +82,10 @@ public class DatabaseLinkBase
|
|||
public Guid LinkID;
|
||||
|
||||
[IgnoreMember]
|
||||
public CultCache Cache;
|
||||
public static CultCache Cache;
|
||||
}
|
||||
|
||||
public interface ITintInspector
|
||||
{
|
||||
float3 TintColor { get; }
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
public static class MathExtensions
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5effe288f2074414930e040d4531709f
|
||||
timeCreated: 1617057296
|
||||
|
|
@ -2,9 +2,11 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class CultCacheExtensions
|
||||
public static class ReflectionExtensions
|
||||
{
|
||||
private static Dictionary<Type,Type[]> InterfaceClasses = new Dictionary<Type, Type[]>();
|
||||
public static Type[] GetAllInterfaceClasses(this Type type)
|
||||
|
|
@ -85,9 +87,34 @@ public static class CultCacheExtensions
|
|||
|
||||
return IsAssignableToGenericType(baseType, genericType);
|
||||
}
|
||||
|
||||
public static async void WrapAwait(this Task task)
|
||||
|
||||
public static string SplitCamelCase( this string str )
|
||||
{
|
||||
await task;
|
||||
return Regex.Replace(
|
||||
Regex.Replace(
|
||||
str,
|
||||
@"(\P{Ll})(\P{Ll}\p{Ll})",
|
||||
"$1 $2"
|
||||
),
|
||||
@"(\p{Ll})(\P{Ll})",
|
||||
"$1 $2"
|
||||
);
|
||||
}
|
||||
|
||||
public static string FormatTypeName(this string typeName)
|
||||
{
|
||||
return (typeName.EndsWith("Data")
|
||||
? typeName.Substring(0, typeName.Length - 4)
|
||||
: typeName).SplitCamelCase();
|
||||
}
|
||||
|
||||
public static string GetFullName(this Type t)
|
||||
{
|
||||
if (!t.IsGenericType)
|
||||
return t.Name.FormatTypeName();
|
||||
|
||||
var name = t.Name.FormatTypeName();
|
||||
return
|
||||
$"{name.Substring(0, name.LastIndexOf("`"))}{t.GetGenericArguments().Aggregate("<", (aggregate, type) => $"{aggregate}{(aggregate == "<" ? "" : ",")}{GetFullName(type)}")}>";
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@ using Newtonsoft.Json;
|
|||
using RethinkDb.Driver;
|
||||
using RethinkDb.Driver.Ast;
|
||||
using RethinkDb.Driver.Net;
|
||||
using UnityEngine;
|
||||
|
||||
public static class RethinkConnection
|
||||
{
|
||||
|
|
@ -47,7 +46,6 @@ public static class RethinkConnection
|
|||
var connection = R.Connection()
|
||||
.Hostname(connectionString.Substring(0,connectionStringDomainLength))
|
||||
.Port(port).Timeout(60).Connect();
|
||||
Debug.Log("Connected to RethinkDB");
|
||||
|
||||
var tables = R.Db(dbName).TableList().RunAtom<string[]>(connection);
|
||||
|
||||
|
|
@ -61,35 +59,32 @@ public static class RethinkConnection
|
|||
{
|
||||
var table = entry.GetType().GetCustomAttribute<RethinkTableAttribute>()?.TableName ?? "Other";
|
||||
var result = await R
|
||||
.Db("Aetheria")
|
||||
.Db(dbName)
|
||||
.Table(table)
|
||||
.Get(entry.ID)
|
||||
.Replace(entry)
|
||||
.RunAsync(connection);
|
||||
Debug.Log($"Uploaded entry to RethinkDB: {entry.ID} result: {result}");
|
||||
};
|
||||
|
||||
cache.OnDataInsertLocal += async entry =>
|
||||
{
|
||||
var table = entry.GetType().GetCustomAttribute<RethinkTableAttribute>()?.TableName ?? "Other";
|
||||
var result = await R
|
||||
.Db("Aetheria")
|
||||
.Db(dbName)
|
||||
.Table(table)
|
||||
.Insert(entry)
|
||||
.RunAsync(connection);
|
||||
Debug.Log($"Inserted entry to RethinkDB: {entry.ID} result: {result}");
|
||||
};
|
||||
|
||||
cache.OnDataDeleteLocal += async entry =>
|
||||
cache.OnDataRemoveLocal += async entry =>
|
||||
{
|
||||
var table = entry.GetType().GetCustomAttribute<RethinkTableAttribute>()?.TableName ?? "Other";
|
||||
var result = await R
|
||||
.Db("Aetheria")
|
||||
.Db(dbName)
|
||||
.Table(table)
|
||||
.Get(entry.ID)
|
||||
.Delete()
|
||||
.RunAsync(connection);
|
||||
Debug.Log($"Deleted entry from RethinkDB: {entry.ID} result: {result}");
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -101,18 +96,17 @@ public static class RethinkConnection
|
|||
Task.Run(async () =>
|
||||
{
|
||||
status.TotalEntries += R
|
||||
.Db("Aetheria")
|
||||
.Db(dbName)
|
||||
.Table(table)
|
||||
.Count().RunAtom<int>(connection);
|
||||
|
||||
var result = await R
|
||||
.Db("Aetheria")
|
||||
.Db(dbName)
|
||||
.Table(table)
|
||||
.RunCursorAsync<DatabaseEntry>(connection);
|
||||
while (await result.MoveNextAsync())
|
||||
{
|
||||
var entry = result.Current;
|
||||
//Debug.Log($"Received Items entry from RethinkDB: {entry.GetType()} {(entry as INamedEntry)?.EntryName ?? ""}:{entry.ID}");
|
||||
cache.Add(entry, true);
|
||||
status.RetrievedEntries++;
|
||||
}
|
||||
|
|
@ -122,34 +116,30 @@ public static class RethinkConnection
|
|||
Task.Run(async () =>
|
||||
{
|
||||
var result = await R
|
||||
.Db("Aetheria")
|
||||
.Db(dbName)
|
||||
.Table(table)
|
||||
.Changes()
|
||||
.RunChangesAsync<DatabaseEntry>(connection);
|
||||
while (await result.MoveNextAsync())
|
||||
{
|
||||
var change = result.Current;
|
||||
if(change.OldValue == null)
|
||||
Debug.Log($"Received change from RethinkDB (Entry Created): {change.NewValue.ID}");
|
||||
else if(change.NewValue == null)
|
||||
Debug.Log($"Received change from RethinkDB (Entry Deleted): {change.OldValue.ID}");
|
||||
else
|
||||
Debug.Log($"Received change from RethinkDB: {change.NewValue.ID}");
|
||||
cache.Add(change.NewValue, true);
|
||||
}
|
||||
}).WrapAwait();
|
||||
}
|
||||
|
||||
|
||||
// Observable.Timer(DateTimeOffset.Now, TimeSpan.FromSeconds(60)).Subscribe(_ =>
|
||||
// {
|
||||
// Debug.Log(R.Now().Run<DateTime>(connection).ToString() as string);
|
||||
// });
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncAwaitExtensions
|
||||
{
|
||||
public static async void WrapAwait(this Task task)
|
||||
{
|
||||
await task;
|
||||
}
|
||||
}
|
||||
|
||||
public class RethinkQueryStatus
|
||||
{
|
||||
public int RetrievedEntries;
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using MessagePack;
|
||||
using MessagePack.ReactivePropertyExtension;
|
||||
using MessagePack.Resolvers;
|
||||
|
||||
public static class RegisterResolver
|
||||
|
|
@ -16,8 +15,7 @@ public static class RegisterResolver
|
|||
MathResolver.Instance,
|
||||
TypeResolver.Instance,
|
||||
NativeGuidResolver.Instance,
|
||||
StandardResolver.Instance,
|
||||
ReactivePropertyResolver.Instance
|
||||
StandardResolver.Instance
|
||||
);
|
||||
var options = MessagePackSerializerOptions.Standard.WithResolver(resolver);
|
||||
MessagePackSerializer.DefaultOptions = options;
|
||||
|
|
|
|||
16
Assets/Scripts/ServerShared/EnumDictionary.cs
Normal file
16
Assets/Scripts/ServerShared/EnumDictionary.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class EnumDictionary<E, T> where E : Enum
|
||||
{
|
||||
[JsonProperty("values"), Key(0)] public T[] Values;
|
||||
|
||||
public EnumDictionary()
|
||||
{
|
||||
Values = new T[Enum.GetNames(typeof(E)).Length];
|
||||
}
|
||||
|
||||
public T this[E key] => Values[Convert.ToInt32(key)];
|
||||
}
|
||||
3
Assets/Scripts/ServerShared/EnumDictionary.cs.meta
Normal file
3
Assets/Scripts/ServerShared/EnumDictionary.cs.meta
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 96c57746cba54d3f9933d93b3242df04
|
||||
timeCreated: 1617745268
|
||||
|
|
@ -22,15 +22,6 @@ public static class Extensions
|
|||
{
|
||||
return baseType.GetInterfaces().Any(interfaceType.Equals);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/800469
|
||||
public static string GetHashSHA1(this byte[] data)
|
||||
{
|
||||
using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider())
|
||||
{
|
||||
return string.Concat(sha1.ComputeHash(data).Select(x => x.ToString("X2")));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Send<T>(this NetPeer peer, T message, DeliveryMethod method = DeliveryMethod.ReliableOrdered) where T : Message
|
||||
{
|
||||
|
|
@ -125,26 +116,6 @@ public static class Extensions
|
|||
throw new ArgumentOutOfRangeException(nameof(rotation), rotation, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static string SplitCamelCase( this string str )
|
||||
{
|
||||
return Regex.Replace(
|
||||
Regex.Replace(
|
||||
str,
|
||||
@"(\P{Ll})(\P{Ll}\p{Ll})",
|
||||
"$1 $2"
|
||||
),
|
||||
@"(\p{Ll})(\P{Ll})",
|
||||
"$1 $2"
|
||||
);
|
||||
}
|
||||
|
||||
public static string FormatTypeName(this string typeName)
|
||||
{
|
||||
return (typeName.EndsWith("Data")
|
||||
? typeName.Substring(0, typeName.Length - 4)
|
||||
: typeName).SplitCamelCase();
|
||||
}
|
||||
|
||||
public static string SignificantDigits(this float d, int digits=10)
|
||||
{
|
||||
|
|
@ -177,152 +148,11 @@ public static class Extensions
|
|||
return pair.Equals(new KeyValuePair<T, TU>());
|
||||
}
|
||||
|
||||
private static Dictionary<float4[], int2> _cachedIndices = new Dictionary<float4[], int2>();
|
||||
public static float Evaluate(this float4[] curve, float time)
|
||||
{
|
||||
// Clamp time
|
||||
time = math.clamp(time, curve[0].x, curve[curve.Length - 1].x);
|
||||
|
||||
FindSurroundingKeyframes(time, curve);
|
||||
return HermiteInterpolate(time, curve[_cachedIndices[curve].x], curve[_cachedIndices[curve].y]);
|
||||
}
|
||||
|
||||
static void FindSurroundingKeyframes(float time, float4[] curve)
|
||||
{
|
||||
// Check that time is within cached keyframe time
|
||||
if (_cachedIndices.ContainsKey(curve) &&
|
||||
_cachedIndices[curve].x != _cachedIndices[curve].y &&
|
||||
time >= curve[_cachedIndices[curve].x].x &&
|
||||
time <= curve[_cachedIndices[curve].y].x)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Fall back to using dichotomic search.
|
||||
var length = curve.Length;
|
||||
int half;
|
||||
int middle;
|
||||
int first = 0;
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
half = length >> 1;
|
||||
middle = first + half;
|
||||
|
||||
if (time < curve[middle].x)
|
||||
{
|
||||
length = half;
|
||||
}
|
||||
else
|
||||
{
|
||||
first = middle + 1;
|
||||
length = length - half - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If not within range, we pick the last element twice.
|
||||
var indices = int2(first - 1, math.min(curve.Length - 1, first));
|
||||
_cachedIndices[curve] = indices;
|
||||
}
|
||||
|
||||
static float HermiteInterpolate(float time, in float4 leftKeyframe, in float4 rightKeyframe)
|
||||
{
|
||||
// Handle stepped curve.
|
||||
if (math.isinf(leftKeyframe.w) || math.isinf(rightKeyframe.z))
|
||||
{
|
||||
return leftKeyframe.y;
|
||||
}
|
||||
|
||||
float dx = rightKeyframe.x - leftKeyframe.x;
|
||||
float m0;
|
||||
float m1;
|
||||
float t;
|
||||
if (dx != 0.0f)
|
||||
{
|
||||
t = (time - leftKeyframe.x) / dx;
|
||||
m0 = leftKeyframe.w * dx;
|
||||
m1 = rightKeyframe.z * dx;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = 0.0f;
|
||||
m0 = 0;
|
||||
m1 = 0;
|
||||
}
|
||||
|
||||
return HermiteInterpolate(t, leftKeyframe.y, m0, m1, rightKeyframe.y);
|
||||
}
|
||||
|
||||
static float HermiteInterpolate(float t, float p0, float m0, float m1, float p1)
|
||||
{
|
||||
// Unrolled the equations to avoid precision issue.
|
||||
// (2 * t^3 -3 * t^2 +1) * p0 + (t^3 - 2 * t^2 + t) * m0 + (-2 * t^3 + 3 * t^2) * p1 + (t^3 - t^2) * m1
|
||||
|
||||
var a = 2.0f * p0 + m0 - 2.0f * p1 + m1;
|
||||
var b = -3.0f * p0 - 2.0f * m0 + 3.0f * p1 - m1;
|
||||
var c = m0;
|
||||
var d = p0;
|
||||
|
||||
return t * (t * (a * t + b) + c) + d;
|
||||
}
|
||||
|
||||
public static float Angle(this float2 from, float2 to)
|
||||
{
|
||||
var num = sqrt(lengthsq(from) * lengthsq(to));
|
||||
return num < 1.00000000362749E-15 ? 0.0f : acos(clamp(dot(from, to) / num, -1f, 1f)) * 57.29578f;
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/3188835
|
||||
public static T MaxBy<T, U>(this IEnumerable<T> items, Func<T, U> selector)
|
||||
{
|
||||
if (!items.Any())
|
||||
{
|
||||
throw new InvalidOperationException("Empty input sequence");
|
||||
}
|
||||
|
||||
var comparer = Comparer<U>.Default;
|
||||
T maxItem = items.First();
|
||||
U maxValue = selector(maxItem);
|
||||
|
||||
foreach (T item in items.Skip(1))
|
||||
{
|
||||
// Get the value of the item and compare it to the current max.
|
||||
U value = selector(item);
|
||||
if (comparer.Compare(value, maxValue) > 0)
|
||||
{
|
||||
maxValue = value;
|
||||
maxItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
return maxItem;
|
||||
}
|
||||
|
||||
public static T MinBy<T, U>(this IEnumerable<T> items, Func<T, U> selector)
|
||||
{
|
||||
if (!items.Any())
|
||||
{
|
||||
throw new InvalidOperationException("Empty input sequence");
|
||||
}
|
||||
|
||||
var comparer = Comparer<U>.Default;
|
||||
T maxItem = items.First();
|
||||
U maxValue = selector(maxItem);
|
||||
|
||||
foreach (T item in items.Skip(1))
|
||||
{
|
||||
// Get the value of the item and compare it to the current max.
|
||||
U value = selector(item);
|
||||
if (comparer.Compare(value, maxValue) < 0)
|
||||
{
|
||||
maxValue = value;
|
||||
maxItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
return maxItem;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/Burtsev-Alexey/net-object-deep-copy
|
||||
|
|
|
|||
|
|
@ -322,8 +322,8 @@ public abstract class EquippableItemData : CraftedItemData
|
|||
// [InspectableField, JsonProperty("heatExponent"), Key(16), SimplePerformanceStat]
|
||||
// public PerformanceStat HeatExponent = new PerformanceStat();
|
||||
|
||||
[InspectableAnimationCurve, JsonProperty("performanceCurve"), Key(17)]
|
||||
public float4[] HeatPerformanceCurve;
|
||||
[InspectableAnimationCurve, JsonProperty("heatCurve"), Key(17)]
|
||||
public BezierCurve HeatPerformanceCurve;
|
||||
|
||||
[Inspectable, JsonProperty("resilience"), Key(18)]
|
||||
public float ThermalResilience = 1;
|
||||
|
|
@ -553,9 +553,4 @@ public class PersonalityAttribute : DatabaseEntry, INamedEntry
|
|||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ITintInspector
|
||||
{
|
||||
float3 TintColor { get; }
|
||||
}
|
||||
Loading…
Reference in a new issue