Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

599 - Action to add Edges to the Architecture Graph to solve Divergences #629

Merged
Merged
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
ad2048e
add Action and NetAction to accept Divergences into Architecture
m4xxed May 25, 2023
19bad11
add ActionStateType for AcceptDivergenceAction
m4xxed May 25, 2023
a2eb3e9
add correct implementation next to current workaround
m4xxed May 25, 2023
2ffd5a9
add convenience method to check for divergence
m4xxed May 25, 2023
f556b92
switch from "dirty hack" to actual solution - works
m4xxed May 25, 2023
55566a6
fix grammar of documentation
m4xxed Jul 20, 2023
28c9e41
remove unused import #599
m4xxed Jul 27, 2023
a50db64
remove unneccesary workaround #599
m4xxed Jul 27, 2023
64c5691
disable networkaction temporarily #599
m4xxed Jul 27, 2023
0d36940
update documentation #599
m4xxed Jul 27, 2023
169b7b6
add functionality to create edges #599
m4xxed Jul 27, 2023
c562db2
fix imports #599
m4xxed Jul 27, 2023
d128490
start adding basic redo functionality #599
m4xxed Jul 27, 2023
7de3d45
Merge branch 'master' into 599-reflexion-sync-edges-from-implementati…
m4xxed Jul 29, 2023
e63c849
something went wrong while merging - reverted to master state #599
m4xxed Jul 29, 2023
1c153b8
use GameEdgeAdder to add Edge to Game
m4xxed Aug 5, 2023
9f56502
add DrawEdge method that accepts an existing Edge as parameter
m4xxed Aug 5, 2023
dd9155c
add DrawEdge because it is required in GraphRenderer
m4xxed Aug 5, 2023
6180133
overload DrawEdge to accept an existing DataModel.Edge as parameter
m4xxed Aug 5, 2023
4c7a097
fixed formatting
m4xxed Aug 5, 2023
1850bdf
add new Draw() method to GameEdgeAdder
m4xxed Aug 5, 2023
fed7e6f
temporary placeholder until we figure out a better way
m4xxed Aug 5, 2023
ca8e634
Automatic changes by Unity
falko17 Aug 6, 2023
3941a48
Use new new in EdgeRenderer
falko17 Aug 6, 2023
2826904
Pass correct source object to Renderer.DrawEdge
falko17 Aug 6, 2023
9a60c00
add audio and a networkaction to edge creation
m4xxed Aug 8, 2023
72c8a3f
reorder Class to fit order convention and add undo / redo
m4xxed Aug 8, 2023
25ae3a3
add NetAction to accept divergences
m4xxed Aug 8, 2023
07c4283
completed undo- and redo functionality
m4xxed Aug 8, 2023
4373f92
complete overhaul of the docstrings and inline documentation
m4xxed Aug 8, 2023
b7b8701
fixed order of actions - AcceptDivergence now before MetricBoard
m4xxed Aug 8, 2023
2160453
rename method to a less blame-y name and adjust documentation
m4xxed Aug 8, 2023
4b7a95a
fix and / or add documentation
m4xxed Aug 8, 2023
bf8fbba
passing GUID to clients to have matching GUID
m4xxed Aug 9, 2023
5d1d558
corrected, appended and adjusted documentation
m4xxed Aug 9, 2023
5066546
removed unused function (AddEdge(Edge) works better)
m4xxed Aug 9, 2023
b352259
check whether both GameObject and Node can be found
m4xxed Aug 9, 2023
36ac009
improve documentation
m4xxed Aug 9, 2023
756e437
Merge branch 'master' into 599-reflexion-sync-edges-from-implementati…
m4xxed Aug 9, 2023
ce1fd9f
remove extraneous newlines and dead code
m4xxed Aug 11, 2023
362f28e
add assertion, that the new edge is actually in architecture
m4xxed Aug 11, 2023
f8579f0
ensure edge is in archticture to avoid exceptions
m4xxed Aug 11, 2023
abc12dc
renamed variable to be more descriptive
m4xxed Aug 11, 2023
7513994
remove old comments and add missing documentation
m4xxed Aug 11, 2023
eaa02b2
remove comment that should've been removed before commit
m4xxed Aug 11, 2023
7e3cb0a
add "missing" braces
m4xxed Aug 11, 2023
aa14af6
refactor code to make it look smoother
m4xxed Aug 11, 2023
8d57202
remove unneccessary lookups
m4xxed Aug 11, 2023
ba361ff
update documentation
m4xxed Aug 11, 2023
1ffa907
simplify documentation
m4xxed Aug 11, 2023
375f2fe
update documentation
m4xxed Aug 11, 2023
6e099fa
remove variable and nesting complexity
m4xxed Aug 11, 2023
00a5e64
remove redundancy in documentation
m4xxed Aug 11, 2023
f2ac554
fixed checking in wrong graph
m4xxed Aug 11, 2023
ad2429c
fixed check for wrong graph
m4xxed Aug 11, 2023
0f93c7f
fixed documentation
m4xxed Aug 13, 2023
a94a752
Merge remote-tracking branch 'origin/master' into 599-reflexion-sync-…
koschke Aug 16, 2023
08bd443
#599 Fixed copy&paste error in documentation.
koschke Aug 16, 2023
abac963
#599 GlobalHistoryEntry can be readonly.
koschke Aug 16, 2023
9f2f358
#599 Replaced magic strings by edge-type declarations in Edge.
koschke Aug 16, 2023
1e09e7c
#599 Simplified new operator.
koschke Aug 16, 2023
c417919
#599 Architecture does not need to be capitalized.
koschke Aug 16, 2023
10fa2f3
#599 Removed obsolete implementation hint.
koschke Aug 16, 2023
8e60295
#599 Added missing import.
koschke Aug 16, 2023
735a67b
#599 We can use Find. Fixed misleading error message.
koschke Aug 16, 2023
d27b8d5
fix documentation - change check to catch propagated edges too
m4xxed Aug 16, 2023
63b8b36
#599 Removed obsolete class that was once created only for video reco…
koschke Aug 17, 2023
9df862b
#599 Created namespace for classes manipulating game objects in the s…
koschke Aug 17, 2023
7aa9390
Merge branch '599-reflexion-sync-edges-from-implementation-to-archite…
koschke Aug 17, 2023
832b437
#599 Removed obsolete class.
koschke Aug 17, 2023
2a69e52
#599 Removed obsolete class.
koschke Aug 17, 2023
a8e1b6b
#599 Use simplified new operator.
koschke Aug 17, 2023
eba4451
#599 Extracted class for code shared among AcceptDivergenceAction and…
koschke Aug 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ RenderTexture:
m_UseDynamicScale: 0
m_BindMS: 0
m_EnableCompatibleFormat: 1
m_EnableRandomWrite: 0
m_TextureSettings:
serializedVersion: 2
m_FilterMode: 1
Expand Down
275 changes: 275 additions & 0 deletions Assets/SEE/Controls/Actions/AcceptDivergenceAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
using System.Collections.Generic;
using SEE.DataModel.DG;
using SEE.Tools.ReflexionAnalysis;
using SEE.GO;
using SEE.Utils;
using UnityEngine;
using System;
using SEE.Game;
using SEE.Net.Actions;
using SEE.Audio;

namespace SEE.Controls.Actions
{
/// <summary>
/// Action to solve a divergence (see <see cref="ReflexionAnalysis.State"/>) between
/// implementation and architecture by adding the exact edge to the architecture that solves
/// this divergence.
/// </summary>
internal class AcceptDivergenceAction : AbstractPlayerAction
{
/// <summary>
/// Returns a new instance of <see cref="AcceptDivergenceAction"/>.
/// </summary>
/// <returns>new instance</returns>
public static ReversibleAction CreateReversibleAction()
{
return new AcceptDivergenceAction();
}

m4xxed marked this conversation as resolved.
Show resolved Hide resolved
/// <summary>
/// Returns a new instance of <see cref="AcceptDivergenceAction"/> as a <see
/// cref="ReversibleAction"/>.
/// </summary>
/// <returns>new instance</returns>
public override ReversibleAction NewInstance()
{
return CreateReversibleAction();
}

/// <summary>
/// The graph that the edge which was hit by the user to be accepted into the graph is
/// in. Set in <see cref="Update"/>.
/// </summary>
private ReflexionGraph graph;


/// <summary>
/// The information required to (re-)create the edge that solves the divergence.
/// </summary>
private struct Memento
{
/// <summary>
/// The source of the edge.
/// </summary>
public Node from;
/// <summary>
/// The target of the edge.
/// </summary>
public Node to;
/// <summary>
/// The type of the edge.
/// </summary>
public string type;
/// <summary>
/// Construct a new memento.
/// </summary>
/// <param name="source">the source node of the edge in the architecture graph</param>
/// <param name="target">the target node of the edge in the architecture grpah</param>
public Memento(Node source, Node target, string type)
{
this.from = source;
this.to = target;
this.type = type;
}
}

/// <summary>
/// The information required to (re-)create the edge that solves the divergence.
/// </summary>
private Memento memento;

/// <summary>
/// The edge created by this action. Can be null if no edge has been created yet or whether
/// an Undo was called. The created edge is stored only to delete it again if Undo is
/// called. All information to create the edge is kept in <see cref="memento"/>.
/// </summary>
private Edge createdEdge;

/// <summary>
/// Registers itself at <see cref="InteractableObject"/> to listen for hovering events.
/// </summary>
public override void Start()
{
InteractableObject.LocalAnyHoverIn += LocalAnyHoverIn;
InteractableObject.LocalAnyHoverOut += LocalAnyHoverOut;
}

/// <summary>
/// Unregisters itself from <see cref="InteractableObject"/>. Does no longer listen for
/// hovering events.
/// </summary>
public override void Stop()
{
InteractableObject.LocalAnyHoverIn -= LocalAnyHoverIn;
InteractableObject.LocalAnyHoverOut -= LocalAnyHoverOut;
}

/// <summary>
/// The default type of an added edge.
/// </summary>
private const string DefaultEdgeType = "Source_Dependency";

/// <summary>
/// See <see cref="ReversibleAction.Update"/>.
/// </summary>
/// <returns>true if completed</returns>
public override bool Update()
{
// indicates whether the divergence has been solved ("true" means "solved")
bool divergenceSolved = false;

// FIXME: Needs adaptation for VR where no mouse is available.
if (Input.GetMouseButtonDown(0)
&& Raycasting.RaycastGraphElement(
out RaycastHit raycastHit,
out GraphElementRef _) != HitGraphElement.None)
{
// find the edge representing the divergence that should be solved.
GameObject selectedDivergenceEdge = raycastHit.collider.gameObject;

// check whether the object selected is an edge.
if (selectedDivergenceEdge.TryGetEdge(out Edge selectedEdge))
{
// check if the selected edge represents a divergence
if (selectedEdge.IsInImplementation() && ReflexionGraph.IsDivergent(selectedEdge))
{
// acquire the containing ReflexionGraph
graph = (ReflexionGraph)selectedEdge.ItsGraph;

// find that node in the architecture graph,
// which the divergence's source node is
// explicitly or implicitly mapped to
Node source = graph.MapsTo(selectedEdge.Source);

// find that node in the ArchitectureGraph,
// which the divergence's target is explicitly
// or implicitly mapped to
Node target = graph.MapsTo(selectedEdge.Target);

// we have both source and target of the edge and use a memento struct
// to remember which edge we have added
memento = new Memento(source, target, "Source_Dependency");

// create the edge
createdEdge = CreateEdge(memento);

// check whether edge creation was successfull
divergenceSolved = createdEdge != null;

// add audio cue to the appearance of the new architecture edge
AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.NEW_EDGE_SOUND);

// update the current state depending on whether the divergence has been solved
// (required in order to register as an undo-able action)
currentState = divergenceSolved ? ReversibleAction.Progress.Completed : ReversibleAction.Progress.NoEffect;

// the selected object is synced and this action is done
return true;
}
}
else
{
Debug.LogWarning($"Selected Element {selectedDivergenceEdge.name} is not an edge.\n");
}
}
return false;
}

/// <summary>
/// Undoes this AcceptDivergenceAction.
/// </summary>
public override void Undo()
{
base.Undo();

// remove the synced edge (its info is saved in memento)
ReflexionGraph graph = (ReflexionGraph)createdEdge.ItsGraph;

if (graph != null)
{
// find the corresponding GameObject
GameObject createdEdgeGO = GraphElementIDMap.Find(createdEdge.ID);
// remove the edge's GameObject and graph representation locally and on the network
GameEdgeAdder.Remove(createdEdgeGO);

// propagate the new edge via network
new DeleteNetAction(createdEdge.ID).Execute();

// ensure the edge's GameObject gets destroyed properly
Destroyer.Destroy(createdEdgeGO);
}
else
{
throw new Exception($"Edge {createdEdge.ID} to be removed is not contained in a graph.");
}

// set any edge references back to null
createdEdge = null;
}

/// <summary>
/// Redoes this AcceptDivergenceAction.
/// </summary>
public override void Redo()
{
base.Redo();
// recreate the edge
createdEdge = CreateEdge(memento);
}

/// <summary>
/// Creates a new edge using the given <paramref
/// name="memento"/>. In case of any error, null will be
/// returned.
/// </summary>
/// <param name="memento">information needed to create the edge</param>
/// <returns>the new edge's GameObject and a reference to itself, or both null</returns>
private Edge CreateEdge(Memento memento)
{
// create the edge beforehand
Edge newEdge = new Edge(memento.from, memento.to, memento.type);

// add the already created edge to the architecture graph
graph.AddToArchitecture(newEdge);

// (re)draw the new edge
GameEdgeAdder.Draw(newEdge);

// propagate the edge (including matching ID) over network
new AcceptDivergenceNetAction(memento.from.ID, memento.to.ID, newEdge.ID, newEdge.Type).Execute();

return newEdge;
}

/// <summary>
/// Returns the <see cref="ActionStateType"/> of this action.
/// </summary>
/// <returns><see cref="ActionStateType.NewNode"/></returns>
public override ActionStateType GetActionStateType()
{
return ActionStateTypes.AcceptDivergence;
}

/// <summary>
/// Returns all IDs of GameObjects manipulated by this action.
/// </summary>
/// <returns>all IDs of GameObjects manipulated by this action</returns>
public override HashSet<string> GetChangedObjects()
{
if (createdEdge == null)
{
return new HashSet<string>();
}
else
{
return new HashSet<string>
{
memento.from.ID,
memento.to.ID,
createdEdge.ID
};
}
}
}
}
11 changes: 11 additions & 0 deletions Assets/SEE/Controls/Actions/AcceptDivergenceAction.cs.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c0170e2fab3a75bda98c1062700a9d2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
2 changes: 1 addition & 1 deletion Assets/SEE/Controls/Actions/ActionStateType.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using SEE.Utils;
using SEE.Utils;
using UnityEngine;

namespace SEE.Controls.Actions
Expand Down
7 changes: 7 additions & 0 deletions Assets/SEE/Controls/Actions/ActionStateTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ static ActionStateTypes()
Color.magenta.Darker(), "Materials/ModernUIPack/Pencil",
DrawAction.CreateReversibleAction);

AcceptDivergence =
new("Accept Divergence", "Accept a diverging edge into the Architecture",
Color.grey.Darker(), "Materials/ModernUIPack/Arrow Bold",
AcceptDivergenceAction.CreateReversibleAction);

// Metric Board actions
MetricBoard =
new("Metric Board", "Manipulate a metric board",
Expand Down Expand Up @@ -165,6 +170,7 @@ static ActionStateTypes()
parent: MetricBoard);
}


public readonly static ActionStateType Move;
public readonly static ActionStateType Rotate;
public readonly static ActionStateType Hide;
Expand All @@ -175,6 +181,7 @@ static ActionStateTypes()
public readonly static ActionStateType Delete;
public readonly static ActionStateType ShowCode;
public readonly static ActionStateType Draw;
public readonly static ActionStateType AcceptDivergence;

public readonly static ActionStateTypeGroup MetricBoard;
public readonly static ActionStateType AddBoard;
Expand Down
33 changes: 31 additions & 2 deletions Assets/SEE/Game/EdgeRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private GameObject DrawEdge(Edge edge, GameObject from, GameObject to, bool addT
Assert.IsNotNull(toLayoutNode, $"Target node {edge.Target.ID} does not have a layout node.\n");
// The single layout edge between source and target. We want the layout only for this edge.
ICollection<LayoutGraphEdge<LayoutGameNode>> layoutEdges = new List<LayoutGraphEdge<LayoutGameNode>>
{ new LayoutGraphEdge<LayoutGameNode>(fromLayoutNode, toLayoutNode, edge) };
{ new(fromLayoutNode, toLayoutNode, edge) };


// Calculate the edge layout (for the single edge only).
Expand Down Expand Up @@ -216,6 +216,35 @@ public GameObject DrawEdge(GameObject source, GameObject target, string edgeType
return DrawEdge(edge, source, target, true);
}

/// <summary>
/// Draws and returns a new game edge <paramref name="edge"/>
/// based on the current settings.
///
/// Note: The default edge layout <see cref="IGraphRenderer.EdgeLayoutDefault"/> will be used if no edge layout,
/// i.e., <see cref="EdgeLayoutKind.None>"/>, was chosen in the settings.
///
/// Precondition: <paramref name="source"/> and <paramref name="target"/> must have a valid
/// node reference. The corresponding graph nodes must be in the same graph.
/// </summary>
/// <param name="edge">the edge to be drawn</param>
/// <param name="sourceNode">GameObject of source of the new edge</param>
/// <param name="targetNode">GameObject of target of the new edge</param>
/// <returns>The new game object representing the given edge.</returns>
public GameObject DrawEdge(Edge edge, GameObject sourceNode = null, GameObject targetNode = null)
{
if (sourceNode == null)
{
sourceNode = GraphElementIDMap.Find(edge.Source.ID);
}

if (targetNode == null)
{
targetNode = GraphElementIDMap.Find(edge.Target.ID);
}

return DrawEdge(edge, sourceNode, targetNode, true);
}

/// <summary>
/// Adds <paramref name="node"/> and all its transitive parent game objects tagged by
/// <see cref="Tags.Node"/> to <paramref name="gameNodes"/>.
Expand Down Expand Up @@ -393,4 +422,4 @@ private static ICollection<LayoutGraphEdge<T>> ConnectingEdges<T>(ICollection<T>
return edges;
}
}
}
}
10 changes: 10 additions & 0 deletions Assets/SEE/Game/Evolution/EvolutionRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,16 @@ public GameObject DrawNode(Node node, GameObject city = null)
return Renderer.DrawNode(node, city);
}

/// <summary>
/// Placeholder to satisfy the compiler. This method is not
/// called anywhere as of yet, but was required in <see
/// cref="EdgeRenderer"/>.
/// </summary>
public GameObject DrawEdge(Edge edge, GameObject source = null, GameObject target = null)
{
throw new NotImplementedException();
}

/// <summary>
/// Returns an edge layout for the given <paramref name="gameEdges"/>.
///
Expand Down
Loading
Loading