Skip to content

Commit

Permalink
Merge pull request #36 from Nytra/main
Browse files Browse the repository at this point in the history
Allow ComponentsDataFeed to enumerate the component library, add ButtonAttachComponent, cleanup stuff
  • Loading branch information
Xlinka committed Jul 1, 2024
2 parents 5b15c61 + 4192136 commit 51fb4ee
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using FrooxEngine;
using FrooxEngine.Undo;

namespace Obsidian;

[Category(new string[] { "Obsidian/Common UI/Button Interactions" })]
public class ButtonAttachComponent : Component, IButtonPressReceiver, IComponent, IComponentBase, IDestroyable, IWorker, IWorldElement, IUpdatable, IChangeable, IAudioUpdatable, IInitializable, ILinkable
{
public readonly SyncRef<Slot> TargetSlot;

public readonly SyncType ComponentType;

public readonly Sync<bool> Undoable;

protected override void OnAttach()
{
base.OnAwake();
Undoable.Value = true;
}

public void Pressed(IButton button, ButtonEventData eventData)
{
Slot target = TargetSlot.Target;
Type componentType = ComponentType.Value;
if (target != null && componentType != null && componentType.ContainsGenericParameters == false)
{
var comp = target.AttachComponent(componentType);
if (Undoable)
{
comp.CreateSpawnUndoPoint();
}
}
}

public void Pressing(IButton button, ButtonEventData eventData)
{
}

public void Released(IButton button, ButtonEventData eventData)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,37 @@ public class ComponentData

public Component component;

private Type _componentType;

public bool Submitted { get; private set; }

public string MainName
{
get
{
return component.Name;
return component?.Name ?? _componentType.Name;
}
}

public string uniqueId;

public int MemberCount => members.Count;

public Type ComponentType => component?.GetType() ?? _componentType;

public bool IsGenericType => ComponentType.IsGenericType;

public Type GenericTypeDefinition => IsGenericType ? ComponentType.GetGenericTypeDefinition() : null;

public ComponentData(Component component)
{
this.component = component;
_componentType = component.GetType();
}

public ComponentData(Type type)
{
this._componentType = type;
}

public void MarkSubmitted()
Expand Down Expand Up @@ -87,12 +103,9 @@ public bool MatchesSearchParameters(List<string> optionalTerms, List<string> req

public bool MatchesTerm(string term)
{
if (component != null)
if (ContainsTerm(MainName, term))
{
if (ContainsTerm(component.Name, term))
{
return true;
}
return true;
}
return false;
}
Expand All @@ -108,6 +121,6 @@ private static bool ContainsTerm(string str, string term)

public override string ToString()
{
return $"Name: {MainName}, ReferenceID: {component.ReferenceID}, Members: {members.Count}";
return $"Name: {MainName}, UniqueID: {uniqueId}, MemberCount: {MemberCount}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class ComponentDataFeedItem : DataFeedItem

public ComponentDataFeedItem(ComponentData componentData)
{
InitBase(componentData.component.ReferenceID.ToString(), null, null, componentData.MainName);
InitBase(componentData.uniqueId, null, null, componentData.MainName);
Data = componentData;
foreach (ISyncMember member in componentData.members)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Elements.Core;
using FrooxEngine;
using SkyFrost.Base;

namespace Obsidian;

// This feed has two functions.

// If TargetSlot has a reference, it returns the components on that slot, optionally also returning components on children slots (IncludeChildrenSlots bool)
// It also returns the sync members (fields, lists etc) as DataFeedEntity<ISyncMember>

// If TargetSlot is null, it returns the components from the component library, which includes the categories (DataFeedCategoryItem)
// When enumerating the component library, the Component reference on the ComponentDataItemInterface will be null and there will be no members

[Category(new string[] { "Obsidian/Radiant UI/Data Feeds/Feeds" })]
public class ComponentsDataFeed : Component, IDataFeedComponent, IDataFeed, IWorldElement
{
Expand All @@ -19,23 +28,32 @@ public class ComponentsDataFeed : Component, IDataFeedComponent, IDataFeed, IWor

private Slot _lastSlot = null;

private void AddComponent(Component c)
private static HashSet<Type> _componentTypes = new();

private static bool SearchStringValid(string str)
{
return !string.IsNullOrWhiteSpace(str) && str.Length >= 3;
}

private void OnSlotComponentAdded(Component c)
{
// If local elements are written to synced fields it can cause exceptions and crashes
if (c.IsLocalElement) return;
foreach (KeyValuePair<SearchPhraseFeedUpdateHandler, ComponentsDataFeedData> updateHandler in _updateHandlers)
{
var data = updateHandler.Value.RegisterComponent(c);
foreach (ISyncMember syncMember in data.component.SyncMembers)
var result = updateHandler.Value.AddComponent(c);
foreach (ISyncMember syncMember in result.data.component.SyncMembers)
{
if (syncMember.IsLocalElement) continue;
data.AddMember(syncMember);
if (FilterMember(syncMember))
{
result.data.AddMember(syncMember);
}
}
ProcessUpdate(updateHandler.Key, data);
ProcessUpdate(updateHandler.Key, result.data);
}
}

private void RemoveComponent(Component c)
private void OnSlotComponentRemoved(Component c)
{
foreach (KeyValuePair<SearchPhraseFeedUpdateHandler, ComponentsDataFeedData> updateHandler in _updateHandlers)
{
Expand All @@ -53,22 +71,28 @@ private void Update()
}
}

private bool FilterMember(ISyncMember member)
{
if (member.IsLocalElement) return false;
return true;
}

private void ProcessUpdate(SearchPhraseFeedUpdateHandler handler, ComponentData data)
{
bool flag = true;
if (!string.IsNullOrEmpty(handler.searchPhrase))
{
List<string> list = Pool.BorrowList<string>();
List<string> list2 = Pool.BorrowList<string>();
List<string> list3 = Pool.BorrowList<string>();
SearchQueryParser.Parse(handler.searchPhrase, list, list2, list3);
if (!data.MatchesSearchParameters(list, list2, list3))
List<string> optionalTerms = Pool.BorrowList<string>();
List<string> requiredTerms = Pool.BorrowList<string>();
List<string> excludedTerms = Pool.BorrowList<string>();
SearchQueryParser.Parse(handler.searchPhrase, optionalTerms, requiredTerms, excludedTerms);
if (!data.MatchesSearchParameters(optionalTerms, requiredTerms, excludedTerms))
{
flag = false;
}
Pool.Return(ref list);
Pool.Return(ref list2);
Pool.Return(ref list3);
Pool.Return(ref optionalTerms);
Pool.Return(ref requiredTerms);
Pool.Return(ref excludedTerms);
}
if (!flag)
{
Expand All @@ -86,14 +110,20 @@ private void ProcessUpdate(SearchPhraseFeedUpdateHandler handler, ComponentData

private void Subscribe(Slot s)
{
s.ComponentAdded += AddComponent;
s.ComponentRemoved += RemoveComponent;
s.ComponentAdded += OnSlotComponentAdded;
s.ComponentRemoved += OnSlotComponentRemoved;
}

private void Unsubscribe(Slot s)
{
s.ComponentAdded -= AddComponent;
s.ComponentRemoved -= RemoveComponent;
s.ComponentAdded -= OnSlotComponentAdded;
s.ComponentRemoved -= OnSlotComponentRemoved;
}

protected override void OnAwake()
{
base.OnAwake();
_lastSlot = TargetSlot.Target;
}

protected override void OnChanges()
Expand Down Expand Up @@ -156,17 +186,53 @@ protected override void OnPrepareDestroy()
}
}

public async IAsyncEnumerable<DataFeedItem> Enumerate(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, string searchPhrase, object viewData)
private void GetAllTypes(HashSet<Type> allTypes, CategoryNode<Type> categoryNode)
{
if (path != null && path.Count > 0)
foreach (var elem in categoryNode.Elements)
{
yield break;
allTypes.Add(elem);
}
if (groupKeys != null && groupKeys.Count > 0)
foreach (var subCat in categoryNode.Subcategories)
{
GetAllTypes(allTypes, subCat);
}
}

private IEnumerable<Type> EnumerateAllTypes(CategoryNode<Type> categoryNode)
{
foreach (var elem in categoryNode.Elements)
{
yield return elem;
}
foreach (var subCat in categoryNode.Subcategories)
{
foreach(var elem2 in EnumerateAllTypes(subCat))
{
yield return elem2;
}
}
}

private string GetCategoryKey(CategoryNode<Type> categoryNode)
{
return categoryNode.Name;
}

private DataFeedCategory GenerateCategory(string key, IReadOnlyList<string> path)
{
DataFeedCategory dataFeedCategory = new DataFeedCategory();
// random icon
dataFeedCategory.InitBase(key, path, null, key, OfficialAssets.Graphics.Icons.Gizmo.TransformLocal);
return dataFeedCategory;
}

public async IAsyncEnumerable<DataFeedItem> Enumerate(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, string searchPhrase, object viewData)
{
if (TargetSlot.Target != null && (path != null && path.Count > 0))
{
yield break;
}
if (TargetSlot.Target == null)
if (groupKeys != null && groupKeys.Count > 0)
{
yield break;
}
Expand All @@ -175,16 +241,77 @@ public async IAsyncEnumerable<DataFeedItem> Enumerate(IReadOnlyList<string> path
componentDataFeedData.Clear();
searchPhrase = searchPhrase?.Trim();

var components = IncludeChildrenSlots ? TargetSlot.Target.GetComponentsInChildren<Component>() : TargetSlot.Target.GetComponents<Component>();
foreach (Component allComponent in components)
if (TargetSlot.Target == null)
{
var lib = WorkerInitializer.ComponentLibrary;
if (path != null && path.Count > 0)
{
var catNode = lib;
foreach (var str in path)
{
var subCat = catNode.Subcategories.FirstOrDefault(x => x.Name == str);
if (subCat != null)
{
catNode = subCat;
}
else
{
yield break;
}
}
foreach (var subCat2 in catNode.Subcategories)
{
yield return GenerateCategory(GetCategoryKey(subCat2), path);
}
if (SearchStringValid(searchPhrase))
{
foreach (var elem in EnumerateAllTypes(catNode))
{
componentDataFeedData.AddComponentType(elem);
}
}
else
{
foreach (var elem in catNode.Elements)
{
componentDataFeedData.AddComponentType(elem);
}
}
}
else
{
if (_componentTypes.Count == 0)
{
GetAllTypes(_componentTypes, lib);
}
foreach (var subCat in lib.Subcategories)
{
yield return GenerateCategory(GetCategoryKey(subCat), path);
}
if (SearchStringValid(searchPhrase))
{
foreach (var elem in _componentTypes)
{
componentDataFeedData.AddComponentType(elem);
}
}
}
}
else
{
// If local elements are written to synced fields it can cause exceptions and crashes
if (allComponent.IsLocalElement) continue;
componentDataFeedData.RegisterComponent(allComponent);
foreach (ISyncMember syncMember in allComponent.SyncMembers)
var components = IncludeChildrenSlots ? TargetSlot.Target.GetComponentsInChildren<Component>() : TargetSlot.Target.GetComponents<Component>();
foreach (Component allComponent in components)
{
if (syncMember.IsLocalElement) continue;
componentDataFeedData.AddMember(syncMember);
// If local elements are written to synced fields it can cause exceptions and crashes
if (allComponent.IsLocalElement) continue;
var result = componentDataFeedData.AddComponent(allComponent);
foreach (ISyncMember syncMember in allComponent.SyncMembers)
{
if (FilterMember(syncMember))
{
result.data.AddMember(syncMember);
}
}
}
}

Expand Down
Loading

0 comments on commit 51fb4ee

Please sign in to comment.