├── Editor ├── Resources │ ├── Node.uss │ ├── QuestGraph.uss │ ├── Node.uss.meta │ └── QuestGraph.uss.meta ├── GraphEditor.meta ├── Resources.meta ├── CustomInspector.meta ├── QuestSystem.QuestEditor.asmdef.meta ├── CustomInspector │ ├── QuestEditor.cs.meta │ ├── QuestLogEditor.cs.meta │ ├── QuestObjectiveUpdaterEditor.cs.meta │ ├── QuestOnObjectWorldEditor.cs.meta │ ├── QuestEditor.cs │ ├── QuestLogEditor.cs │ ├── QuestOnObjectWorldEditor.cs │ └── QuestObjectiveUpdaterEditor.cs ├── GraphEditor │ ├── NodeQuestGraph.cs.meta │ ├── QuestGraphEditor.cs.meta │ ├── QuestGraphUtility.cs.meta │ ├── QuestGraphView.cs.meta │ ├── QuestGraphSaveUtility.cs.meta │ ├── QuestNodeSearchWindow.cs.meta │ ├── QuestObjectiveGraph.cs.meta │ ├── NodeQuestGraph.cs │ ├── QuestGraphUtility.cs │ ├── QuestNodeSearchWindow.cs │ ├── QuestObjectiveGraph.cs │ ├── QuestGraphEditor.cs │ ├── QuestGraphView.cs │ └── QuestGraphSaveUtility.cs └── QuestSystem.QuestEditor.asmdef ├── LICENSE.meta ├── README.md.meta ├── package.json.meta ├── Editor.meta ├── Runtime.meta ├── Runtime ├── QuestSystem.asmdef.meta ├── SaveData.meta ├── IQuestInteraction.cs ├── Quest.cs.meta ├── QuestLog.cs.meta ├── NodeQuest.cs.meta ├── QuestGiver.cs.meta ├── QuestManager.cs.meta ├── IQuestInteraction.cs.meta ├── QuestConstants.cs.meta ├── QuestObjective.cs.meta ├── QuestOnObjectWorld.cs.meta ├── QuestObjectiveUpdater.cs.meta ├── SaveData │ ├── QuestSaveSystem.cs.meta │ ├── QuestObjectiveSurrogate.cs.meta │ ├── QuestSaveDataSurrogate.cs.meta │ ├── NodeQuestSaveDataSurrogate.cs.meta │ ├── QuestLogSaveDataSurrogate.cs.meta │ ├── QuestObjectiveSurrogate.cs │ ├── NodeQuestSaveDataSurrogate.cs │ ├── QuestSaveDataSurrogate.cs │ ├── QuestLogSaveDataSurrogate.cs │ └── QuestSaveSystem.cs ├── QuestObjective.cs ├── QuestSystem.asmdef ├── QuestConstants.cs ├── NodeQuest.cs ├── QuestGiver.cs ├── Quest.cs ├── QuestLog.cs ├── QuestManager.cs ├── QuestOnObjectWorld.cs └── QuestObjectiveUpdater.cs ├── package.json ├── LICENSE └── README.md /Editor/Resources/Node.uss: -------------------------------------------------------------------------------- 1 | NodeQuestGraph #title{ 2 | background-color: rgba(252,109,64, 0.5); 3 | } 4 | 5 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: df31e3a1612d59045908141a08c7e003 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Resources/QuestGraph.uss: -------------------------------------------------------------------------------- 1 | GridBackground{ 2 | --grid-background-color: #282828; 3 | --line-color: rgba(193,196,192,0.1); 4 | --thick-line-color: rgba(193,196,192,0.1); 5 | --spacing: 20; 6 | } -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d96beee1b0f0c9746bfd79dc8480f07c 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7c26c6fb6aa06540b7d3e8d3f96945d 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6a82d0d6ac5432041a21b5300ed89946 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 223c3480aae48384bb3db3888ea3b7ee 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/GraphEditor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 951d5f66c49e8664ba4b78344f59dadc 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9a61ca50386f78e4e975d697173d80a3 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/QuestSystem.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e1473c92b2d9c7344b39e95badfd8c14 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/SaveData.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3e08fdee9b67b294fbb87b1c0e7b861f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/CustomInspector.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0ebf92d715db1c14bb7c7c4d68f82eb1 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/QuestSystem.QuestEditor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5e5cbbed08dc1ba4d84c4a66e29b7070 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime/IQuestInteraction.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace QuestSystem 6 | { 7 | public interface IQuestInteraction 8 | { 9 | void Interact(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Runtime/Quest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 992dd6fbed83a8c479511053360814f9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/QuestLog.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 11d554e09c21c014d905b01d7af3e0f9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/NodeQuest.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6d043e38139fc86409d4439ee183e20e 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/QuestGiver.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7f774627a6dc2de439327a1763695cde 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/QuestManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ca5a425bf12ca3c4a908575f2bfc7836 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/IQuestInteraction.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fa43d163d13b5c947b0872dc6a74b266 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/QuestConstants.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 253e747509c363c4a9a6a24873a114ce 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/QuestObjective.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5cdd44027babdfc4886ecf7353074bcf 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/QuestOnObjectWorld.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e94ef085bbfd17946ab79270b9bfa807 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/QuestObjectiveUpdater.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c645587000ea5314e929763c21d20ba9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 32e0864665f1d9d48b8472605f0f8a82 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphEditor/NodeQuestGraph.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 59a94712ce03d4e4f857693b739d6ffa 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4eaf58b6613f4604fa2f53b1f3f4d424 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c740771a11eb58489c094a0156e29d5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphView.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dae28899ce23cb540905954e8a9414b6 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/SaveData/QuestSaveSystem.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: feeb46a691fc8a14b9039817b19edab8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestLogEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: eae025e0ec3ad9a4ea48cf8b22c17920 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphSaveUtility.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 61d6d49d2cb56ce46acc036745c664f0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestNodeSearchWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c0c4f88cbc0267f4cbafe0cf4139d343 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestObjectiveGraph.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 16e9abe02941d3243a015dec07c5236f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/SaveData/QuestObjectiveSurrogate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be3be36bc8e4a9445a1f6e30448e5e5b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/SaveData/QuestSaveDataSurrogate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 878048445c09b39418b0b2864e1e6435 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/SaveData/NodeQuestSaveDataSurrogate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fea3c646fddb24a498a2d90be929f2e1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/SaveData/QuestLogSaveDataSurrogate.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 475ef3131a3cbd14eb9e0e5cbf8a5d79 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestObjectiveUpdaterEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a87c290931cdc2f449136922096223f0 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestOnObjectWorldEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5f986b42bfd47d64aa553b738ca92379 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Resources/Node.uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68c6779cf0cb5954791680d37f035820 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} 11 | disableValidation: 0 12 | -------------------------------------------------------------------------------- /Editor/Resources/QuestGraph.uss.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 22ab095dcd3ac8540aa96e0846c78a7a 3 | ScriptedImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 2 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0} 11 | disableValidation: 0 12 | -------------------------------------------------------------------------------- /Editor/QuestSystem.QuestEditor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QuestSystem.QuestEditor", 3 | "references": [ 4 | "GUID:e1473c92b2d9c7344b39e95badfd8c14" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /Runtime/QuestObjective.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace QuestSystem 6 | { 7 | [System.Serializable] 8 | public class QuestObjective 9 | { 10 | public string keyName; 11 | public bool isCompleted; 12 | public int maxItems; 13 | public int actualItems; 14 | public string description; 15 | public bool hiddenObjective; 16 | public bool autoExitOnCompleted; 17 | 18 | } 19 | } -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace QuestSystem.QuestEditor 5 | { 6 | [CustomEditor(typeof(Quest))] 7 | public class QuestEditor : Editor 8 | { 9 | public override void OnInspectorGUI() 10 | { 11 | Quest q = (Quest)target; 12 | 13 | DrawDefaultInspector(); 14 | 15 | if (GUILayout.Button("Reset")) 16 | { 17 | q.Reset(); 18 | } 19 | 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestLogEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | 4 | 5 | namespace QuestSystem.QuestEditor 6 | { 7 | [CustomEditor(typeof(QuestLog))] 8 | public class QuestLogEditor : Editor 9 | { 10 | public override void OnInspectorGUI() 11 | { 12 | QuestLog questLog = (QuestLog)target; 13 | 14 | DrawDefaultInspector(); 15 | 16 | if (GUILayout.Button("Reset all Quest")) 17 | { 18 | questLog.ResetAllQuest(); 19 | } 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Runtime/QuestSystem.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QuestSystem", 3 | "references": [ 4 | "GUID:6055be8ebefd69e48b49212b09b47b2f", 5 | "GUID:5a2c12b55024db74cbd4a4b97dfd2361", 6 | "GUID:8e1d4d52b41ceaf4e9b37f507525c939", 7 | "GUID:fd257328d8a437f4aa4369fbe24bf9c4", 8 | "GUID:4307f53044263cf4b835bd812fc161a4" 9 | ], 10 | "includePlatforms": [], 11 | "excludePlatforms": [], 12 | "allowUnsafeCode": false, 13 | "overrideReferences": false, 14 | "precompiledReferences": [], 15 | "autoReferenced": true, 16 | "defineConstraints": [], 17 | "versionDefines": [], 18 | "noEngineReferences": false 19 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "questsystem", 3 | "version": "1.0.0", 4 | "displayName": "QuestSystem", 5 | "description": "This is a premade Quest system with saves and a custom graph editor", 6 | "unity": "2019.1", 7 | "documentationUrl": "https://github.com/lluispalerm/QuestSystem-Demo", 8 | "changelogUrl": "https://example.com/changelog.html", 9 | "licensesUrl": "https://github.com/lluispalerm/QuestSystem-Demo/blob/main/LICENSE", 10 | "keywords": [ 11 | "Quest", 12 | "Editor Graph", 13 | "QuestSystem" 14 | ], 15 | "author": { 16 | "name": "Lluis Palerm", 17 | "email": "unity@example.com", 18 | "url": "https://www.unity3d.com" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Editor/GraphEditor/NodeQuestGraph.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEditor.Experimental.GraphView; 4 | using UnityEngine; 5 | using UnityEngine.UIElements; 6 | using UnityEditor; 7 | 8 | namespace QuestSystem.QuestEditor 9 | { 10 | [System.Serializable] 11 | public class NodeQuestGraph : UnityEditor.Experimental.GraphView.Node 12 | { 13 | public string GUID; 14 | 15 | public TextAsset extraText; 16 | 17 | public VisualElement objectivesRef; 18 | 19 | public List questObjectives; 20 | 21 | public bool isFinal; 22 | 23 | public bool entryPoint = false; 24 | 25 | public int limitDay; 26 | 27 | public int startDay; 28 | 29 | public string misionName; 30 | 31 | public bool isMain; 32 | 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestOnObjectWorldEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | 7 | namespace QuestSystem.QuestEditor 8 | { 9 | [CustomEditor(typeof(QuestOnObjectWorld))] 10 | public class QuestOnObjectWorldEditor : Editor 11 | { 12 | public override void OnInspectorGUI() 13 | { 14 | QuestOnObjectWorld qOW = (QuestOnObjectWorld)target; 15 | 16 | if (GUILayout.Button("Get all Nodes from Quest")) 17 | { 18 | qOW.GetAllNodesFromQuest(); 19 | } 20 | 21 | DrawDefaultInspector(); 22 | 23 | if (GUILayout.Button("Populate with children")) 24 | { 25 | qOW.PopulateChildListDefault(); 26 | } 27 | 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphUtility.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine.UIElements; 2 | using UnityEditor.UIElements; 3 | 4 | public static class QuestGraphUtility 5 | { 6 | public static TextField CreateTextField(string label, string variableToModify, string defaultValue = "") 7 | { 8 | var field = new TextField(label) 9 | { 10 | value = defaultValue 11 | }; 12 | 13 | field.RegisterValueChangedCallback(evt => 14 | { 15 | variableToModify = evt.newValue; 16 | }); 17 | 18 | return field; 19 | } 20 | 21 | public static IntegerField CreateIntegerField(string label, int variableToModify, int defaultValue = 0) 22 | { 23 | var field = new IntegerField(label) 24 | { 25 | value = defaultValue 26 | }; 27 | 28 | field.RegisterValueChangedCallback(evt => 29 | { 30 | variableToModify = evt.newValue; 31 | }); 32 | 33 | return field; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Runtime/QuestConstants.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace QuestSystem 6 | { 7 | public static class QuestConstants 8 | { 9 | public static readonly string RESOURCES_PATH = "Assets/Resources"; 10 | public static readonly string RESOURCES_NAME = "Resources"; 11 | public static readonly string MISIONS_FOLDER = "Assets/Resources/Missions"; 12 | public static readonly string MISIONS_NAME = "Missions"; 13 | public static readonly string PARENT_PATH = "Assets"; 14 | public static readonly string SAVE_FILE_PATH = Application.persistentDataPath + "/saves/" + "savefile" + ".save"; 15 | public static readonly string SAVE_FILE_FOLDER = Application.persistentDataPath + "/saves"; 16 | public static readonly string QUEST_LOG_NAME = "TheQuestLog"; 17 | public static readonly string NODES_TEMP_FOLDER_NAME = "NodesTemp"; 18 | public static readonly string NODES_FOLDER_NAME = "Nodes"; 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 lluispalerm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Runtime/NodeQuest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | 6 | namespace QuestSystem 7 | { 8 | [CreateAssetMenu(fileName = "New NodeQuest", menuName = "QuestSystem/NodeQuest")] 9 | [System.Serializable] 10 | public class NodeQuest : ScriptableObject 11 | { 12 | public List nextNode = new List(); 13 | public TextAsset extraText; 14 | public List objectsActivated; 15 | public bool isFinal; 16 | public QuestObjective[] nodeObjectives; 17 | 18 | [Header("Graph Part")] 19 | public string GUID; 20 | public Vector2 position; 21 | 22 | public void AddObject(GameObject g) 23 | { 24 | if (g == null) Debug.Log("Object is null"); 25 | if (!objectsActivated.Contains(g)) 26 | { 27 | objectsActivated.Add(g); 28 | } 29 | } 30 | 31 | public void ChangeTheStateOfObjects(bool b) 32 | { 33 | foreach (GameObject g in objectsActivated) 34 | { 35 | g.SetActive(b); 36 | } 37 | } 38 | 39 | private void OnEnable() 40 | { 41 | objectsActivated = new List(); 42 | } 43 | 44 | 45 | 46 | } 47 | } -------------------------------------------------------------------------------- /Runtime/SaveData/QuestObjectiveSurrogate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using System.Runtime.Serialization; 5 | 6 | namespace QuestSystem.SaveSystem 7 | { 8 | public class QuestObjectiveSurrogate : ISerializationSurrogate 9 | { 10 | public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) 11 | { 12 | QuestObjective qo = (QuestObjective)obj; 13 | 14 | info.AddValue("keyName", qo.keyName); 15 | info.AddValue("isCompleted", qo.isCompleted); 16 | info.AddValue("maxItems", qo.maxItems); 17 | info.AddValue("actualItems", qo.actualItems); 18 | info.AddValue("description", qo.description); 19 | } 20 | 21 | public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) 22 | { 23 | QuestObjective qo = (QuestObjective)obj; 24 | 25 | qo.keyName = (string)info.GetValue("keyName", typeof(string)); 26 | qo.isCompleted = (bool)info.GetValue("isCompleted", typeof(bool)); 27 | qo.maxItems = (int)info.GetValue("maxItems", typeof(int)); 28 | qo.actualItems = (int)info.GetValue("actualItems", typeof(int)); 29 | qo.description = (string)info.GetValue("description", typeof(string)); 30 | 31 | obj = qo; 32 | return obj; 33 | } 34 | 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /Runtime/SaveData/NodeQuestSaveDataSurrogate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | using UnityEngine; 5 | 6 | namespace QuestSystem.SaveSystem 7 | { 8 | public class NodeQuestSaveDataSurrogate : ISerializationSurrogate 9 | { 10 | public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) 11 | { 12 | NodeQuest nq = (NodeQuest)obj; 13 | info.AddValue("extraText", nq.extraText); 14 | info.AddValue("isFinal", nq.isFinal); 15 | info.AddValue("nodeObjectives", nq.nodeObjectives); 16 | } 17 | 18 | public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) 19 | { 20 | NodeQuest nq = (NodeQuest)obj; 21 | nq.isFinal = (bool)info.GetValue("isFinal", typeof(bool)); 22 | nq.nodeObjectives = (QuestObjective[])info.GetValue("nodeObjectives", typeof(QuestObjective[])); 23 | obj = nq; 24 | return obj; 25 | } 26 | 27 | } 28 | 29 | [System.Serializable] 30 | public class NodeQuestSaveData 31 | { 32 | public QuestObjective[] objectives; 33 | 34 | public NodeQuestSaveData() 35 | { 36 | objectives = new QuestObjective[1]; 37 | } 38 | 39 | public NodeQuestSaveData(int i) 40 | { 41 | objectives = new QuestObjective[i]; 42 | } 43 | 44 | 45 | } 46 | } -------------------------------------------------------------------------------- /Runtime/SaveData/QuestSaveDataSurrogate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization; 5 | using System.Runtime.Serialization.Formatters.Binary; 6 | using UnityEngine; 7 | 8 | namespace QuestSystem.SaveSystem 9 | { 10 | public class QuestSaveDataSurrogate : ISerializationSurrogate 11 | { 12 | public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) 13 | { 14 | Quest q = (Quest)obj; 15 | 16 | info.AddValue("firtsNode", q.firtsNode); 17 | info.AddValue("nodeActual", q.nodeActual); 18 | info.AddValue("state", q.state); 19 | info.AddValue("limitDay", q.limitDay); 20 | info.AddValue("startDay", q.startDay); 21 | info.AddValue("misionName", q.misionName); 22 | } 23 | 24 | public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) 25 | { 26 | Quest q = (Quest)obj; 27 | 28 | q.firtsNode = (NodeQuest)info.GetValue("firtsNode", typeof(NodeQuest)); 29 | q.firtsNode = (NodeQuest)info.GetValue("nodeActual", typeof(NodeQuest)); 30 | q.state = (List)info.GetValue("state", typeof(List)); 31 | q.limitDay = (int)info.GetValue("limitDay", typeof(int)); 32 | q.startDay = (int)info.GetValue("startDay", typeof(int)); 33 | q.misionName = (string)info.GetValue("misionName", typeof(string)); 34 | 35 | obj = q; 36 | return obj; 37 | } 38 | 39 | } 40 | 41 | [System.Serializable] 42 | public class QuestSaveData 43 | { 44 | public List states; 45 | public string name; 46 | public NodeQuestSaveData actualNodeData; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestNodeSearchWindow.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEditor.Experimental.GraphView; 5 | using UnityEngine; 6 | using UnityEngine.UIElements; 7 | 8 | namespace QuestSystem.QuestEditor 9 | { 10 | public class QuestNodeSearchWindow : ScriptableObject, ISearchWindowProvider 11 | { 12 | 13 | private QuestGraphView _graphView; 14 | private EditorWindow _window; 15 | private Texture2D _textureForTable; 16 | 17 | public void Init(QuestGraphView graphView, EditorWindow window){ 18 | _graphView = graphView; 19 | _window = window; 20 | 21 | _textureForTable = new Texture2D(1,1); 22 | _textureForTable.SetPixel(0,0, new Color(0,0,0,0)); 23 | _textureForTable.Apply(); 24 | } 25 | 26 | public List CreateSearchTree(SearchWindowContext context) 27 | { 28 | var tree = new List 29 | { 30 | new SearchTreeGroupEntry(new GUIContent("Create Node"), 0) 31 | { 32 | }, 33 | new SearchTreeEntry(new GUIContent(" Quest Node")) 34 | { 35 | level = 1, userData = new NodeQuestGraph(), 36 | }, 37 | 38 | }; 39 | 40 | return tree; 41 | } 42 | 43 | public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context) 44 | { 45 | Vector2 mousePosition = _window.rootVisualElement.ChangeCoordinatesTo(_window.rootVisualElement.parent, 46 | context.screenMousePosition - _window.position.position); 47 | 48 | Vector2 graphViewMousePosition = _graphView.contentViewContainer.WorldToLocal(mousePosition); 49 | 50 | 51 | switch(SearchTreeEntry.userData){ 52 | case NodeQuestGraph nodeQuestGraph: 53 | _graphView.CreateNode("NodeQuest", graphViewMousePosition); 54 | return true; 55 | default: 56 | return false; 57 | } 58 | } 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /Runtime/QuestGiver.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace QuestSystem 6 | { 7 | public class QuestGiver : MonoBehaviour , IQuestInteraction 8 | { 9 | public Quest questToGive; 10 | public TextAsset extraText; 11 | 12 | private bool ableToGive = false; 13 | private bool questAlreadyGiven; 14 | private QuestManager questManagerRef; 15 | 16 | // Start is called before the first frame update 17 | void Start() 18 | { 19 | questManagerRef = QuestManager.GetInstance(); 20 | questAlreadyGiven = questManagerRef.IsMisionInLog(questToGive); 21 | } 22 | 23 | public void giveQuest() 24 | { 25 | showDialogue(); 26 | questManagerRef.AddMisionToCurrent(questToGive); 27 | 28 | questAlreadyGiven = true; 29 | QuestManager.GetInstance().Save(); 30 | } 31 | 32 | public void showDialogue() 33 | { 34 | //if (conversation != null) FindObjectOfType().StartDialogue(conversation, null); 35 | //else return; 36 | } 37 | 38 | 39 | //Delete the ones you don't want to use 40 | 41 | private void OnTriggerEnter(Collider other) 42 | { 43 | resultOfEnter(true, other.tag); 44 | } 45 | 46 | private void OnTriggerExit(Collider other) 47 | { 48 | resultOfEnter(false, other.tag); 49 | } 50 | 51 | private void OnTriggerEnter2D(Collider2D other) 52 | { 53 | resultOfEnter(true, other.tag); 54 | } 55 | 56 | private void OnTriggerExit2D(Collider2D other) 57 | { 58 | resultOfEnter(false, other.tag); 59 | } 60 | 61 | private void resultOfEnter(bool ableToGiveResult, string tag) 62 | { 63 | if (tag == "Player") ableToGive = ableToGiveResult; 64 | } 65 | 66 | public void Interact() 67 | { 68 | if(ableToGive && !questAlreadyGiven) 69 | { 70 | giveQuest(); 71 | } 72 | } 73 | 74 | 75 | } 76 | } -------------------------------------------------------------------------------- /Runtime/Quest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | 6 | 7 | namespace QuestSystem 8 | { 9 | [CreateAssetMenu(fileName = "New Quest", menuName = "QuestSystem/Quest")] 10 | [System.Serializable] 11 | public class Quest : ScriptableObject 12 | { 13 | [Header("Warning!!!! This ScriptaleObject has to be in a resources folder under Missions/[MisionName]")] 14 | public NodeQuest firtsNode; 15 | public NodeQuest nodeActual; 16 | public List state; 17 | public int limitDay; 18 | public int startDay; 19 | public string misionName; 20 | public bool isMain; 21 | 22 | [Header("Graph Part")] 23 | public List nodeLinkData; 24 | 25 | [System.Serializable] 26 | public class NodeLinksGraph 27 | { 28 | public string baseNodeGUID; 29 | public string portName; 30 | public string targetNodeGUID; 31 | } 32 | 33 | public void Reset() 34 | { 35 | state = new List(); 36 | nodeActual = null; 37 | 38 | NodeQuest[] getNodes = Resources.LoadAll($"{QuestConstants.MISIONS_NAME}/{ this.misionName}/Nodes"); 39 | 40 | foreach (NodeQuest n in getNodes) 41 | { 42 | for (int i = 0; i < n.nodeObjectives.Length; i++) 43 | { 44 | n.nodeObjectives[i].isCompleted = false; 45 | n.nodeObjectives[i].actualItems = 0; 46 | } 47 | #if UNITY_EDITOR 48 | EditorUtility.SetDirty(n); 49 | #endif 50 | } 51 | 52 | QuestManager.GetInstance().misionLog.RemoveQuest(this); 53 | } 54 | 55 | public void AdvanceToCurrentNode() 56 | { 57 | nodeActual = firtsNode; 58 | foreach (int i in state) 59 | { 60 | nodeActual = nodeActual.nextNode[i]; 61 | } 62 | 63 | 64 | 65 | } 66 | 67 | public void ResetNodeLinksGraph() 68 | { 69 | nodeLinkData = new List(); 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /Runtime/QuestLog.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using QuestSystem.SaveSystem; 5 | using System.Linq; 6 | 7 | namespace QuestSystem 8 | { 9 | [CreateAssetMenu(fileName = "New Quest", menuName = "QuestSystem/QuestLog")] 10 | [System.Serializable] 11 | public class QuestLog : ScriptableObject 12 | { 13 | public List curentQuests = new List(); 14 | public List doneQuest = new List(); 15 | public List failedQuest = new List(); 16 | 17 | public int businessDay; 18 | 19 | public bool IsCurrent(Quest q) => curentQuests.Contains(q); 20 | 21 | public bool IsDoned(Quest q) => doneQuest.Contains(q); 22 | 23 | public bool IsFailed(Quest q) => failedQuest.Contains(q); 24 | 25 | public void LoadUpdate(QuestLogSaveData qls) 26 | { 27 | //Coger el dia 28 | businessDay = qls.dia; 29 | 30 | //Actualizar currents 31 | curentQuests = new List(); 32 | 33 | foreach (QuestSaveData qs in qls.currentQuestSave) 34 | { 35 | Quest q = Resources.Load(QuestConstants.MISIONS_NAME + "/" + qs.name + "/" + qs.name) as Quest; 36 | q.state = qs.states; 37 | q.AdvanceToCurrentNode(); 38 | q.nodeActual.nodeObjectives = qs.actualNodeData.objectives; 39 | 40 | curentQuests.Add(q); 41 | } 42 | 43 | //Done i failed add 44 | doneQuest = new List(); 45 | 46 | foreach (QuestSaveData qs in qls.doneQuestSave) 47 | { 48 | Quest q = Resources.Load(QuestConstants.MISIONS_NAME + "/" + qs.name + "/" + qs.name) as Quest; 49 | doneQuest.Add(q); 50 | } 51 | 52 | failedQuest = new List(); 53 | 54 | foreach (QuestSaveData qs in qls.failedQuestSave) 55 | { 56 | Quest q = Resources.Load(QuestConstants.MISIONS_NAME + "/" + qs.name + "/" + qs.name) as Quest; 57 | failedQuest.Add(q); 58 | } 59 | } 60 | 61 | public void RemoveQuest(Quest q) 62 | { 63 | if (IsCurrent(q)) 64 | curentQuests.Remove(q); 65 | else if (IsDoned(q)) 66 | doneQuest.Remove(q); 67 | else if (IsFailed(q)) 68 | failedQuest.Remove(q); 69 | 70 | } 71 | 72 | public void ResetAllQuest() 73 | { 74 | List quests = curentQuests.Concat(doneQuest).Concat(failedQuest).ToList(); 75 | 76 | foreach (Quest q in quests) 77 | { 78 | q.Reset(); 79 | RemoveQuest(q); 80 | } 81 | } 82 | 83 | } 84 | } -------------------------------------------------------------------------------- /Runtime/SaveData/QuestLogSaveDataSurrogate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Runtime.Serialization; 4 | using UnityEngine; 5 | 6 | namespace QuestSystem.SaveSystem 7 | { 8 | public class QuestLogSaveDataSurrogate : ISerializationSurrogate 9 | { 10 | public void GetObjectData(object obj, SerializationInfo info, StreamingContext context) 11 | { 12 | QuestLog ql = (QuestLog)obj; 13 | 14 | info.AddValue("curentQuest", ql.curentQuests); 15 | info.AddValue("doneQuest", ql.doneQuest); 16 | info.AddValue("failedQuest", ql.failedQuest); 17 | info.AddValue("businessDay", ql.businessDay); 18 | 19 | } 20 | 21 | public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector) 22 | { 23 | QuestLog ql = (QuestLog)obj; 24 | 25 | ql.curentQuests = (List)info.GetValue("curentQuest", typeof(List)); 26 | ql.doneQuest = (List)info.GetValue("doneQuest", typeof(List)); 27 | ql.failedQuest = (List)info.GetValue("failedQuest", typeof(List)); 28 | 29 | ql.businessDay = (int)info.GetValue("businessDay", typeof(int)); 30 | 31 | obj = ql; 32 | return obj; 33 | } 34 | } 35 | 36 | [System.Serializable] 37 | public class QuestLogSaveData 38 | { 39 | public List currentQuestSave; 40 | public List doneQuestSave; 41 | public List failedQuestSave; 42 | 43 | public int dia; 44 | 45 | public QuestLogSaveData(QuestLog ql) 46 | { 47 | //Manage current quest 48 | currentQuestSave = new List(); 49 | doneQuestSave = new List(); 50 | failedQuestSave = new List(); 51 | 52 | foreach (Quest q in ql.curentQuests) 53 | { 54 | QuestSaveData aux = new QuestSaveData(); 55 | aux.name = q.misionName; 56 | aux.states = q.state; 57 | 58 | aux.actualNodeData = new NodeQuestSaveData(q.nodeActual.nodeObjectives.Length); 59 | 60 | for (int i = 0; i < q.nodeActual.nodeObjectives.Length; i++) 61 | aux.actualNodeData.objectives[i] = q.nodeActual.nodeObjectives[i]; 62 | 63 | currentQuestSave.Add(aux); 64 | } 65 | 66 | foreach (Quest q in ql.doneQuest) 67 | { 68 | QuestSaveData aux = new QuestSaveData(); 69 | aux.name = q.misionName; 70 | 71 | currentQuestSave.Add(aux); 72 | } 73 | 74 | foreach (Quest q in ql.failedQuest) 75 | { 76 | QuestSaveData aux = new QuestSaveData(); 77 | aux.name = q.misionName; 78 | 79 | currentQuestSave.Add(aux); 80 | } 81 | 82 | dia = ql.businessDay; 83 | 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Editor/CustomInspector/QuestObjectiveUpdaterEditor.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | namespace QuestSystem.QuestEditor 7 | { 8 | [CustomEditor(typeof(QuestObjectiveUpdater))] 9 | public class QuestObjectiveUpdaterEditor : Editor 10 | { 11 | private int selectedValue = 0; 12 | private string previousKey = ""; 13 | private readonly float marginX = 25; 14 | private readonly int marginBottomSpaces = 8; 15 | //private int 16 | 17 | 18 | 19 | public override void OnInspectorGUI() 20 | { 21 | QuestObjectiveUpdater qU = (QuestObjectiveUpdater)target; 22 | GUIContent objectFieldLabel = new GUIContent("Hola"); 23 | Rect commonRect = new Rect(new Vector2(20,344), new Vector2(EditorGUIUtility.currentViewWidth - marginX, 20)); 24 | DrawDefaultInspector(); 25 | 26 | 27 | 28 | //Get all Keys 29 | if (qU.nodeToUpdate != null) { 30 | string[] keyList = qU.GetListOfObjectives(); 31 | int[] numberList = new int[keyList.Length]; 32 | 33 | for (int i = 0; i < keyList.Length; i++) 34 | { 35 | numberList[i] = i; 36 | } 37 | 38 | if (!string.IsNullOrEmpty(qU.keyObjectiveSelected)) selectedValue = Array.IndexOf(keyList, qU.keyObjectiveSelected); 39 | 40 | selectedValue = EditorGUILayout.IntPopup("Keys: ", selectedValue, keyList, numberList); 41 | if (keyList.Length > 0 && selectedValue >= 0) 42 | { 43 | if(previousKey != keyList[selectedValue]) 44 | { 45 | qU.keyObjectiveSelected = keyList[selectedValue]; 46 | previousKey = keyList[selectedValue]; 47 | EditorUtility.SetDirty(qU); 48 | } 49 | } 50 | } 51 | 52 | for (int i = 0; i < marginBottomSpaces; i++) 53 | { 54 | EditorGUILayout.Space(); 55 | } 56 | 57 | if (GUI.Button(commonRect, "~")) 58 | { 59 | EditorGUIUtility.ShowObjectPicker(qU.nodeToUpdate, false, qU.GetMisionName(), GetInstanceID()); 60 | } 61 | 62 | if (Event.current.commandName == "ObjectSelectorUpdated") 63 | { 64 | if (EditorGUIUtility.GetObjectPickerControlID() == GetInstanceID()) 65 | { 66 | qU.nodeToUpdate = EditorGUIUtility.GetObjectPickerObject() as NodeQuest; 67 | EditorUtility.SetDirty(qU); 68 | } 69 | 70 | } 71 | 72 | EditorGUI.ObjectField(commonRect, " Node to Update", qU.nodeToUpdate, typeof(NodeQuest), false); 73 | 74 | 75 | for (int i = 0; i < marginBottomSpaces; i++) 76 | { 77 | EditorGUILayout.Space(); 78 | } 79 | } 80 | 81 | 82 | 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Runtime/SaveData/QuestSaveSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization; 5 | using System.Runtime.Serialization.Formatters.Binary; 6 | using UnityEngine; 7 | 8 | namespace QuestSystem.SaveSystem 9 | { 10 | public class QuestSaveSystem 11 | { 12 | public static string GetPath(string saveName) 13 | { 14 | return QuestConstants.SAVE_FILE_FOLDER + "/" + saveName + ".save"; 15 | } 16 | 17 | public static bool Save(object saveData) 18 | { 19 | BinaryFormatter formatter = GetBinaryFormater(); 20 | 21 | if (!Directory.Exists(QuestConstants.SAVE_FILE_FOLDER)) 22 | { 23 | Directory.CreateDirectory(QuestConstants.SAVE_FILE_FOLDER); 24 | } 25 | 26 | string path = QuestConstants.SAVE_FILE_PATH; 27 | Debug.Log(path); 28 | FileStream file = File.Create(path); 29 | 30 | formatter.Serialize(file, saveData); 31 | Debug.Log("Saved"); 32 | file.Close(); 33 | 34 | return true; 35 | } 36 | 37 | public static object Load(string path) 38 | { 39 | Debug.Log(path); 40 | if (!File.Exists(path)) return null; 41 | 42 | BinaryFormatter formatter = GetBinaryFormater(); 43 | 44 | FileStream file = File.Open(path, FileMode.Open); 45 | try 46 | { 47 | object save = formatter.Deserialize(file); 48 | file.Close(); 49 | Debug.Log("Loaded"); 50 | return save; 51 | } 52 | catch 53 | { 54 | Debug.LogErrorFormat("Faled to load file at {0}", path); 55 | file.Close(); 56 | return null; 57 | } 58 | } 59 | 60 | /* 61 | public static object LoadFromName(string saveName) 62 | { 63 | return Load(GetPath(saveName)); 64 | }*/ 65 | 66 | public static BinaryFormatter GetBinaryFormater() 67 | { 68 | //Create binary formater 69 | BinaryFormatter formatter = new BinaryFormatter(); 70 | 71 | 72 | //Define surrogates (especificacions de com tractar les dades) 73 | SurrogateSelector selector = new SurrogateSelector(); 74 | 75 | QuestObjectiveSurrogate objectiveSurrogate = new QuestObjectiveSurrogate(); 76 | NodeQuestSaveDataSurrogate nodeSurrogate = new NodeQuestSaveDataSurrogate(); 77 | QuestSaveDataSurrogate questSurrogate = new QuestSaveDataSurrogate(); 78 | QuestLogSaveDataSurrogate questLogSurrogate = new QuestLogSaveDataSurrogate(); 79 | 80 | //selector.AddSurrogate(typeof(QuestObjective), new StreamingContext(StreamingContextStates.All), objectiveSurrogate); 81 | selector.AddSurrogate(typeof(NodeQuest), new StreamingContext(StreamingContextStates.All), nodeSurrogate); 82 | selector.AddSurrogate(typeof(Quest), new StreamingContext(StreamingContextStates.All), questSurrogate); 83 | selector.AddSurrogate(typeof(QuestLog), new StreamingContext(StreamingContextStates.All), questLogSurrogate); 84 | 85 | formatter.SurrogateSelector = selector; 86 | 87 | return formatter; 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QuestSystem 2 | ![Nodes Gif](https://drive.google.com/uc?id=17b7JXwI9zuZHWpgKX8w82NiScTlwHo14) 3 | 4 | This is a Quest system with saves and a custom graph editor for Unity 5 | 6 | You can import directly this package into your unity project by going "Window > Package Manager > + > Add package from git url" and pasting this: https://github.com/lluispalerm/QuestSystem.git (is the same one you can get from github if you click the green button code and get the https url) 7 | 8 | For a demo project of this tool go to: https://github.com/lluispalerm/QuestSystem-Demo 9 | 10 | ## User manual 11 | 12 | ### Concepts 13 | All of this are scriptable objects except the manager 14 | 15 | #### Quest Objective 16 | The quest objectives are the minimun unit of the quest. It tracks how many interactions are required to complete itself and holds information about it. The objectives can be hidden from the player if they are suposed to be secrets. 17 | #### Node Quest 18 | The nodes of a quest can have multiple objectives. When all of of them are completed or the objective is an important one (autoExitOnCompleted) the state of the quest will go to the next node especified. It also has and extra field for a text file in the case you want to use some sort of dialog system. 19 | #### Quest 20 | A quest has 1 initial point but can have endless paths. If you use the graphic tool provided by this project inside unity it will also save the information of the nodes. If you use the a day counting for your game you can specify when in those days the quest will be avaliable. You can also say if the quest is a main quest or not. 21 | #### Quest Log 22 | You can only have one quest log per game. It keeps track of all the current assigned quests, the completed ones and even the failed ones. You can also keep track of the day of the game here. 23 | #### Quest Manager 24 | All the previos points where "just data", the manager is the one that will update an all of the parameters. 25 | 26 | ### Scene 27 | #### Quest On Object World 28 | This script will have a list to objects that need to be active in the specified poinst of the quest (When a node Quest is current) 29 | #### Quest Giver 30 | A monobehaviour to atach to a NPC or a triger and start a Quest. It also has and extra text file field. 31 | 32 | #### Quest Updater 33 | A monobehaviour to atach to a NPC or a triger that updates the the estate of a Quest. Normally it will update and objective, if its compled it updates the node, if its completed updates the quest and if the the node was an endpoint it moves the quest in the Quest Log. It also has and extra text file field. 34 | 35 | #### IQuestInteraction 36 | In order to interact with the updater and the giver you can use the Interact method implemented from the IQuestInteraction interface, or you can use a custom one. 37 | 38 | For more information about c# interface: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface 39 | 40 | ### Editor Tools 41 | The package contais a graphView based editor of the quest 42 | 43 | ![Nodes Gif](https://drive.google.com/uc?id=1AoBwwKTHv78Xo2W4mFTfjtrojzdT3dLq) 44 | 45 | ### Save system 46 | When you update and finish an objective there is a save system (By default is disabled in the editor because its alredy saved on the scriptable assets). 47 | 48 | ## Code documentation 49 | If you want to modify or contribute to this tool check the wiki for more information: https://github.com/lluispalerm/QuestSystem/wiki 50 | -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestObjectiveGraph.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.UIElements; 5 | using UnityEditor.UIElements; 6 | 7 | namespace QuestSystem.QuestEditor 8 | { 9 | [System.Serializable] 10 | public class QuestObjectiveGraph : VisualElement 11 | { 12 | public string keyName; 13 | public int maxItems; 14 | public int actualItems; 15 | public string description; 16 | public bool hiddenObjective; 17 | public bool autoExitOnCompleted; 18 | 19 | 20 | public QuestObjectiveGraph(string key = "", int max = 0, int actual = 0, string des = "", bool hiddenObjectiveDefault = false, bool autoExitOnCompletedDefault = false) 21 | { 22 | 23 | //keyName 24 | var propertyKeyNameField = new TextField("keyName:") 25 | { 26 | value = key 27 | }; 28 | 29 | propertyKeyNameField.RegisterValueChangedCallback(evt => 30 | { 31 | keyName = evt.newValue; 32 | }); 33 | 34 | 35 | this.Add(propertyKeyNameField); 36 | 37 | 38 | // Max items 39 | var propertyMaxItemsField = new IntegerField("maxItems:") 40 | { 41 | value = max 42 | }; 43 | 44 | propertyMaxItemsField.RegisterValueChangedCallback(evt => 45 | { 46 | maxItems = evt.newValue; 47 | }); 48 | 49 | this.Add(propertyMaxItemsField); 50 | 51 | // actualItems 52 | var propertyActualItemsField = new IntegerField("actualItems:") 53 | { 54 | value = actual 55 | }; 56 | 57 | propertyActualItemsField.RegisterValueChangedCallback(evt => 58 | { 59 | actualItems = evt.newValue; 60 | }); 61 | 62 | this.Add(propertyActualItemsField); 63 | 64 | //keyName 65 | var propertyDescriptionField = new TextField("description:") 66 | { 67 | value = des 68 | }; 69 | 70 | propertyDescriptionField.RegisterValueChangedCallback(evt => 71 | { 72 | description = evt.newValue; 73 | }); 74 | 75 | this.Add(propertyDescriptionField); 76 | 77 | //Hidden hiddenObjective 78 | var propertyHiddenField = new Toggle(); 79 | propertyHiddenField.label = "Hidden objective"; 80 | 81 | propertyHiddenField.RegisterValueChangedCallback(evt => 82 | { 83 | hiddenObjective = evt.newValue; 84 | }); 85 | propertyHiddenField.SetValueWithoutNotify(hiddenObjectiveDefault); 86 | 87 | this.Add(propertyHiddenField); 88 | 89 | //Auto ecit on complete 90 | var propertyAutoExitField = new Toggle(); 91 | propertyAutoExitField.label = "Auto exit on complete"; 92 | 93 | propertyAutoExitField.RegisterValueChangedCallback(evt => 94 | { 95 | autoExitOnCompleted = evt.newValue; 96 | }); 97 | propertyAutoExitField.SetValueWithoutNotify(autoExitOnCompletedDefault); 98 | 99 | this.Add(propertyAutoExitField); 100 | 101 | 102 | 103 | 104 | } 105 | 106 | } 107 | } -------------------------------------------------------------------------------- /Runtime/QuestManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEditor; 5 | using QuestSystem.SaveSystem; 6 | 7 | namespace QuestSystem 8 | { 9 | public class QuestManager 10 | { 11 | public QuestLog misionLog; 12 | public QuestLogSaveData data; 13 | 14 | private static QuestManager instance; 15 | 16 | public static QuestManager GetInstance() 17 | { 18 | if (instance == null) instance = new QuestManager(); 19 | return instance; 20 | } 21 | 22 | private QuestManager() 23 | { 24 | misionLog = Resources.Load(QuestConstants.QUEST_LOG_NAME); 25 | 26 | if (misionLog == null) 27 | { 28 | // crear 29 | misionLog = ScriptableObject.CreateInstance(); 30 | #if UNITY_EDITOR 31 | AssetDatabase.CreateAsset(misionLog, QuestConstants.RESOURCES_PATH + "/" + QuestConstants.QUEST_LOG_NAME + ".asset"); 32 | #endif 33 | 34 | } 35 | 36 | QuestLogSaveData aux = QuestSaveSystem.Load(QuestConstants.SAVE_FILE_PATH) as QuestLogSaveData; 37 | if (aux == null) Debug.Log("No file to load in " + aux); 38 | else 39 | { 40 | data = aux; 41 | misionLog.LoadUpdate(data); 42 | } 43 | } 44 | 45 | public void AddMisionToCurrent(Quest q) 46 | { 47 | q.nodeActual = q.firtsNode; 48 | q.nodeActual.ChangeTheStateOfObjects(true); 49 | misionLog.curentQuests.Add(q); 50 | } 51 | 52 | public bool IsMisionInLog(Quest q) 53 | { 54 | return misionLog.IsCurrent(q) || misionLog.IsDoned(q) || misionLog.IsFailed(q); 55 | } 56 | 57 | public bool IsCurrent(Quest q) => misionLog.IsCurrent(q); 58 | 59 | public bool IsDoned(Quest q) => misionLog.IsDoned(q); 60 | 61 | public bool IsFailed(Quest q) => misionLog.IsFailed(q); 62 | 63 | public void DonearQuest(Quest q) 64 | { 65 | misionLog.curentQuests.Remove(q); 66 | misionLog.doneQuest.Add(q); 67 | 68 | Save(); 69 | } 70 | 71 | public void Save() 72 | { 73 | //Comprovar que se guarde compilado 74 | #if !UNITY_EDITOR 75 | data = new QuestLogSaveData(misionLog); 76 | QuestSaveSystem.Save(data); 77 | #endif 78 | } 79 | 80 | 81 | 82 | /// 83 | /// Formats the current mision information like this: 84 | /// Mision Name /n 85 | /// /tab Objective description 0/1 86 | /// 87 | /// Returns the string formated 88 | public string GetCurrentQuestsInformation() 89 | { 90 | string textFormated = ""; 91 | 92 | foreach (Quest quest in misionLog.curentQuests) 93 | { 94 | textFormated += quest.misionName + "\n"; 95 | 96 | for (int i = 0; i < quest.nodeActual.nodeObjectives.Length; i++) 97 | { 98 | QuestObjective currentObjective = quest.nodeActual.nodeObjectives[i]; 99 | textFormated += " " + currentObjective.description + " " 100 | + currentObjective.actualItems + "/" + currentObjective.maxItems 101 | + "\n"; 102 | } 103 | } 104 | 105 | return textFormated; 106 | } 107 | 108 | 109 | 110 | } 111 | } -------------------------------------------------------------------------------- /Runtime/QuestOnObjectWorld.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace QuestSystem 4 | { 5 | public class QuestOnObjectWorld : MonoBehaviour 6 | { 7 | //Structs in order to show on editor 8 | [System.Serializable] 9 | public struct ObjectsForQuestTable 10 | { 11 | public Quest quest; 12 | public ActivationRowNode[] tableNodes; 13 | } 14 | 15 | [System.Serializable] 16 | public struct ActivationRowNode 17 | { 18 | public NodeQuest node; 19 | public bool activate; 20 | } 21 | 22 | public ObjectsForQuestTable[] objectsForQuestTable; 23 | 24 | public GameObject[] objectsToControlList; 25 | 26 | private QuestManager questManagerRef; 27 | // Start is called before the first frame update 28 | private void Awake() 29 | { 30 | questManagerRef = QuestManager.GetInstance(); 31 | } 32 | 33 | 34 | 35 | void Start() 36 | { 37 | //Default: every object is disabled 38 | foreach (GameObject g in objectsToControlList) 39 | { 40 | g.SetActive(false); 41 | } 42 | 43 | for (int i = 0; i < objectsForQuestTable.Length; i++) 44 | { 45 | bool isCurrent = questManagerRef.IsCurrent(objectsForQuestTable[i].quest); 46 | bool hasBeenActivated = false; 47 | 48 | 49 | for (int j = 0; j < objectsForQuestTable[i].tableNodes.Length; j++) 50 | { 51 | if (objectsForQuestTable[i].tableNodes[j].activate) 52 | { 53 | foreach (GameObject g in objectsToControlList) 54 | { 55 | objectsForQuestTable[i].tableNodes[j].node.AddObject(g); 56 | } 57 | } 58 | 59 | if (!hasBeenActivated && isCurrent && objectsForQuestTable[i].quest.nodeActual == objectsForQuestTable[i].tableNodes[j].node) 60 | { 61 | foreach (GameObject g in objectsToControlList) 62 | { 63 | g.SetActive(objectsForQuestTable[i].tableNodes[j].activate); 64 | } 65 | hasBeenActivated = true; 66 | } 67 | } 68 | } 69 | 70 | 71 | 72 | 73 | } 74 | 75 | public void PopulateChildListDefault() 76 | { 77 | int numberOfChilds = transform.childCount; 78 | GameObject[] children = new GameObject[numberOfChilds]; 79 | 80 | for (int i = 0; i < numberOfChilds; i++) 81 | { 82 | children[i] = transform.GetChild(i).gameObject; 83 | } 84 | 85 | objectsToControlList = children; 86 | } 87 | 88 | public void GetAllNodesFromQuest() 89 | { 90 | for (int i = 0; i < objectsForQuestTable.Length; i++) 91 | { 92 | string path = $"{QuestConstants.MISIONS_NAME}/{objectsForQuestTable[i].quest.misionName}/{QuestConstants.NODES_FOLDER_NAME}"; 93 | NodeQuest[] nodesFromQuest = Resources.LoadAll(path); 94 | if (nodesFromQuest != null && nodesFromQuest.Length > 0) 95 | { 96 | ActivationRowNode[] tableNodes = new ActivationRowNode[nodesFromQuest.Length]; 97 | for (int j = 0; j < tableNodes.Length; j++) 98 | { 99 | tableNodes[j].node = nodesFromQuest[j]; 100 | } 101 | 102 | objectsForQuestTable[i].tableNodes = tableNodes; 103 | } 104 | } 105 | } 106 | 107 | } 108 | 109 | 110 | 111 | 112 | } -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphEditor.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEditor.Experimental.GraphView; 5 | using UnityEditor; 6 | using UnityEngine; 7 | using UnityEngine.UIElements; 8 | using UnityEditor.UIElements; 9 | using System; 10 | 11 | namespace QuestSystem.QuestEditor 12 | { 13 | public class QuestGraphEditor : GraphViewEditorWindow 14 | { 15 | public static Quest questForGraph; 16 | 17 | private QuestGraphView _questGraph; 18 | private bool mouseClicked; 19 | 20 | [MenuItem("Tools/QuestGraph")] 21 | public static void OpenQuestGraphWindow() 22 | { 23 | questForGraph = null; 24 | var window = GetWindow(); 25 | window.titleContent = new GUIContent("QuestGraph"); 26 | 27 | } 28 | 29 | private void OnEnable() 30 | { 31 | ConstructGraphView(); 32 | GenerateToolBar(); 33 | GenerateMinimap(); 34 | } 35 | 36 | 37 | 38 | 39 | private void GenerateMinimap() 40 | { 41 | var minimap = new MiniMap { anchored = true }; 42 | minimap.SetPosition(new Rect(10, 30, 200, 140)); 43 | 44 | _questGraph.Add(minimap); 45 | } 46 | 47 | private void ConstructGraphView() 48 | { 49 | _questGraph = new QuestGraphView(this) 50 | { 51 | name = "Quest Graph" 52 | }; 53 | 54 | if (questForGraph != null) 55 | _questGraph.misionName = questForGraph.misionName; 56 | 57 | _questGraph.StretchToParentSize(); 58 | 59 | rootVisualElement.Add(_questGraph); 60 | } 61 | 62 | private void GenerateToolBar() 63 | { 64 | var toolbar = new Toolbar(); 65 | 66 | var nodeCreateButton = new Button(clickEvent: () => { _questGraph.CreateNode("NodeQuest", Vector2.zero); }); 67 | nodeCreateButton.text = "Crete Node"; 68 | 69 | toolbar.Add(nodeCreateButton); 70 | 71 | //Save 72 | toolbar.Add(new Button(clickEvent: () => SaveQuestData()) { text = "Save Quest Data" }); 73 | toolbar.Add(new Button(clickEvent: () => LoadQuestData()) { text = "Load Quest Data" }); 74 | 75 | //Current quest 76 | var Ins = new ObjectField("Quest editing"); 77 | Ins.objectType = typeof(Quest); 78 | Ins.RegisterValueChangedCallback(evt => 79 | { 80 | questForGraph = evt.newValue as Quest; 81 | }); 82 | 83 | toolbar.Add(Ins); 84 | 85 | rootVisualElement.Add(toolbar); 86 | } 87 | 88 | private void CreateQuest() 89 | { 90 | // create new scriptableObject 91 | 92 | //questForGraph = 93 | 94 | Quest newQuest = ScriptableObject.CreateInstance(); 95 | 96 | NodeQuestGraph entryNode = _questGraph.GetEntryPointNode(); 97 | newQuest.misionName = entryNode.misionName; 98 | newQuest.isMain = entryNode.isMain; 99 | newQuest.startDay = entryNode.startDay; 100 | newQuest.limitDay = entryNode.limitDay; 101 | 102 | questForGraph = newQuest; 103 | 104 | var saveUtility = QuestGraphSaveUtility.GetInstance(_questGraph); 105 | 106 | saveUtility.CheckFolders(questForGraph); 107 | AssetDatabase.CreateAsset(newQuest, $"{QuestConstants.MISIONS_FOLDER}/{newQuest.misionName}/{newQuest.misionName}.asset"); 108 | 109 | //saveUtility.LoadGraph(questForGraph); 110 | 111 | } 112 | 113 | private void LoadQuestData() 114 | { 115 | if (questForGraph == null) 116 | { 117 | EditorUtility.DisplayDialog("Error!!", "No quest to load!", "OK"); 118 | return; 119 | } 120 | 121 | var saveUtility = QuestGraphSaveUtility.GetInstance(_questGraph); 122 | saveUtility.LoadGraph(questForGraph); 123 | } 124 | 125 | private void SaveQuestData() 126 | { 127 | if (questForGraph == null) 128 | { 129 | CreateQuest(); 130 | } 131 | 132 | 133 | var saveUtility = QuestGraphSaveUtility.GetInstance(_questGraph); 134 | Debug.Log(questForGraph.misionName); 135 | saveUtility.SaveGraph(questForGraph); 136 | } 137 | 138 | private void OnDisable() 139 | { 140 | rootVisualElement.Remove(_questGraph); 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /Runtime/QuestObjectiveUpdater.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using UnityEngine.Events; 5 | 6 | namespace QuestSystem 7 | { 8 | public class QuestObjectiveUpdater : MonoBehaviour, IQuestInteraction 9 | { 10 | public Quest questToUpdate; 11 | [HideInInspector] public NodeQuest nodeToUpdate; 12 | [HideInInspector] public string keyObjectiveSelected; 13 | public int adder = 1; 14 | public int exit = 0; 15 | public TextAsset extraText; 16 | 17 | public UnityEvent eventsOnUpdate; 18 | public UnityEvent eventsOnFinish; 19 | 20 | private bool canUpdate; 21 | private bool updating; 22 | private bool isDone; 23 | private QuestManager questManagerRef; 24 | 25 | 26 | // Start is called before the first frame update 27 | void Start() 28 | { 29 | canUpdate = false; 30 | updating = false; 31 | questManagerRef = QuestManager.GetInstance(); 32 | isDone = questManagerRef.IsDoned(questToUpdate) || questManagerRef.IsFailed(questToUpdate); 33 | } 34 | 35 | public void updateQuest() 36 | { 37 | //Afegir instancies al objectiu 38 | if (!string.IsNullOrEmpty(keyObjectiveSelected)) { 39 | QuestObjective questObjective = new QuestObjective(); 40 | 41 | int i = 0; 42 | //Find 43 | while (questObjective.keyName == null && i < nodeToUpdate.nodeObjectives.Length) 44 | { 45 | if (nodeToUpdate.nodeObjectives[i].keyName == keyObjectiveSelected) 46 | { 47 | questObjective = nodeToUpdate.nodeObjectives[i]; 48 | } 49 | i++; 50 | } 51 | 52 | questObjective.actualItems += adder; 53 | 54 | if (IsNodeCompleted(questObjective)) 55 | { 56 | if (nodeToUpdate.isFinal) 57 | { 58 | questToUpdate.nodeActual.ChangeTheStateOfObjects(false); 59 | questManagerRef.DonearQuest(questToUpdate); 60 | isDone = true; 61 | } 62 | else 63 | { 64 | questToUpdate.nodeActual.ChangeTheStateOfObjects(false); 65 | questToUpdate.state.Add(exit); 66 | Debug.Log("Exit :" + exit + ", Next node: " + nodeToUpdate.nextNode.Count); 67 | questToUpdate.nodeActual = nodeToUpdate.nextNode[exit]; 68 | questToUpdate.nodeActual.ChangeTheStateOfObjects(true); 69 | 70 | } 71 | 72 | eventsOnFinish.Invoke(); 73 | QuestManager.GetInstance().Save(); 74 | } 75 | 76 | eventsOnUpdate.Invoke(); 77 | } 78 | } 79 | 80 | IEnumerator ShowDialogue() 81 | { 82 | updating = true; 83 | 84 | if (extraText == null) 85 | { 86 | yield return null; 87 | updateQuest(); 88 | updating = false; 89 | } 90 | else 91 | { 92 | 93 | } 94 | } 95 | 96 | private bool isCurrent() => questToUpdate.nodeActual == nodeToUpdate; 97 | 98 | private bool isAbleToUpdateQuest() => canUpdate && !isDone && isCurrent() && !updating; 99 | 100 | public void ChangeExit(int n) 101 | { 102 | exit = n; 103 | } 104 | 105 | //Delete the ones you don't want to use 106 | 107 | private void OnTriggerEnter(Collider other) 108 | { 109 | resultOfEnter(true, other.tag); 110 | } 111 | 112 | private void OnTriggerExit(Collider other) 113 | { 114 | resultOfEnter(false, other.tag); 115 | } 116 | 117 | private void OnTriggerEnter2D(Collider2D other) 118 | { 119 | resultOfEnter(true, other.tag); 120 | } 121 | 122 | private void OnTriggerExit2D(Collider2D other) 123 | { 124 | resultOfEnter(false, other.tag); 125 | } 126 | 127 | private void resultOfEnter(bool canUpdateResult, string tag) 128 | { 129 | if (tag == "Player") canUpdate = canUpdateResult; 130 | } 131 | 132 | public string GetMisionName() 133 | { 134 | string returnValue = ""; 135 | 136 | if (questToUpdate != null) returnValue += questToUpdate.misionName + "_"; 137 | 138 | return returnValue; 139 | } 140 | 141 | public string[] GetListOfObjectives() 142 | { 143 | List returnList = new List() ; 144 | 145 | if(nodeToUpdate != null) 146 | { 147 | if (nodeToUpdate.nodeObjectives != null) { 148 | for (int i = 0; i < nodeToUpdate.nodeObjectives.Length; i++) 149 | { 150 | returnList.Add(nodeToUpdate.nodeObjectives[i].keyName); 151 | } 152 | } 153 | } 154 | 155 | return returnList.ToArray(); 156 | } 157 | 158 | public void Interact() 159 | { 160 | if (isAbleToUpdateQuest()) 161 | { 162 | StartCoroutine(ShowDialogue()); 163 | } 164 | } 165 | 166 | private bool IsNodeCompleted(QuestObjective questObjective) 167 | { 168 | if (questObjective.actualItems >= questObjective.maxItems) 169 | { 170 | questObjective.isCompleted = true; 171 | if(questObjective.autoExitOnCompleted) return true; 172 | } 173 | 174 | for (int i = 0; i < nodeToUpdate.nodeObjectives.Length; i++) 175 | { 176 | if (!nodeToUpdate.nodeObjectives[i].isCompleted && !nodeToUpdate.nodeObjectives[i].autoExitOnCompleted) 177 | { 178 | return false; 179 | } 180 | } 181 | 182 | return true; 183 | } 184 | } 185 | } -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphView.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEditor.Experimental.GraphView; 5 | using UnityEditor; 6 | using UnityEngine; 7 | using UnityEngine.UIElements; 8 | using UnityEditor.UIElements; 9 | 10 | namespace QuestSystem.QuestEditor 11 | { 12 | public class QuestGraphView : GraphView 13 | { 14 | public string misionName; 15 | 16 | private QuestNodeSearchWindow _searchWindow; 17 | public Quest questRef; 18 | private QuestGraphView _self; 19 | private QuestGraphEditor editorWindow; 20 | 21 | 22 | public QuestGraphView(EditorWindow _editorWindow, Quest q = null) 23 | { 24 | questRef = q; 25 | editorWindow = (QuestGraphEditor)_editorWindow; 26 | styleSheets.Add(Resources.Load("QuestGraph")); 27 | SetupZoom(ContentZoomer.DefaultMinScale, ContentZoomer.DefaultMaxScale); 28 | 29 | this.AddManipulator(new ContentDragger()); 30 | this.AddManipulator(new SelectionDragger()); 31 | this.AddManipulator(new RectangleSelector()); 32 | 33 | //Grid 34 | var grid = new GridBackground(); 35 | Insert(0, grid); 36 | grid.StretchToParentSize(); 37 | 38 | this.AddElement(GenerateEntryPointNode()); 39 | this.AddSearchWindow(editorWindow); 40 | _self = this; 41 | 42 | } 43 | 44 | 45 | //TODO: Create node at desired position with fewer hide 46 | /*public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) 47 | { 48 | base.BuildContextualMenu(evt); 49 | 50 | if (evt.target is GraphView) 51 | { 52 | evt.menu.InsertAction(1,"Create Node", (e) => { 53 | 54 | 55 | var a = editorWindow.rootVisualElement; var b = editorWindow.position.position; var c = editorWindow.rootVisualElement.parent; 56 | 57 | var context = new SearchWindowContext(e.eventInfo.mousePosition, a.worldBound.x, a.worldBound.y); 58 | Vector2 mousePosition = editorWindow.rootVisualElement.ChangeCoordinatesTo(editorWindow.rootVisualElement, context.screenMousePosition - editorWindow.position.position); 59 | Vector2 graphViewMousePosition = this.contentViewContainer.WorldToLocal(mousePosition); 60 | 61 | CreateNode("NodeQuest", mousePosition); 62 | }); 63 | } 64 | }*/ 65 | 66 | private void AddSearchWindow(EditorWindow editorWindow) 67 | { 68 | _searchWindow = ScriptableObject.CreateInstance(); 69 | _searchWindow.Init(this, editorWindow); 70 | nodeCreationRequest = context => SearchWindow.Open(new SearchWindowContext(context.screenMousePosition),_searchWindow); 71 | } 72 | 73 | private Port GeneratePort(NodeQuestGraph node, Direction direction, Port.Capacity capacity = Port.Capacity.Single) 74 | { 75 | return node.InstantiatePort(Orientation.Horizontal, direction, capacity, typeof(float)); 76 | } 77 | 78 | 79 | public NodeQuestGraph GenerateEntryPointNode() 80 | { 81 | var node = new NodeQuestGraph 82 | { 83 | title = "Start", 84 | GUID = Guid.NewGuid().ToString(), 85 | entryPoint = true 86 | }; 87 | 88 | //Add ouput port 89 | var generatetPort = GeneratePort(node, Direction.Output); 90 | generatetPort.portName = "Next"; 91 | node.outputContainer.Add(generatetPort); 92 | 93 | //Quest params 94 | var box = new Box(); 95 | 96 | // 97 | var misionName = new TextField("Mision Name:") 98 | { 99 | value = "Temp name" 100 | }; 101 | 102 | misionName.RegisterValueChangedCallback(evt => 103 | { 104 | node.misionName = evt.newValue; 105 | }); 106 | 107 | box.Add(misionName); 108 | 109 | // 110 | var isMain = new Toggle(); 111 | isMain.label = "isMain"; 112 | 113 | isMain.value = false; 114 | 115 | isMain.RegisterValueChangedCallback(evt => 116 | { 117 | node.isMain = evt.newValue; 118 | }); 119 | 120 | //isMain.SetValueWithoutNotify(false); 121 | 122 | box.Add(isMain); 123 | 124 | // 125 | var startDay = new IntegerField("Start Day:") 126 | { 127 | value = 0 128 | }; 129 | 130 | startDay.RegisterValueChangedCallback(evt => 131 | { 132 | node.startDay = evt.newValue; 133 | }); 134 | 135 | box.Add(startDay); 136 | 137 | // 138 | var limitDay = new IntegerField("Limit Day:") 139 | { 140 | value = 0 141 | }; 142 | 143 | limitDay.RegisterValueChangedCallback(evt => 144 | { 145 | node.limitDay = evt.newValue; 146 | }); 147 | 148 | box.Add(limitDay); 149 | 150 | node.mainContainer.Add(box); 151 | 152 | 153 | //Refresh visual part 154 | node.RefreshExpandedState(); 155 | node.RefreshPorts(); 156 | 157 | node.SetPosition(new Rect(100, 200, 100, 150)); 158 | 159 | return node; 160 | 161 | } 162 | 163 | public override List GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter) 164 | { 165 | var compatiblePorts = new List(); 166 | 167 | //Reglas de conexions 168 | ports.ForEach(port => 169 | { 170 | if (startPort != port && startPort.node != port.node) 171 | compatiblePorts.Add(port); 172 | }); 173 | 174 | return compatiblePorts; 175 | } 176 | 177 | public void CreateNode(string nodeName, Vector2 position) 178 | { 179 | AddElement(CreateNodeQuest(nodeName,position)); 180 | } 181 | 182 | public NodeQuestGraph CreateNodeQuest(string nodeName, Vector2 position, TextAsset ta = null, bool end = false) 183 | { 184 | var node = new NodeQuestGraph 185 | { 186 | title = nodeName, 187 | GUID = Guid.NewGuid().ToString(), 188 | questObjectives = new List(), 189 | }; 190 | 191 | //Add Input port 192 | var generatetPortIn = GeneratePort(node, Direction.Input, Port.Capacity.Multi); 193 | generatetPortIn.portName = "Input"; 194 | node.inputContainer.Add(generatetPortIn); 195 | 196 | node.styleSheets.Add(Resources.Load("Node")); 197 | 198 | //Add button to add ouput 199 | var button = new Button(clickEvent: () => 200 | { 201 | AddNextNodePort(node); 202 | }); 203 | button.text = "New Next Node"; 204 | node.titleContainer.Add(button); 205 | 206 | //Button to add more objectives 207 | var button2 = new Button(clickEvent: () => 208 | { 209 | AddNextQuestObjective(node); 210 | }); 211 | button2.text = "Add new Objective"; 212 | 213 | //Hide/Unhide elements 214 | var hideButton = new Button(clickEvent: () => 215 | { 216 | HideUnhide(node, button2); 217 | }); 218 | hideButton.text = "Hide/Unhide"; 219 | 220 | 221 | 222 | 223 | //Extra information 224 | var extraText = new ObjectField("Extra information:"); 225 | extraText.objectType = typeof(TextAsset); 226 | 227 | extraText.RegisterValueChangedCallback(evt => 228 | { 229 | node.extraText = evt.newValue as TextAsset; 230 | }); 231 | extraText.SetValueWithoutNotify(ta); 232 | 233 | //Bool es final 234 | var togle = new Toggle(); 235 | togle.label = "isFinal"; 236 | 237 | togle.RegisterValueChangedCallback(evt => 238 | { 239 | node.isFinal = evt.newValue; 240 | }); 241 | togle.SetValueWithoutNotify(end); 242 | 243 | var container = new Box(); 244 | node.mainContainer.Add(container);// Container per a tenir fons solid 245 | 246 | container.Add(extraText); 247 | container.Add(togle); 248 | container.Add(hideButton); 249 | container.Add(button2); 250 | 251 | node.objectivesRef = new Box(); 252 | container.Add(node.objectivesRef); 253 | 254 | //Refresh la part Visual 255 | node.RefreshExpandedState(); 256 | node.RefreshPorts(); 257 | node.SetPosition(new Rect(position.x, position.y, 400, 450)); 258 | 259 | return node; 260 | } 261 | 262 | private void HideUnhide(NodeQuestGraph node, Button b) 263 | { 264 | bool show = !b.visible; 265 | b.visible = show; 266 | 267 | foreach (var objective in node.questObjectives) 268 | { 269 | if (show) 270 | { 271 | node.objectivesRef.Add(objective); 272 | } 273 | else 274 | { 275 | node.objectivesRef.Remove(objective); 276 | } 277 | } 278 | 279 | node.RefreshExpandedState(); 280 | node.RefreshPorts(); 281 | } 282 | 283 | public void AddNextNodePort(NodeQuestGraph node, string overrideName = "") 284 | { 285 | var generatetPort = GeneratePort(node, Direction.Output); 286 | int nPorts = node.outputContainer.Query("connector").ToList().Count; 287 | 288 | //generatetPort.portName = "NextNode " + nPorts; 289 | 290 | string choicePortName = string.IsNullOrEmpty(overrideName) ? "NextNode " + nPorts : overrideName; 291 | generatetPort.portName = choicePortName; 292 | 293 | var deleteButton = new Button(clickEvent: () => RemovePort(node, generatetPort)) 294 | { 295 | text = "x" 296 | }; 297 | generatetPort.contentContainer.Add(deleteButton); 298 | 299 | node.outputContainer.Add(generatetPort); 300 | node.RefreshPorts(); 301 | node.RefreshExpandedState(); 302 | } 303 | 304 | private void RemovePort(NodeQuestGraph node, Port p) 305 | { 306 | var targetEdge = edges.ToList().Where(x => x.output.portName == p.portName && x.output.node == p.node); 307 | if (targetEdge.Any()) 308 | { 309 | var edge = targetEdge.First(); 310 | edge.input.Disconnect(edge); 311 | RemoveElement(targetEdge.First()); 312 | } 313 | 314 | node.outputContainer.Remove(p); 315 | node.RefreshPorts(); 316 | node.RefreshExpandedState(); 317 | } 318 | 319 | public void removeQuestObjective(NodeQuestGraph nodes, QuestObjectiveGraph objective) 320 | { 321 | nodes.objectivesRef.Remove(objective); 322 | nodes.questObjectives.Remove(objective); 323 | nodes.RefreshExpandedState(); 324 | } 325 | 326 | private void AddNextQuestObjective(NodeQuestGraph node) 327 | { 328 | var Q = new QuestObjectiveGraph(); 329 | 330 | var deleteButton = new Button(clickEvent: () => removeQuestObjective(node, Q)) 331 | { 332 | text = "x" 333 | }; 334 | Q.contentContainer.Add(deleteButton); 335 | 336 | //Visual Box separator 337 | var newBox = new Box(); 338 | Q.Add(newBox); 339 | 340 | node.objectivesRef.Add(Q); 341 | node.questObjectives.Add(Q); 342 | node.RefreshPorts(); 343 | node.RefreshExpandedState(); 344 | } 345 | 346 | public NodeQuestGraph GetEntryPointNode() 347 | { 348 | List nodeList = this.nodes.ToList().Cast().ToList(); 349 | return nodeList.First(node => node.entryPoint); 350 | } 351 | 352 | 353 | 354 | } 355 | } -------------------------------------------------------------------------------- /Editor/GraphEditor/QuestGraphSaveUtility.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UnityEngine; 5 | using UnityEngine.UIElements; 6 | using UnityEditor.UIElements; 7 | using UnityEditor.Experimental.GraphView; 8 | using UnityEditor; 9 | using UnityEngine.Windows; 10 | using System; 11 | 12 | namespace QuestSystem.QuestEditor 13 | { 14 | public class QuestGraphSaveUtility 15 | { 16 | private QuestGraphView _targetGraphView; 17 | 18 | private List Edges => _targetGraphView.edges.ToList(); 19 | private List node => _targetGraphView.nodes.ToList().Cast().ToList(); 20 | 21 | private List _cacheNodes = new List(); 22 | 23 | public static QuestGraphSaveUtility GetInstance(QuestGraphView targetGraphView) 24 | { 25 | return new QuestGraphSaveUtility 26 | { 27 | _targetGraphView = targetGraphView, 28 | }; 29 | } 30 | 31 | private void creteNodeQuestAssets(Quest Q, ref List NodesInGraph) 32 | { 33 | int j = 0; 34 | CheckFolders(Q); 35 | 36 | string path = QuestConstants.MISIONS_FOLDER + $"/{Q.misionName}/Nodes"; 37 | string tempPath = QuestConstants.MISIONS_FOLDER + $"/{Q.misionName}/Temp"; 38 | //Move all nodes OUT to temp 39 | if (AssetDatabase.IsValidFolder(path)) { 40 | AssetDatabase.CreateFolder(QuestConstants.MISIONS_FOLDER + $"{Q.misionName}", "Temp"); 41 | 42 | var debug = AssetDatabase.MoveAsset(path, tempPath); 43 | } 44 | 45 | 46 | Debug.Log("GUID: " + AssetDatabase.CreateFolder(QuestConstants.MISIONS_FOLDER + $"/{Q.misionName}", "Nodes")); 47 | 48 | //Order by position 49 | List nodeList = node.Where(node => !node.entryPoint).ToList(); 50 | 51 | foreach (var nodequest in nodeList) 52 | { 53 | //Visual part 54 | string nodeSaveName = Q.misionName + "_Node" + j; 55 | NodeQuest saveNode; 56 | 57 | //Si existe en temps 58 | bool alredyExists = false; 59 | if (alredyExists = !string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(tempPath + "/" + nodeSaveName + ".asset"))) 60 | { 61 | saveNode = AssetDatabase.LoadAssetAtPath(tempPath + "/" + nodeSaveName + ".asset"); 62 | } 63 | else 64 | { 65 | saveNode = ScriptableObject.CreateInstance(); 66 | } 67 | 68 | saveNode.GUID = nodequest.GUID; 69 | saveNode.position = nodequest.GetPosition().position; 70 | 71 | //Quest Part 72 | saveNode.isFinal = nodequest.isFinal; 73 | saveNode.extraText = nodequest.extraText; 74 | saveNode.nodeObjectives = createObjectivesFromGraph(nodequest.questObjectives); 75 | 76 | if(!alredyExists) 77 | AssetDatabase.CreateAsset(saveNode, $"{QuestConstants.MISIONS_FOLDER}/{Q.misionName}/Nodes/{nodeSaveName}.asset"); 78 | else 79 | { 80 | AssetDatabase.MoveAsset(tempPath + "/" + nodeSaveName + ".asset", path + "/" + nodeSaveName + ".asset"); 81 | } 82 | 83 | EditorUtility.SetDirty(saveNode); 84 | AssetDatabase.SaveAssets(); 85 | 86 | NodesInGraph.Add(saveNode); 87 | j++; 88 | } 89 | 90 | AssetDatabase.DeleteAsset(tempPath); 91 | 92 | } 93 | 94 | public void CheckFolders(Quest Q) 95 | { 96 | if (!AssetDatabase.IsValidFolder(QuestConstants.RESOURCES_PATH)) 97 | { 98 | AssetDatabase.CreateFolder(QuestConstants.PARENT_PATH, QuestConstants.RESOURCES_NAME); 99 | } 100 | 101 | if (!AssetDatabase.IsValidFolder(QuestConstants.MISIONS_FOLDER)) 102 | { 103 | AssetDatabase.CreateFolder(QuestConstants.RESOURCES_PATH, QuestConstants.MISIONS_NAME); 104 | } 105 | 106 | if (!AssetDatabase.IsValidFolder(QuestConstants.MISIONS_FOLDER + $"/{Q.misionName}")) 107 | { 108 | AssetDatabase.CreateFolder(QuestConstants.MISIONS_FOLDER, $"{Q.misionName}"); 109 | } 110 | 111 | 112 | } 113 | 114 | private void saveConections(Quest Q, List nodesInGraph) 115 | { 116 | var connectedPorts = Edges.Where(x => x.input.node != null).ToArray(); 117 | Q.ResetNodeLinksGraph(); 118 | 119 | 120 | foreach (NodeQuest currentNode in nodesInGraph) 121 | { 122 | currentNode.nextNode.Clear(); 123 | } 124 | 125 | 126 | for (int i = 0; i < connectedPorts.Length; i++) 127 | { 128 | var outputNode = connectedPorts[i].output.node as NodeQuestGraph; 129 | var inputNode = connectedPorts[i].input.node as NodeQuestGraph; 130 | 131 | Q.nodeLinkData.Add(new Quest.NodeLinksGraph 132 | { 133 | baseNodeGUID = outputNode.GUID, 134 | portName = connectedPorts[i].output.portName, 135 | targetNodeGUID = inputNode.GUID 136 | }); 137 | 138 | //Add to next node list 139 | NodeQuest baseNode = nodesInGraph.Find(n => n.GUID == outputNode.GUID); 140 | NodeQuest targetNode = nodesInGraph.Find(n => n.GUID == inputNode.GUID); 141 | 142 | if (targetNode != null && baseNode != null) 143 | baseNode.nextNode.Add(targetNode); 144 | } 145 | } 146 | 147 | public void SaveGraph(Quest Q) 148 | { 149 | if (!Edges.Any()) return; 150 | 151 | 152 | List NodesInGraph = new List(); 153 | // Nodes 154 | creteNodeQuestAssets(Q, ref NodesInGraph); 155 | 156 | // Conections 157 | saveConections(Q, NodesInGraph); 158 | 159 | //Last Quest parameters 160 | 161 | var startNode = node.Find(node => node.entryPoint); //Find the first node Graph 162 | Q.startDay = startNode.startDay; 163 | Q.limitDay = startNode.limitDay; 164 | Q.isMain = startNode.isMain; 165 | 166 | 167 | //Questionable 168 | var firstMisionNode = Edges.Find(x => x.output.portName == "Next"); 169 | var firstMisionNode2 = firstMisionNode.input.node as NodeQuestGraph; 170 | string GUIDfirst = firstMisionNode2.GUID; 171 | Q.firtsNode = NodesInGraph.Find(n => n.GUID == GUIDfirst); 172 | 173 | EditorUtility.SetDirty(Q); 174 | 175 | 176 | } 177 | 178 | public void LoadGraph(Quest Q) 179 | { 180 | if (Q == null) 181 | { 182 | EditorUtility.DisplayDialog("Error!!", "Quest aprece como null, revisa el scriptable object", "OK"); 183 | return; 184 | } 185 | 186 | NodeQuest[] getNodes = Resources.LoadAll($"{QuestConstants.MISIONS_NAME}/{ Q.misionName}/Nodes"); 187 | _cacheNodes = new List(getNodes); 188 | 189 | clearGraph(Q); 190 | LoadNodes(Q); 191 | ConectNodes(Q); 192 | } 193 | 194 | private void clearGraph(Quest Q) 195 | { 196 | node.Find(x => x.entryPoint).GUID = Q.nodeLinkData[0].baseNodeGUID; 197 | 198 | foreach (var node in node) 199 | { 200 | if (node.entryPoint) 201 | { 202 | 203 | var aux = node.mainContainer.Children().ToList(); 204 | var aux2 = aux[2].Children().ToList(); 205 | 206 | // C 207 | TextField misionName = aux2[0] as TextField; 208 | Toggle isMain = aux2[1] as Toggle; 209 | IntegerField startDay = aux2[2] as IntegerField; 210 | IntegerField limitDay = aux2[3] as IntegerField; 211 | 212 | misionName.value = Q.misionName; 213 | isMain.value = Q.isMain; 214 | startDay.value = Q.startDay; 215 | limitDay.value = Q.limitDay; 216 | 217 | // 218 | node.limitDay = Q.limitDay; 219 | node.startDay = Q.startDay; 220 | node.isMain = Q.isMain; 221 | node.misionName = Q.misionName; 222 | 223 | continue; 224 | } 225 | 226 | //Remove edges 227 | Edges.Where(x => x.input.node == node).ToList().ForEach(edge => _targetGraphView.RemoveElement(edge)); 228 | 229 | //Remove Node 230 | _targetGraphView.RemoveElement(node); 231 | } 232 | } 233 | 234 | private void LoadNodes(Quest Q) 235 | { 236 | foreach (var node in _cacheNodes) 237 | { 238 | var tempNode = _targetGraphView.CreateNodeQuest(node.name, Vector2.zero, node.extraText, node.isFinal); 239 | //Load node variables 240 | tempNode.GUID = node.GUID; 241 | tempNode.extraText = node.extraText; 242 | tempNode.isFinal = node.isFinal; 243 | tempNode.RefreshPorts(); 244 | 245 | if (node.nodeObjectives != null) { 246 | foreach (QuestObjective qObjective in node.nodeObjectives) 247 | { 248 | //CreateObjectives 249 | QuestObjectiveGraph objtemp = new QuestObjectiveGraph(qObjective.keyName, qObjective.maxItems, qObjective.actualItems, 250 | qObjective.description, qObjective.hiddenObjective, qObjective.autoExitOnCompleted); 251 | 252 | 253 | var deleteButton = new Button(clickEvent: () => _targetGraphView.removeQuestObjective(tempNode, objtemp)) 254 | { 255 | text = "x" 256 | }; 257 | objtemp.Add(deleteButton); 258 | 259 | var newBox = new Box(); 260 | objtemp.Add(newBox); 261 | 262 | 263 | objtemp.actualItems = qObjective.actualItems; 264 | objtemp.description = qObjective.description; 265 | objtemp.maxItems = qObjective.maxItems; 266 | objtemp.keyName = qObjective.keyName; 267 | objtemp.hiddenObjective = qObjective.hiddenObjective; 268 | objtemp.autoExitOnCompleted = qObjective.autoExitOnCompleted; 269 | 270 | tempNode.objectivesRef.Add(objtemp); 271 | tempNode.questObjectives.Add(objtemp); 272 | } 273 | } 274 | 275 | 276 | _targetGraphView.AddElement(tempNode); 277 | 278 | var nodePorts = Q.nodeLinkData.Where(x => x.baseNodeGUID == node.GUID).ToList(); 279 | nodePorts.ForEach(x => _targetGraphView.AddNextNodePort(tempNode)); 280 | 281 | 282 | } 283 | } 284 | 285 | private void ConectNodes(Quest Q) 286 | { 287 | List nodeListCopy = new List(node); 288 | 289 | for (int i = 0; i < nodeListCopy.Count; i++) 290 | { 291 | var conections = Q.nodeLinkData.Where(x => x.baseNodeGUID == nodeListCopy[i].GUID).ToList(); 292 | 293 | for (int j = 0; j < conections.Count(); j++) 294 | { 295 | string targetNodeGUID = conections[j].targetNodeGUID; 296 | var targetNode = nodeListCopy.Find(x => x.GUID == targetNodeGUID); 297 | LinkNodes(nodeListCopy[i].outputContainer[j].Q(), (Port)targetNode.inputContainer[0]); 298 | 299 | targetNode.SetPosition(new Rect(_cacheNodes.First(x => x.GUID == targetNodeGUID).position, new Vector2(150, 200))); 300 | } 301 | } 302 | } 303 | 304 | private void LinkNodes(Port outpor, Port inport) 305 | { 306 | var tempEdge = new Edge 307 | { 308 | output = outpor, 309 | input = inport 310 | }; 311 | 312 | tempEdge.input.Connect(tempEdge); 313 | tempEdge.output.Connect(tempEdge); 314 | _targetGraphView.Add(tempEdge); 315 | 316 | 317 | } 318 | 319 | public QuestObjective[] createObjectivesFromGraph(List qog) 320 | { 321 | List Listaux = new List(); 322 | 323 | foreach (QuestObjectiveGraph obj in qog) 324 | { 325 | QuestObjective aux = new QuestObjective 326 | { 327 | keyName = obj.keyName, 328 | maxItems = obj.maxItems, 329 | actualItems = obj.actualItems, 330 | description = obj.description, 331 | hiddenObjective = obj.hiddenObjective, 332 | autoExitOnCompleted = obj.autoExitOnCompleted 333 | }; 334 | 335 | Listaux.Add(aux); 336 | 337 | } 338 | 339 | return Listaux.ToArray(); 340 | } 341 | 342 | 343 | } 344 | } --------------------------------------------------------------------------------