Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
A node-based editor for S-Quest

A node-based editor for S-Quest

The class listed below this text, QuestRIBackend.cs, provides a graph editor for the relations between quests in S-Quest. In order to use it, first install RelationsInspector and then place QuestRIBackend.cs into the folder Assets/S-Quest/C#/Editor of your Unity project. Now select Window/RelationsInspector from Unity's toolbar and when the window has opened, select QuestRIBackend from the window's toolbar. You'll then see the quest graph of the active scene, and can start adding and removing quests as well as change their connections. If you have questions or feedback, please use the S-Quest discussion thread.

It looks like this:

using UnityEngine;
using UnityEditor;
using RelationsInspector;
using RelationsInspector.Backend;
using System.Collections.Generic;
using System.Linq;
public class QuestRIBackend : MinimalBackend<QuestC, string>
{
HashSet<QuestC> quests = new HashSet<QuestC>();
GameObject questGiver; // when a quest is added, its component is added to this GameObject
const string DefaultQuestCode = "GiveMeAName";
public override void Awake( GetAPI getAPI )
{
base.Awake( getAPI );
// if there are quest targets, move along
if ( api.GetTargets().OfType<QuestC>().Any() )
return;
var questsInScene = Object.FindObjectsOfType<QuestC>();
if ( !questsInScene.Any() )
return;
api.ResetTargets( questsInScene.Cast<object>().ToArray() );
}
public override IEnumerable<QuestC> Init( object target )
{
var asQuest = target as QuestC;
if ( asQuest == null )
yield break;
quests.Add( asQuest );
yield return asQuest;
}
public override IEnumerable<Relation<QuestC, string>> GetRelations( QuestC entity )
{
var successors = quests
.Where( q => q.ParentQuest == entity && q != entity);
foreach ( var successor in successors )
yield return new Relation<QuestC, string>( entity, successor, string.Empty );
}
public override Rect OnGUI()
{
GUILayout.BeginHorizontal(EditorStyles.toolbar);
{
if ( GUILayout.Button( "Regenerate", EditorStyles.toolbarButton, GUILayout.ExpandWidth( false ) ) )
GenerateQuestView();
GUILayout.Space(20);
if ( GUILayout.Button( "Add Quest", EditorStyles.toolbarButton, GUILayout.ExpandWidth( false ) ) )
CreateQuest( null );
GUILayout.Space( 20 );
GUILayout.Label( "Quest giver", EditorStyles.miniLabel );
questGiver = (GameObject) EditorGUILayout.ObjectField( questGiver, typeof( GameObject ), true );
GUILayout.FlexibleSpace();
}
GUILayout.EndHorizontal();
return base.OnGUI();
}
void GenerateQuestView()
{
api.ResetTargets( Object.FindObjectsOfType<QuestC>().Cast<object>().ToArray() );
}
public override GUIContent GetContent( QuestC entity )
{
string title = entity.QuestCode;
return new GUIContent( title, null, entity.gameObject.name );
}
public override string GetEntityTooltip( QuestC entity )
{
return entity.QuestObjective;
}
public override void OnEntitySelectionChange( QuestC[] selection )
{
Selection.objects = selection.Cast<Object>().ToArray();
}
public override void OnEntityContextClick( IEnumerable<QuestC> entities, GenericMenu menu )
{
if ( entities.Count() == 1 )
{
var single = entities.First();
menu.AddItem( new GUIContent( "Add next quest" ), false, () => CreateQuest( single ) );
menu.AddItem( new GUIContent( "Select next quest" ), false, () => api.InitRelation( new object[] { single } ) );
menu.AddItem( new GUIContent( "Remove quest" ), false, () => RemoveQuest( single ) );
}
}
public override void CreateRelation( QuestC source, QuestC target )
{
Undo.RecordObject( target, "changing quest order" );
var previousParent = target.ParentQuest;
target.ParentQuest = source;
EditorUtility.SetDirty( target );
api.AddRelation( source, target, string.Empty );
if ( previousParent != null )
api.RemoveRelation( previousParent, target, string.Empty );
}
public override void OnRelationContextClick( Relation<QuestC, string> relation, GenericMenu menu )
{
menu.AddItem( new GUIContent( "Remove relation" ), false, () => RemoveRelation( relation ) );
base.OnRelationContextClick( relation, menu );
}
void RemoveRelation( Relation<QuestC, string> relation )
{
Undo.RecordObject( relation.Target, "changing quest order" );
relation.Target.ParentQuest = null;
EditorUtility.SetDirty( relation.Target );
api.RemoveRelation( relation.Source, relation.Target, relation.Tag );
}
void CreateQuest( QuestC predecessor )
{
if ( questGiver == null )
{
EditorUtility.DisplayDialog( "Warning", "You need to first set the quest giver in the toolbar.", "OK" );
return;
}
var successor = Undo.AddComponent<QuestC>( questGiver );
successor.ParentQuest = predecessor;
successor.QuestCode = predecessor==null? DefaultQuestCode : predecessor.QuestCode;
quests.Add( successor );
EditorUtility.SetDirty( successor );
api.AddEntity( successor, Vector2.zero, false );
if(predecessor != null )
api.AddRelation( predecessor, successor, string.Empty, false );
}
void RemoveQuest( QuestC entity )
{
string qCode = entity.QuestCode;
var owner = entity.gameObject;
quests.Remove( entity );
Undo.DestroyObjectImmediate( entity );
EditorUtility.SetDirty( owner );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment