diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 0000000..dadf3a7 --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,25 @@ +{ + "files": [ + "README.md" + ], + "imageSize": 100, + "commit": false, + "commitConvention": "angular", + "contributors": [ + { + "login": "bosaku", + "name": "Richard Bryan Irwin", + "avatar_url": "https://avatars.githubusercontent.com/u/2468343?v=4", + "profile": "https://github.com/bosaku", + "contributions": [ + "doc" + ] + } + ], + "contributorsPerLine": 7, + "skipCi": true, + "repoType": "github", + "repoHost": "https://github.com", + "projectName": "fluid-dialogue", + "projectOwner": "ashblue" +} diff --git a/.github/workflows/nightly-build.yml b/.github/workflows/nightly-build.yml index d9eb239..44f2044 100644 --- a/.github/workflows/nightly-build.yml +++ b/.github/workflows/nightly-build.yml @@ -1,4 +1,6 @@ name: Nightly Build +permissions: + contents: write on: push: branches: diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 0f37935..0a5e9a0 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -1,17 +1,40 @@ -name: CI -on: push +name: Release + +on: + push: + branches: + - main + - master + +permissions: + contents: read + jobs: - test: + release: + name: Release runs-on: ubuntu-latest + permissions: + contents: write + issues: write + pull-requests: write + id-token: write steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + persist-credentials: false + - name: Setup Node.js + uses: actions/setup-node@v3 with: node-version: 16 - - run: HUSKY=0 npm ci - - run: npm run build + - name: Install dependencies + run: HUSKY=0 npm ci && npm run build + - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies + run: npm audit signatures - name: Release env: + GH_TOKEN: ${{ secrets.GH_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: npm run semantic-release + run: npm run semantic-release \ No newline at end of file diff --git a/.husky/commit-msg b/.husky/commit-msg index 988eb59..c160a77 100644 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,4 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -npx --no -- commitlint --edit +npx --no -- commitlint --edit ${1} diff --git a/.oyster.json b/.oyster.json index 870d4e0..5c726a3 100644 --- a/.oyster.json +++ b/.oyster.json @@ -6,7 +6,7 @@ "dialogue", "dialogue system" ], - "oysterVersion": "3.0.0", + "oysterVersion": "3.0.2", "packageName": "com.fluid.dialogue", "packageScope": "com.fluid", "unityVersion": "2019.1", diff --git a/Assets/Examples/BasicConversation/BasicConversation.unity b/Assets/Examples/BasicConversation/BasicConversation.unity index d5a7048..7e19581 100644 --- a/Assets/Examples/BasicConversation/BasicConversation.unity +++ b/Assets/Examples/BasicConversation/BasicConversation.unity @@ -13,7 +13,7 @@ OcclusionCullingSettings: --- !u!104 &2 RenderSettings: m_ObjectHideFlags: 0 - serializedVersion: 9 + serializedVersion: 10 m_Fog: 0 m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} m_FogMode: 3 @@ -38,13 +38,12 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 705507994} - m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 serializedVersion: 12 - m_GIWorkflowMode: 0 m_GISettings: serializedVersion: 2 m_BounceScale: 1 @@ -67,9 +66,6 @@ LightmapSettings: m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 m_TextureCompression: 1 - m_FinalGather: 0 - m_FinalGatherFiltering: 1 - m_FinalGatherRayCount: 256 m_ReflectionCompression: 2 m_MixedBakeMode: 2 m_BakeBackend: 1 @@ -105,7 +101,7 @@ NavMeshSettings: serializedVersion: 2 m_ObjectHideFlags: 0 m_BuildSettings: - serializedVersion: 2 + serializedVersion: 3 agentTypeID: 0 agentRadius: 0.5 agentHeight: 2 @@ -118,7 +114,7 @@ NavMeshSettings: cellSize: 0.16666667 manualTileSize: 0 tileSize: 256 - accuratePlacement: 0 + buildHeightMesh: 0 maxJobWorkers: 0 preserveTilesOutsideBounds: 0 debug: @@ -154,7 +150,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1854390184} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -218,7 +213,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1987331376} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} @@ -289,9 +283,8 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 705507993} m_Enabled: 1 - serializedVersion: 10 + serializedVersion: 11 m_Type: 1 - m_Shape: 0 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 @@ -350,13 +343,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 705507993} + serializedVersion: 2 m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 3, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} --- !u!82 &705507996 AudioSource: @@ -369,6 +362,7 @@ AudioSource: serializedVersion: 4 OutputAudioMixerGroup: {fileID: 0} m_audioClip: {fileID: 8300000, guid: 68d5592cda1d5bd429da0481390f1a6a, type: 3} + m_Resource: {fileID: 8300000, guid: 68d5592cda1d5bd429da0481390f1a6a, type: 3} m_PlayOnAwake: 1 m_Volume: 1 m_Pitch: 1 @@ -454,6 +448,37 @@ AudioSource: m_PreInfinity: 2 m_PostInfinity: 2 m_RotationOrder: 4 +--- !u!1 &894268022 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 894268023} + m_Layer: 0 + m_Name: SetActiveTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &894268023 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 894268022} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &963194225 GameObject: m_ObjectHideFlags: 0 @@ -494,9 +519,17 @@ Camera: m_projectionMatrixMode: 1 m_GateFitMode: 2 m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} - m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 x: 0 @@ -530,13 +563,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 963194225} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 1, z: -10} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &991365858 GameObject: @@ -569,7 +602,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1987331376} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 0, y: 1} @@ -694,6 +726,7 @@ Canvas: m_OverrideSorting: 0 m_OverridePixelPerfect: 0 m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 m_AdditionalShaderChannelsFlag: 0 m_UpdateRectTransformForStandalone: 0 m_SortingLayerID: 0 @@ -715,7 +748,6 @@ RectTransform: - {fileID: 1854390184} - {fileID: 1217128673} m_Father: {fileID: 0} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -739,7 +771,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &1217128673 RectTransform: m_ObjectHideFlags: 0 @@ -753,7 +785,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1037096126} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -828,6 +859,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} m_Name: m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 m_HorizontalAxis: Horizontal m_VerticalAxis: Vertical m_SubmitButton: Submit @@ -857,13 +889,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1578604058} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1854390183 GameObject: @@ -896,7 +928,6 @@ RectTransform: - {fileID: 1987331376} - {fileID: 8172351} m_Father: {fileID: 1037096126} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -933,9 +964,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: dialogue: {fileID: 11400000, guid: 9ee08f7122b445246ba6e627bb67b59a, type: 2} - gameObjectOverrides: - - _variable: {fileID: 11400000, guid: 9f63ecc07e0124045b2c27d0dfb67d38, type: 2} - _gameObject: {fileID: 1217128672} speakerContainer: {fileID: 1854390183} portrait: {fileID: 62754277} lines: {fileID: 991365860} @@ -949,13 +977,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1965669758} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1987331375 GameObject: @@ -990,7 +1018,6 @@ RectTransform: - {fileID: 991365859} - {fileID: 62754276} m_Father: {fileID: 1854390184} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -1066,7 +1093,6 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 1037096126} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} @@ -1111,3 +1137,13 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2077554726} m_CullTransparentMesh: 0 +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1965669760} + - {fileID: 1037096126} + - {fileID: 1578604061} + - {fileID: 963194228} + - {fileID: 705507995} + - {fileID: 894268023} diff --git a/Assets/Examples/BasicConversation/ExampleConversation.asset b/Assets/Examples/BasicConversation/ExampleConversation.asset index a95259b..df9e81d 100644 --- a/Assets/Examples/BasicConversation/ExampleConversation.asset +++ b/Assets/Examples/BasicConversation/ExampleConversation.asset @@ -15,10 +15,10 @@ MonoBehaviour: _uniqueId: 0eacc16b-09da-4963-bd52-a0f523d2eaae rect: serializedVersion: 2 - x: 51260 - y: 50235 + x: 51272 + y: 50247 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: 8469888643324881027} @@ -62,7 +62,7 @@ MonoBehaviour: x: 50972 y: 50397 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -9183305000158909614} @@ -92,7 +92,7 @@ MonoBehaviour: x: 51819 y: 50359 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -3436942782412272395} @@ -136,7 +136,7 @@ MonoBehaviour: x: 51819 y: 50507 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -1807495471838374980} @@ -195,15 +195,15 @@ MonoBehaviour: _uniqueId: 9b8bf58c-0906-4ca9-a722-d589abfb87c3 rect: serializedVersion: 2 - x: 50700 - y: 50156 + x: 50715 + y: 50151 width: 200 - height: 222 + height: 226 nodeTitle: children: [] conditions: [] enterActions: - - {fileID: 6437907874617121193} + - {fileID: 3483931158575894282} exitActions: [] choices: - {fileID: -6868820908879997394} @@ -232,7 +232,7 @@ MonoBehaviour: x: 52270 y: 50209 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -1807495471838374980} @@ -293,7 +293,7 @@ MonoBehaviour: x: 52043 y: 50360 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -1807495471838374980} @@ -322,7 +322,7 @@ MonoBehaviour: x: 50976 y: 50078 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -9183305000158909614} @@ -352,6 +352,31 @@ MonoBehaviour: children: - {fileID: 2969575773676471478} _uniqueId: e9aad9c8-491b-4bb2-8665-6fc4cde30c9b +--- !u!114 &-2030564491796885544 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9bde9a25e35e47d5bc8e840897ea28e6, type: 3} + m_Name: Note + m_EditorClassIdentifier: + _uniqueId: 99fb440c-334f-4912-bd1f-2c97f48b7430 + rect: + serializedVersion: 2 + x: 50464.33 + y: 50344.004 + width: 200 + height: 106 + nodeTitle: + children: [] + conditions: [] + enterActions: [] + exitActions: [] + note: This is a note I left behind --- !u!114 &-1807495471838374980 MonoBehaviour: m_ObjectHideFlags: 0 @@ -410,7 +435,7 @@ MonoBehaviour: x: 52048 y: 50211 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -5972268922082454213} @@ -495,8 +520,9 @@ MonoBehaviour: - {fileID: -7347677369531188231} - {fileID: -1221359623688907011} - {fileID: 3721123120546049034} + - {fileID: -2030564491796885544} root: {fileID: 426936237664981933} - scrollPosition: {x: 50048.676, y: 50061} + scrollPosition: {x: 50859, y: 50000.336} --- !u!114 &373158185418196577 MonoBehaviour: m_ObjectHideFlags: 0 @@ -515,12 +541,14 @@ MonoBehaviour: x: 50467 y: 50163 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -6450186612614065154} conditions: [] - enterActions: [] + enterActions: + - {fileID: 1446717557922608989} + - {fileID: 5168258614544093285} exitActions: [] choices: [] actor: {fileID: 11400000, guid: d6a8e0fd1eb801d4ca00320f6b2e9e8b, type: 2} @@ -541,8 +569,8 @@ MonoBehaviour: _uniqueId: cd458853-4898-4aa5-a8cc-cb7b6dce03b1 rect: serializedVersion: 2 - x: 50050 - y: 50200 + x: 50010 + y: 50197.33 width: 100 height: 57 nodeTitle: @@ -551,6 +579,22 @@ MonoBehaviour: conditions: [] enterActions: [] exitActions: [] +--- !u!114 &1446717557922608989 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: df570d683f114d44abe229f3daba4dbb, type: 3} + m_Name: ActionSetActive + m_EditorClassIdentifier: + _title: ActionSetActive + _uniqueId: 53501ffe-a288-4961-9aa0-af94ccc23a0a + _gameObjectName: Canvas/Image + _setActive: 1 --- !u!114 &2969575773676471478 MonoBehaviour: m_ObjectHideFlags: 0 @@ -569,7 +613,7 @@ MonoBehaviour: x: 50978 y: 50237 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -9183305000158909614} @@ -581,6 +625,22 @@ MonoBehaviour: audio: {fileID: 0} dialogue: My people have suffered more than any other in this war. Please see that the elves are taken care of first. +--- !u!114 &3483931158575894282 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: df570d683f114d44abe229f3daba4dbb, type: 3} + m_Name: ActionSetActive + m_EditorClassIdentifier: + _title: ActionSetActive + _uniqueId: fca3e154-534c-4146-a028-7327d26fd819 + _gameObjectName: Canvas/Image + _setActive: 0 --- !u!114 &3721123120546049034 MonoBehaviour: m_ObjectHideFlags: 0 @@ -599,7 +659,7 @@ MonoBehaviour: x: 51229 y: 50544 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -6450186612614065154} @@ -626,6 +686,22 @@ MonoBehaviour: children: - {fileID: 6784819468853313292} _uniqueId: 98db76ca-7fbd-4fdf-a14a-a0cd471d6c52 +--- !u!114 &5168258614544093285 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: df570d683f114d44abe229f3daba4dbb, type: 3} + m_Name: ActionSetActive + m_EditorClassIdentifier: + _title: ActionSetActive + _uniqueId: e3641bc1-d91c-4918-a371-77add2f2ae9d + _gameObjectName: SetActiveTest + _setActive: 1 --- !u!114 &5315272478784475652 MonoBehaviour: m_ObjectHideFlags: 0 @@ -641,10 +717,10 @@ MonoBehaviour: _uniqueId: 033a0d93-1bef-4d49-991e-693d93735b23 rect: serializedVersion: 2 - x: 51561 - y: 50151 + x: 51564 + y: 50148 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: 8469888643324881027} @@ -704,22 +780,6 @@ MonoBehaviour: children: - {fileID: -1221359623688907011} _uniqueId: b6639707-3558-459c-b2e0-01ebc3bc951b ---- !u!114 &6437907874617121193 -MonoBehaviour: - m_ObjectHideFlags: 1 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: df570d683f114d44abe229f3daba4dbb, type: 3} - m_Name: SetActive - m_EditorClassIdentifier: - _title: SetActive - _uniqueId: b63a213c-b0fa-4526-a78b-55ced115098d - _gameObject: {fileID: 11400000, guid: 9f63ecc07e0124045b2c27d0dfb67d38, type: 2} - _setActive: 0 --- !u!114 &6784819468853313292 MonoBehaviour: m_ObjectHideFlags: 0 @@ -738,7 +798,7 @@ MonoBehaviour: x: 51822 y: 50209 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: -1590606014626862060} @@ -793,10 +853,10 @@ MonoBehaviour: _uniqueId: e89a7a34-92ab-4b6d-be12-57808bba2c05 rect: serializedVersion: 2 - x: 50219 - y: 50170 + x: 50215.664 + y: 50153.332 width: 200 - height: 142 + height: 146 nodeTitle: children: - {fileID: 373158185418196577} diff --git a/Assets/Examples/BasicConversation/ExampleNestedDialogue.asset b/Assets/Examples/BasicConversation/ExampleNestedDialogue.asset index cbd6878..7c10b15 100644 --- a/Assets/Examples/BasicConversation/ExampleNestedDialogue.asset +++ b/Assets/Examples/BasicConversation/ExampleNestedDialogue.asset @@ -18,7 +18,7 @@ MonoBehaviour: x: 50050 y: 50200 width: 100 - height: 55 + height: 57 nodeTitle: children: - {fileID: 3628622021116016526} @@ -61,7 +61,7 @@ MonoBehaviour: x: 50221 y: 50156 width: 200 - height: 133 + height: 146 nodeTitle: children: - {fileID: 6362165008871370358} @@ -70,6 +70,7 @@ MonoBehaviour: exitActions: [] choices: [] actor: {fileID: 11400000, guid: d6a8e0fd1eb801d4ca00320f6b2e9e8b, type: 2} + audio: {fileID: 0} dialogue: When is this all going to end. --- !u!114 &6362165008871370358 MonoBehaviour: @@ -89,7 +90,7 @@ MonoBehaviour: x: 50474 y: 50157 width: 200 - height: 133 + height: 146 nodeTitle: children: [] conditions: [] @@ -97,4 +98,5 @@ MonoBehaviour: exitActions: [] choices: [] actor: {fileID: 11400000, guid: d6a8e0fd1eb801d4ca00320f6b2e9e8b, type: 2} + audio: {fileID: 0} dialogue: Decision after decision, death after death. What's the point anymore? diff --git a/Assets/Examples/BasicConversation/Scripts/ExampleDialoguePlayback.cs b/Assets/Examples/BasicConversation/Scripts/ExampleDialoguePlayback.cs index 31f7f76..4dc0994 100644 --- a/Assets/Examples/BasicConversation/Scripts/ExampleDialoguePlayback.cs +++ b/Assets/Examples/BasicConversation/Scripts/ExampleDialoguePlayback.cs @@ -1,5 +1,4 @@ using System.Collections; -using System.Linq; using CleverCrow.Fluid.Databases; using CleverCrow.Fluid.Dialogues.Graphs; using UnityEngine; @@ -11,8 +10,6 @@ public class ExampleDialoguePlayback : MonoBehaviour { public DialogueGraph dialogue; - public GameObjectOverride[] gameObjectOverrides; - [Header("Graphics")] public GameObject speakerContainer; public Image portrait; @@ -22,7 +19,7 @@ public class ExampleDialoguePlayback : MonoBehaviour { public ChoiceButton choicePrefab; private void Awake () { - var database = new DatabaseInstanceExtended(); + var database = new DatabaseInstance(); _ctrl = new DialogueController(database); // @NOTE If you don't need audio just call _ctrl.Events.Speak((actor, text) => {}) instead @@ -56,7 +53,7 @@ private void Awake () { Debug.Log($"Node Enter: {node.GetType()} - {node.UniqueId}"); }); - _ctrl.Play(dialogue, gameObjectOverrides.ToArray()); + _ctrl.Play(dialogue); } private void ClearChoices () { diff --git a/Assets/Examples/BasicConversation/Variables/VariableImage.asset b/Assets/Examples/BasicConversation/Variables/VariableImage.asset deleted file mode 100644 index ae9460d..0000000 --- a/Assets/Examples/BasicConversation/Variables/VariableImage.asset +++ /dev/null @@ -1,16 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 20133dd9a8004ec68e82b7a342deb715, type: 3} - m_Name: VariableImage - m_EditorClassIdentifier: - key: Initial Background - defaultValue: {fileID: 0} diff --git a/Assets/Examples/BasicConversation/Variables/VariableImage.asset.meta b/Assets/Examples/BasicConversation/Variables/VariableImage.asset.meta deleted file mode 100644 index ab6b55b..0000000 --- a/Assets/Examples/BasicConversation/Variables/VariableImage.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 9f63ecc07e0124045b2c27d0dfb67d38 -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 0 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/com.fluid.dialogue/Editor/CreateDialogueGraph.cs b/Assets/com.fluid.dialogue/Editor/CreateDialogueGraph.cs index 213dc2c..8889435 100644 --- a/Assets/com.fluid.dialogue/Editor/CreateDialogueGraph.cs +++ b/Assets/com.fluid.dialogue/Editor/CreateDialogueGraph.cs @@ -8,7 +8,19 @@ namespace CleverCrow.Fluid.Dialogues.Editors { public static class CreateDialogueGraph { [MenuItem("Assets/Create/Fluid/Dialogue/Graph", priority = 0)] public static void CreateAsset () { - var graph = CreateGraph(); + var path = AssetDatabase.GetAssetPath(Selection.activeObject); + CreateAsset(path, "Dialogue"); + + AssetDatabase.SaveAssets(); + } + + /// + /// Create a dialogue graph asset in a specific folder. + /// Designed to create dialogue graphs through custom Unity editor scripts. + /// You must call AssetDatabase.SaveAssets(); on your own to save the asset properly. + /// + public static DialogueGraph CreateAsset (string folderPath, string graphName) { + var graph = CreateGraph(folderPath, graphName); var root = ScriptableObject.CreateInstance(); root.rect.position = @@ -17,15 +29,15 @@ public static void CreateAsset () { graph.root = root; AssetDatabase.AddObjectToAsset(root, graph); - AssetDatabase.SaveAssets(); + + return graph; } - private static DialogueGraph CreateGraph () { + private static DialogueGraph CreateGraph (string folderPath, string graphName) { var graph = ScriptableObject.CreateInstance(); - graph.name = "Dialogue"; - var path = AssetDatabase.GetAssetPath(Selection.activeObject); + graph.name = graphName; var assetsInPath = AssetDatabase - .FindAssets("t:DialogueGraph", new[] {path}) + .FindAssets("t:DialogueGraph", new[] {folderPath}) .Select(i => { var p = AssetDatabase.GUIDToAssetPath(i); var parts = p.Split('/'); @@ -40,7 +52,7 @@ private static DialogueGraph CreateGraph () { graph.name = $"{name}({count})"; } - AssetDatabase.CreateAsset(graph, $"{path}/{graph.name}.asset"); + AssetDatabase.CreateAsset(graph, $"{folderPath}/{graph.name}.asset"); return graph; } } diff --git a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/NodeDataBaseEditor.cs b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/NodeDataBaseEditor.cs index 1caf551..8216287 100644 --- a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/NodeDataBaseEditor.cs +++ b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/NodeDataBaseEditor.cs @@ -20,7 +20,9 @@ private void OnEnable () { _dialogue = serializedObject.FindProperty("dialogue"); _choices = serializedObject.FindProperty("choices"); - _conditions = new ConditionSortableList(this, "conditions", node, node.conditions); + if (!node.HideInspectorConditions) + _conditions = new ConditionSortableList(this, "conditions", node, node.conditions); + if (!node.HideInspectorActions) { _enterActions = new ActionsSortableList(this, "enterActions", node, node.enterActions); _exitActions = new ActionsSortableList(this, "exitActions", node, node.exitActions); @@ -31,9 +33,13 @@ public override void OnInspectorGUI () { base.OnInspectorGUI(); SpellCheckText(); - _conditions.Update(); + serializedObject.Update(); + + _conditions?.Update(); _enterActions?.Update(); _exitActions?.Update(); + + serializedObject.ApplyModifiedProperties(); } private void SpellCheckText () { diff --git a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ActionsSortableList.cs b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ActionsSortableList.cs index 63f7042..724a1ff 100644 --- a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ActionsSortableList.cs +++ b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ActionsSortableList.cs @@ -11,11 +11,11 @@ public class ActionsSortableList : SortableListBase { private readonly NestedDataCrud _actionCrud; private static TypesToMenu ActionTypes => - _actionTypes ?? (_actionTypes = new TypesToMenu()); + _actionTypes ??= new TypesToMenu(); public ActionsSortableList (Editor editor, string property, NodeDataBase node, List actions) : base(editor, property) { - _soPrinter = new ScriptableObjectListPrinter(_serializedProp); + _soPrinter = new ScriptableObjectListPrinter(editor.serializedObject.FindProperty(property)); _actionCrud = new NestedDataCrud(node, actions, ActionTypes); _list.drawElementCallback = _soPrinter.DrawScriptableObject; diff --git a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ConditionSortableList.cs b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ConditionSortableList.cs index 7c5726e..9142a89 100644 --- a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ConditionSortableList.cs +++ b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/ConditionSortableList.cs @@ -11,11 +11,11 @@ public class ConditionSortableList : SortableListBase { private readonly NestedDataCrud _conditionCrud; private static TypesToMenu ConditionTypes => - _conditionTypes ?? (_conditionTypes = new TypesToMenu()); + _conditionTypes ??= new TypesToMenu(); public ConditionSortableList (Editor editor, string property, NodeDataBase node, List conditions) : base(editor, property) { - _soPrinter = new ScriptableObjectListPrinter(_serializedProp); + _soPrinter = new ScriptableObjectListPrinter(editor.serializedObject.FindProperty(property)); _conditionCrud = new NestedDataCrud(node, conditions, ConditionTypes); _list.drawElementCallback = _soPrinter.DrawScriptableObject; diff --git a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/NestedDataCrud.cs b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/NestedDataCrud.cs index 78802d0..6f6d3ee 100644 --- a/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/NestedDataCrud.cs +++ b/Assets/com.fluid.dialogue/Editor/Inspectors/NodeDataBase/SortableLists/NestedDataCrud.cs @@ -54,6 +54,7 @@ private void CreateItem (Type type) { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); } public void DeleteItem (ReorderableList list) { @@ -70,7 +71,15 @@ public void DeleteItem (ReorderableList list) { Undo.DestroyObjectImmediate(listItem); Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); - AssetDatabase.SaveAssets(); + + // Forcibly refresh the serialized object to prevent an immediate crash + list.serializedProperty.serializedObject.Update(); + + // We must refresh instead of save. Otherwise the re-orderable list will crash due to an editor bug + AssetDatabase.Refresh(); + + // Mark the asset dirty so the changes are saved + EditorUtility.SetDirty(graph); } } } diff --git a/Assets/com.fluid.dialogue/Editor/Inspectors/SortableListBase.cs b/Assets/com.fluid.dialogue/Editor/Inspectors/SortableListBase.cs index b4bc808..f59696a 100644 --- a/Assets/com.fluid.dialogue/Editor/Inspectors/SortableListBase.cs +++ b/Assets/com.fluid.dialogue/Editor/Inspectors/SortableListBase.cs @@ -4,10 +4,8 @@ namespace CleverCrow.Fluid.Dialogues.Editors.Inspectors { public class SortableListBase { - protected readonly Editor _editor; - protected readonly ReorderableList _list; - protected readonly SerializedObject _serializedObject; - protected readonly SerializedProperty _serializedProp; + protected ReorderableList _list; + bool _skipFrame; public SortableListBase (Editor editor, string property) { if (editor == null) { @@ -15,31 +13,25 @@ public SortableListBase (Editor editor, string property) { return; } - _editor = editor; - _serializedProp = _editor.serializedObject.FindProperty(property); - _serializedObject = _editor.serializedObject; - - if (_serializedProp == null) { + var prop = editor.serializedObject.FindProperty(property); + if (prop == null) { Debug.LogErrorFormat("Could not find property {0}", property); return; } _list = new ReorderableList( - _serializedObject, - _serializedProp, + editor.serializedObject, + prop, true, true, true, true); + var title = prop.displayName; _list.drawHeaderCallback = rect => { - EditorGUI.LabelField(rect, _serializedProp.displayName); + EditorGUI.LabelField(rect, title); }; } public void Update () { - _serializedObject.Update(); - - _list?.DoLayoutList(); - - _serializedObject.ApplyModifiedProperties(); + if (_list != null) _list.DoLayoutList(); } } } diff --git a/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/HeaderTextStyle.cs b/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/HeaderTextStyle.cs index a7d90b4..9414abf 100644 --- a/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/HeaderTextStyle.cs +++ b/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/HeaderTextStyle.cs @@ -11,7 +11,7 @@ public GUIStyle Style { if (!_init && EditorStyles.centeredGreyMiniLabel != null) { _init = true; _style = EditorStyles.centeredGreyMiniLabel; - _style.normal.textColor = Color.black; + _style.normal.textColor = ThemeUtility.IsDarkTheme ? Color.white : Color.black; } else if (_style == null) { _style = new GUIStyle(); } diff --git a/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeEditorBase.cs b/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeEditorBase.cs index 7b793da..54841e9 100644 --- a/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeEditorBase.cs +++ b/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeEditorBase.cs @@ -22,7 +22,7 @@ public abstract partial class NodeEditorBase { public NodeDataBase Data { get; private set; } private bool IsSelected { get; set; } - protected virtual Color NodeColor => Color.gray; + protected virtual Color NodeColor { get; } = new Color(0.7f, 0.7f, 0.7f); protected virtual float NodeWidth { get; } = 100; public bool IsMemoryLeak => Data == null; @@ -57,11 +57,7 @@ public void Print () { PrintBody(); } - if (IsSelected) { - GUI.Box(Data.rect, GUIContent.none, _styles.ContainerHighlightStyle.Style); - } - - PrintConnections(); + if (!Data.HideConnections) PrintConnections(); } private void PrintHeader () { @@ -72,7 +68,11 @@ private void PrintHeader () { headerBox.width - PADDING_HEADER, headerBox.height - PADDING_HEADER); + var prev = GUI.backgroundColor; + GUI.backgroundColor = _styles.BodyColor; GUI.Box(headerBox, GUIContent.none, _styles.HeaderStyle.Style); + GUI.backgroundColor = prev; + GUI.Label(headerArea, NodeTitle, _styles.HeaderTextStyle.Style); } @@ -84,7 +84,14 @@ private void PrintBody () { Data.rect.width - PADDING_CONTENT, Data.rect.height - PADDING_CONTENT); - GUI.Box(box, GUIContent.none, _styles.ContentStyle.Style); + var prev = GUI.backgroundColor; + GUI.backgroundColor = _styles.BodyColor; + if (IsSelected) { + GUI.Box(box, GUIContent.none, _styles.ContainerHighlightStyle.Style); + } else { + GUI.Box(box, GUIContent.none, _styles.ContentStyle.Style); + } + GUI.backgroundColor = prev; GUILayout.BeginArea(ContentArea); diff --git a/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeStyles.cs b/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeStyles.cs index c2cad56..89cfa9a 100644 --- a/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeStyles.cs +++ b/Assets/com.fluid.dialogue/Editor/NodeEditors/Base/NodeStyles.cs @@ -6,13 +6,17 @@ public class NodeStyles { public NodeBoxStyle HeaderStyle { get; } public NodeBoxStyle ContainerHighlightStyle { get; } public HeaderTextStyle HeaderTextStyle { get; } + public Color BodyColor { get; } public NodeStyles (Color bodyColor) { - ContentStyle = new NodeBoxStyle(bodyColor, bodyColor); - ContainerHighlightStyle = new NodeBoxStyle(Color.white, Color.clear); + BodyColor = bodyColor; + + ContentStyle = new NodeBoxStyle(BodyColor, BodyColor); + var brightBodyColor = BodyColor * 1.3f; + ContainerHighlightStyle = new NodeBoxStyle(Color.black, brightBodyColor); HeaderTextStyle = new HeaderTextStyle(); - var headerColor = bodyColor * 1.3f; + var headerColor = BodyColor * 1.3f; headerColor.a = 1f; HeaderStyle = new NodeBoxStyle(headerColor, headerColor); } diff --git a/Assets/com.fluid.dialogue/Editor/NodeEditors/Dialogue/ChoiceCollection.cs b/Assets/com.fluid.dialogue/Editor/NodeEditors/Dialogue/ChoiceCollection.cs index 7c3cdc4..cdffceb 100644 --- a/Assets/com.fluid.dialogue/Editor/NodeEditors/Dialogue/ChoiceCollection.cs +++ b/Assets/com.fluid.dialogue/Editor/NodeEditors/Dialogue/ChoiceCollection.cs @@ -8,16 +8,16 @@ namespace CleverCrow.Fluid.Dialogues.Editors.NodeDisplays { public class ChoiceCollection { - private readonly DialogueWindow _window; - private readonly NodeEditorBase _node; - private readonly NodeDataChoiceBase _data; + protected readonly DialogueWindow _window; + protected readonly NodeEditorBase _node; + protected readonly NodeDataChoiceBase _data; - private readonly List _graveyard = new List(); - private readonly List _connections = new List(); - private readonly List _serializedObjects = new List(); - private readonly Stack _callbacks = new Stack(); - private readonly SerializedObject _serializedData; - private readonly SerializedProperty _propChoices; + protected readonly List _graveyard = new List(); + protected readonly List _connections = new List(); + protected readonly List _serializedObjects = new List(); + protected readonly Stack _callbacks = new Stack(); + protected readonly SerializedObject _serializedData; + protected readonly SerializedProperty _propChoices; private bool IsChoiceMemoryLeak => _data.choices.Count != _connections.Count; @@ -35,9 +35,9 @@ public void Add () { Undo.SetCurrentGroupName("Add choice"); Undo.RecordObject(_data, "Add choice"); - var choice = ScriptableObject.CreateInstance(); - choice.name = "Choice"; - choice.Setup(); + var choice = CreateChoice(); + + // Field should be overridable _data.choices.Add(choice); if (FluidDialogueSettings.Current.HideNestedNodeData) { @@ -53,6 +53,14 @@ public void Add () { Undo.CollapseUndoOperations(Undo.GetCurrentGroup()); } + protected virtual ChoiceData CreateChoice () { + var choice = ScriptableObject.CreateInstance(); + choice.name = "Choice"; + choice.Setup(); + + return choice; + } + public void Print (Event e) { _serializedData.Update(); @@ -90,7 +98,7 @@ public NodeDataBase GetParentDataCopy (NodeDataChoiceBase copy) { return copy; } - private void PrintChoices (Event e) { + protected virtual void PrintChoices (Event e) { for (var i = 0; i < _propChoices.arraySize; i++) { GUILayout.BeginHorizontal(); @@ -120,7 +128,7 @@ private void PrintChoices (Event e) { } } - private void ShowEditMenu (ChoiceData choice, int index) { + protected void ShowEditMenu (ChoiceData choice, int index) { GUI.FocusControl(null); var menu = new GenericMenu(); diff --git a/Assets/com.fluid.dialogue/Editor/NodeEditors/NoteEditor.cs b/Assets/com.fluid.dialogue/Editor/NodeEditors/NoteEditor.cs new file mode 100644 index 0000000..1e7f4de --- /dev/null +++ b/Assets/com.fluid.dialogue/Editor/NodeEditors/NoteEditor.cs @@ -0,0 +1,18 @@ +using CleverCrow.Fluid.Dialogues.Nodes; +using UnityEditor; +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Editors.NodeDisplays { + [NodeType(typeof(NodeNoteData))] + public class NoteEditor : NodeEditorBase { + protected override Color NodeColor { get; } = Color.yellow; + protected override float NodeWidth { get; } = 200; + + protected override void OnPrintBody (Event e) { + serializedObject.Update(); + EditorGUILayout.PropertyField(serializedObject.FindProperty("note"), GUIContent.none); + serializedObject.ApplyModifiedProperties(); + } + + } +} diff --git a/Assets/com.fluid.dialogue/Editor/NodeEditors/NoteEditor.cs.meta b/Assets/com.fluid.dialogue/Editor/NodeEditors/NoteEditor.cs.meta new file mode 100644 index 0000000..4714d3f --- /dev/null +++ b/Assets/com.fluid.dialogue/Editor/NodeEditors/NoteEditor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 791aabda2583449390ea07cfba17cf88 +timeCreated: 1713805041 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Editor/Utilities/NodeAssemblies.cs b/Assets/com.fluid.dialogue/Editor/Utilities/NodeAssemblies.cs index 046ac74..d6c2c5d 100644 --- a/Assets/com.fluid.dialogue/Editor/Utilities/NodeAssemblies.cs +++ b/Assets/com.fluid.dialogue/Editor/Utilities/NodeAssemblies.cs @@ -17,33 +17,52 @@ public static class NodeAssemblies { _stringToData ?? (_stringToData = GetStringToData()); private static Dictionary GetDataToDisplay () { - var displayTypes = Assembly - .GetAssembly(typeof(NodeEditorBase)) - .GetTypes() - .Where(t => t.IsSubclassOf(typeof(NodeEditorBase))); - - return displayTypes.ToDictionary( - (k) => { - var attribute = k.GetCustomAttribute(); - return attribute.Type; - }, - (v) => v); + var dict = new Dictionary(); + + // Expensive to get all assemblies, but only way to get data outside the package + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { + foreach (var type in assembly.GetTypes()) { + if (!type.IsSubclassOf(typeof(NodeEditorBase)) || type.IsAbstract) continue; + + var attr = type.GetCustomAttribute(); + if (attr == null) continue; + + dict.Add(attr.Type, type); + } + } + + return dict; + } + + class TypeEntry { + public Type type; + public string path; + public int priority; } private static Dictionary GetStringToData () { - var menuTypes = Assembly - .GetAssembly(typeof(NodeDataBase)) - .GetTypes() - .Where(t => t.IsSubclassOf(typeof(NodeDataBase)) - && t.GetCustomAttribute() != null) - .OrderByDescending(t => t.GetCustomAttribute().Priority); - - return menuTypes.ToDictionary( - (k) => { - var attribute = k.GetCustomAttribute(); - return attribute.Path; - }, - (v) => v); + var list = new List(); + + // Expensive to get all assemblies, but only way to get data outside the package + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { + foreach (var type in assembly.GetTypes()) { + if (!type.IsSubclassOf(typeof(NodeDataBase)) || type.IsAbstract) continue; + var attr = type.GetCustomAttribute(); + if (attr == null) continue; + + list.Add(new TypeEntry { + type = type, + path = attr?.Path ?? type.FullName, + priority = attr?.Priority ?? 0, + }); + } + } + + return list + .OrderByDescending(t => t.priority) + .ToDictionary( + (k) => k.path, + (v) => v.type); } } } diff --git a/Assets/com.fluid.dialogue/Editor/Utilities/NodeBoxStyle.cs b/Assets/com.fluid.dialogue/Editor/Utilities/NodeBoxStyle.cs index 7587c9d..0741765 100644 --- a/Assets/com.fluid.dialogue/Editor/Utilities/NodeBoxStyle.cs +++ b/Assets/com.fluid.dialogue/Editor/Utilities/NodeBoxStyle.cs @@ -4,7 +4,7 @@ namespace CleverCrow.Fluid.Dialogues.Editors { public class NodeBoxStyle { private GUIStyle _style; - private readonly Color32 _borderColor; + private readonly Color _borderColor; private readonly Color _backgroundColor; private Texture2D _texture; @@ -39,9 +39,17 @@ public NodeBoxStyle (Color32 border, Color background) { } private void CreateTexture () { - _texture = Texture2DExtensions.CreateTexture(19, 19, _borderColor); - _texture.SetPixels(1, 1, 17, 17, - Enumerable.Repeat(_backgroundColor, 17 * 17).ToArray()); + _texture = new Texture2D(19, 19, TextureFormat.ARGB32, false); + _texture.filterMode = FilterMode.Point; + + // Create an array for border colors with semi-transparency + Color[] borderColors = Enumerable.Repeat(new Color(_borderColor.r, _borderColor.g, _borderColor.b, 128), 19 * 19).ToArray(); + _texture.SetPixels(borderColors); + + // Set the internal area to a transparent background color + Color[] backgroundColors = Enumerable.Repeat(new Color(_backgroundColor.r, _backgroundColor.g, _backgroundColor.b, 0.5f), 17 * 17).ToArray(); + _texture.SetPixels(1, 1, 17, 17, backgroundColors); + _texture.Apply(); } } diff --git a/Assets/com.fluid.dialogue/Editor/Utilities/Texture2DExtensions.cs b/Assets/com.fluid.dialogue/Editor/Utilities/Texture2DExtensions.cs deleted file mode 100644 index 67fb0ab..0000000 --- a/Assets/com.fluid.dialogue/Editor/Utilities/Texture2DExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Linq; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues.Editors { - public static class Texture2DExtensions { - public static Texture2D CreateTexture (int width, int height, Color color) { - var texture = new Texture2D(width, height, TextureFormat.ARGB32, false); - texture.SetPixels(Enumerable.Repeat(color, width * height).ToArray()); - texture.Apply(); - - return texture; - } - } -} diff --git a/Assets/com.fluid.dialogue/Editor/Utilities/Texture2DExtensions.cs.meta b/Assets/com.fluid.dialogue/Editor/Utilities/Texture2DExtensions.cs.meta deleted file mode 100644 index e91b240..0000000 --- a/Assets/com.fluid.dialogue/Editor/Utilities/Texture2DExtensions.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 614ad7c764924ea09896ebe4d62c851a -timeCreated: 1563150504 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Editor/Utilities/ThemeUtility.cs b/Assets/com.fluid.dialogue/Editor/Utilities/ThemeUtility.cs new file mode 100644 index 0000000..1f90f43 --- /dev/null +++ b/Assets/com.fluid.dialogue/Editor/Utilities/ThemeUtility.cs @@ -0,0 +1,7 @@ +using UnityEditor; + +namespace CleverCrow.Fluid.Dialogues.Editors { + public static class ThemeUtility { + public static bool IsDarkTheme => EditorGUIUtility.isProSkin; + } +} diff --git a/Assets/com.fluid.dialogue/Editor/Utilities/ThemeUtility.cs.meta b/Assets/com.fluid.dialogue/Editor/Utilities/ThemeUtility.cs.meta new file mode 100644 index 0000000..87b37be --- /dev/null +++ b/Assets/com.fluid.dialogue/Editor/Utilities/ThemeUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6046c9915ae2480aac0ed254866ec23f +timeCreated: 1713807421 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/README.md b/Assets/com.fluid.dialogue/README.md index 497d4ee..66069f5 100644 --- a/Assets/com.fluid.dialogue/README.md +++ b/Assets/com.fluid.dialogue/README.md @@ -1,4 +1,7 @@ # Fluid Dialogue + +[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) + A Unity dialogue system that features an easy to use drag and drop graph. ScriptableObject driven with the ability to write custom actions and conditions to create complex dialogue workflows. @@ -25,7 +28,34 @@ First you'll need to [install](#installation) the package with Unity Package Man 1. Create -> Fluid -> Dialogue -> Graph 1. Click "Edit Dialogue" to customize your graph -To create a custom UI to display your graph, you'll need to handle a series of events emitted by the dialogue controller. You can find a full example of this in the [Examples](#examples) folder. +To create a custom UI to display your graph, you'll need to handle a series of events emitted by the dialogue controller. You can find a full example of this in the [Examples](#examples) folder. + +### Playing Dialogue + +To trigger dialogue playback you'll need the following snippet. This will turn your dialogue data into an ongoing conversation with events and variables. + +```csharp +using System.Collections; +using System.Linq; +using CleverCrow.Fluid.Databases; +using CleverCrow.Fluid.Dialogues.Graphs; +using CleverCrow.Fluid.Dialogues; +using UnityEngine; + +public class ExampleDialoguePlayback : MonoBehaviour { + private DialogueController _ctrl; + public DialogueGraph dialogue; + + private void Awake () { + var database = new DatabaseInstanceExtended(); + _ctrl = new DialogueController(database); + _ctrl.Events.Speak.AddListener((actor, text) => { Debug.Log($"{actor.DisplayName}: {text}"); }); + _ctrl.Play(dialogue); + } +} +``` + +For more details see the [`ExampleDialoguePlayback.cs`](https://github.com/ashblue/fluid-dialogue/blob/develop/Assets/Examples/BasicConversation/Scripts/ExampleDialoguePlayback.cs) file for a complete solution on how to manage dialogue in your game. ### Node Types @@ -65,6 +95,18 @@ Globals are mostly the same as local variables. The difference is these will be The GlobalDatabaseManager will be marked DoNotDestroyOnLoad to persist between scene loads. If you want to save it and write the contents to a file run `Save()` to return a string. You can then restore the database simply by calling `Load(returned save string)`. +### Interacting With Runtime GameObject(s) + +To interact with GameObject(s) at runtime use the "SendMessage" action suite. You cannot directly reference GameObjects in the dialogue graph as they are separately serialized. Instead, you can use the "SendMessage" action to send a message to a GameObject at runtime. + +It's strongly recommended when sending messages you use a consistent object name like "DIALOGUE_DIRECTOR" to keep things simple and write your own custom scripts to handle the messages. This will make it easier to maintain and debug your game. + +![send-message.png](docs/send-message.png) + +You can also use the "SetActive" action to toggle GameObjects on and off. This is a great low overhead way to manage dialogue scripts easily. + +If you need to do a lot of heavy lifting with tons of scripting on runtime GameObjects, it's recommended you write your own custom actions to handle this. See the APIs section for more details. + ### Examples To see the entire Fluid Dialogue workflow, it's highly recommended that you download this repo and run projects in the `Assets/Examples` folder. @@ -85,7 +127,7 @@ Fluid Dialogue is used through [Unity's Package Manager](https://docs.unity3d.co } ], "dependencies": { - "com.fluid.dialogue": "1.0.0" + "com.fluid.dialogue": "2.6.0" } } ``` @@ -150,6 +192,139 @@ public class CustomCondition : ConditionDataBase { } ``` +### Resuming Graph Playback + +Graph playback can be resumed from anywhere. This includes nested graphs and the exact node you want to resume from. + +```C# +var ctrl = new DialogueController(...); + +// Play your graph to generate runtime data and advance the graph to a specific node by hand +ctrl.Play(...); + +// Record the required serialized properties +var graph = ctrl.RootGraph; // Finds the root graph that is playing +var parentHierarchy = dialogue.Ctrl.ParentHierarchy; // Gets the IDs of all nodes the nested graphs that are playing +var nextNodeId = ctrl.ActiveDialogue.Pointer.Next()?.UniqueId; // You probably want the next node in your graph, not the current one + +// Create a new graph and resume playback +var newCtrl = new DialogueController(...); + +if (newCtrl.CanPlay(graph, parentHierarchy, nextNodeId)) { + // Failsafe that makes sure our graph playback data is valid + newCtrl.Play(graph, parentHierarchy, nextNodeId); +} else { + // If the data is invalid, just play the graph from the beginning or implement your own fallback logic + newCtrl.Play(graph); +} +``` + +### Custom Nodes (Experimental) + +You can create your own custom nodes with the following API. Please note this is experimental and missing some features. + +First you will need to setup the data layer. This is what will be converted to a nested ScriptableObject on demand for the graph. + +```c# +using System.Linq; +using CleverCrow.Fluid.Dialogues; +using CleverCrow.Fluid.Dialogues.Graphs; +using CleverCrow.Fluid.Dialogues.Nodes; + +namespace YourNamespaceHere { + // Changing this will customize the name in the graph editor creation menu + [CreateMenu("Example")] + public class NodeExampleData : NodeDataBase { + public string myMessage; + + // This is the default name the node will display in the graph editor + protected override string DefaultName => "Example"; + + public override INode GetRuntime (IGraph graphRuntime, IDialogueController dialogue) { + return new NodeCombat( + graphRuntime, + UniqueId, + myMessage, + children.ToList(), + conditions.Select(c => c.GetRuntime(graphRuntime, dialogue)).ToList(), + enterActions.Select(c => c.GetRuntime(graphRuntime, dialogue)).ToList(), + exitActions.Select(c => c.GetRuntime(graphRuntime, dialogue)).ToList() + ); + } + } +} +``` + +Next you will need to create the runtime node. This is what will be generated at runtime for every corresponding data object. + +```c# +using CleverCrow.Fluid.Dialogues; +using CleverCrow.Fluid.Dialogues.Graphs; +using CleverCrow.Fluid.Dialogues.Nodes; + +namespace YourNamespaceHere { + public class NodeExample : NodeBase { + readonly string _myMessage; + + public NodeCombat ( + IGraph runtime, + string uniqueId, + // We've added our new value here. You can pass in whatever values you need. Just add more parameters to the constructor + string myMessage, + System.Collections.Generic.List children, + System.Collections.Generic.List conditions, + System.Collections.Generic.List enterActions, + System.Collections.Generic.List exitActions) + // This is what handles all the messy setup we'd normally have to do + : base(runtime, uniqueId, children, conditions, enterActions, exitActions) { + + _myMessage = myMessage; + } + + // Handles what happens when the node is played + protected override void OnPlay (IDialoguePlayback playback) { + Debug.Log(_myMessage); + } + } +} +``` + +Lastly you will need to create a view layer. This is what will be displayed in the graph editor. Please note this must be nested in a folder called `Editor`. + +```c# +using CleverCrow.Fluid.Dialogues.Editors; +using CleverCrow.Fluid.Dialogues.Editors.NodeDisplays; +using UnityEditor; +using UnityEngine; + +namespace YourNamespaceHere { + [NodeType(typeof(NodeExampleData))] + public class NodeExampleEditor : NodeEditorBase { + protected override Color NodeColor { get; } = new(0.75f, 0.52f, 0f); + protected override float NodeWidth => 200; + + protected override void OnPrintBody (Event e) { + serializedObject.Update(); + + // This creates a dynamic input for the myMessage field + EditorGUILayout.PropertyField(serializedObject.FindProperty("myMessage"), GUIContent.none); + + serializedObject.ApplyModifiedProperties(); + } + } +} +``` + +And that's it. The node will now be available in the graph editor and print our message at runtime. It even supports conditions, actions, and parent/child connections. + +For more details please take a look at the source code for the different node types. This will give you a better idea of how to structure more complex custom nodes with multiple choices and other details. + +## Releases + +Please note that whatever node you're resuming from will play that exact node with enter actions and all previous nodes will not trigger anything. This is a direct reference and does not simulate the graph from the beginning. + +```c# + ## Releases Archives of specific versions and release notes are available on the [releases page](https://github.com/ashblue/fluid-dialogue/releases). @@ -189,3 +364,25 @@ npm run commit --- This project was generated with [Oyster Package Generator](https://github.com/ashblue/oyster-package-generator). + +## Contributors ✨ + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + +
Richard Bryan Irwin
Richard Bryan Irwin

📖
+ + + + + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/ActionSetActive.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/ActionSetActive.cs new file mode 100644 index 0000000..da06b3f --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/ActionSetActive.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { + [CreateMenu("GameObject/Set Active")] + public class ActionSetActive : ActionDataBase { + [SerializeField] + private string _gameObjectName; + + [SerializeField] + private bool _setActive; + + public override void OnStart () { + var target = GameObjectUtilities.FindGameObject(_gameObjectName); + if (target == null) return; + + target.SetActive(_setActive); + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SetActive.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/ActionSetActive.cs.meta similarity index 100% rename from Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SetActive.cs.meta rename to Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/ActionSetActive.cs.meta diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectUtilities.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectUtilities.cs new file mode 100644 index 0000000..46411be --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectUtilities.cs @@ -0,0 +1,50 @@ +using System; +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { + public static class GameObjectUtilities { + public static GameObject FindGameObject (string name) { + var target = GameObject.Find(name); + + if (target == null) { + // Try to find inactive object's parent one level up + // @NOTE Only works if the parent is active for runtime performance reasons + var hasParent = name.Contains("/"); + if (hasParent) { + var parentPath = name.Substring(0, name.LastIndexOf("/", StringComparison.Ordinal)); + var parent = GameObject.Find(parentPath); + + // We know we have a parent, now we need to find the inactive child + if (parent != null) { + var objectName = name.Substring(name.LastIndexOf("/", StringComparison.Ordinal) + 1); + foreach (Transform child in parent.transform) { + if (child.gameObject.name == objectName) { + target = child.gameObject; + break; + } + } + } + } else { + // Look at top level inactive objects only for performance reasons + // @NOTE This only works if the object is in the active scene + var currentScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); + var rootObjects = currentScene.GetRootGameObjects(); + foreach (var obj in rootObjects) { + if (obj.name == name) { + target = obj; + break; + } + } + } + } + + // Give up and fire an error + if (target == null) { + Debug.LogError($"GameObject not found: {name}. SendMessage action will not run. Make sure the object path is correct.\nIf the object is inactive it must be nested under an active object or in the active scene if using async loading."); + return null; + } + + return target; + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectUtilities.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectUtilities.cs.meta new file mode 100644 index 0000000..8e898f7 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectUtilities.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6e8b757d08544840bad085c69282358e +timeCreated: 1713987162 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectWrapper.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectWrapper.cs deleted file mode 100644 index 653e1bf..0000000 --- a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectWrapper.cs +++ /dev/null @@ -1,19 +0,0 @@ -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { - public interface IGameObjectWrapper { - void SetActive (bool value); - } - - public class GameObjectWrapper : IGameObjectWrapper { - private readonly GameObject _go; - - public GameObjectWrapper (GameObject go) { - _go = go; - } - - public void SetActive (bool value) { - _go.SetActive(value); - } - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectWrapper.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectWrapper.cs.meta deleted file mode 100644 index 04178a6..0000000 --- a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/GameObjectWrapper.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 891618fb42204d859f01d21467f8711c -timeCreated: 1585362821 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage.meta new file mode 100644 index 0000000..9be742f --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c00b7a5f10f347e4b239b3c2c9a3fe26 +timeCreated: 1713986894 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessage.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessage.cs new file mode 100644 index 0000000..73cac61 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessage.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { + [CreateMenu("GameObject/Send Message/Default")] + public class ActionSendMessage : ActionDataBase { + [SerializeField] + private string _gameObjectName; + + [SerializeField] + private string _methodName; + + [SerializeField] + SendMessageOptions _options; + + public override void OnStart () { + var target = GameObjectUtilities.FindGameObject(_gameObjectName); + if (target == null) return; + + target.SendMessage(_methodName, _options); + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessage.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessage.cs.meta new file mode 100644 index 0000000..0ede377 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessage.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6a4a5f32d02a4826a57d4ca1997744f8 +timeCreated: 1713986914 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageBool.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageBool.cs new file mode 100644 index 0000000..e7e2561 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageBool.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { + [CreateMenu("GameObject/Send Message/Bool")] + public class ActionSendMessageBool : ActionDataBase { + [SerializeField] + private string _gameObjectName; + + [SerializeField] + private string _methodName; + + [SerializeField] + private bool _value; + + [SerializeField] + SendMessageOptions _options; + + public override void OnStart () { + var target = GameObjectUtilities.FindGameObject(_gameObjectName); + if (target == null) return; + + target.SendMessage(_methodName, _value, _options); + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageBool.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageBool.cs.meta new file mode 100644 index 0000000..4fe8463 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageBool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 90924811a5ed4e2e996a1975ca0d2d5a +timeCreated: 1713987645 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageFloat.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageFloat.cs new file mode 100644 index 0000000..0b00058 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageFloat.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { + [CreateMenu("GameObject/Send Message/Float")] + public class ActionSendMessageFloat : ActionDataBase { + [SerializeField] + private string _gameObjectName; + + [SerializeField] + private string _methodName; + + [SerializeField] + private float _value; + + [SerializeField] + SendMessageOptions _options; + + public override void OnStart () { + var target = GameObjectUtilities.FindGameObject(_gameObjectName); + if (target == null) return; + + target.SendMessage(_methodName, _value, _options); + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageFloat.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageFloat.cs.meta new file mode 100644 index 0000000..1ab9cb5 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageFloat.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d4a70d9e108c496095c540b29ba0e1b2 +timeCreated: 1713987659 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageInt.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageInt.cs new file mode 100644 index 0000000..c069916 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageInt.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { + [CreateMenu("GameObject/Send Message/Int")] + public class ActionSendMessageInt : ActionDataBase { + [SerializeField] + private string _gameObjectName; + + [SerializeField] + private string _methodName; + + [SerializeField] + private int _value; + + [SerializeField] + SendMessageOptions _options; + + public override void OnStart () { + var target = GameObjectUtilities.FindGameObject(_gameObjectName); + if (target == null) return; + + target.SendMessage(_methodName, _value, _options); + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageInt.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageInt.cs.meta new file mode 100644 index 0000000..8c0cec6 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageInt.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 946e9b68658d4b7ebcee2d476837a535 +timeCreated: 1713987458 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageString.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageString.cs new file mode 100644 index 0000000..e17bec6 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageString.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { + [CreateMenu("GameObject/Send Message/String")] + public class ActionSendMessageString : ActionDataBase { + [SerializeField] + private string _gameObjectName; + + [SerializeField] + private string _methodName; + + [SerializeField] + private string _value; + + [SerializeField] + SendMessageOptions _options; + + public override void OnStart () { + var target = GameObjectUtilities.FindGameObject(_gameObjectName); + if (target == null) return; + + target.SendMessage(_methodName, _value, _options); + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageString.cs.meta b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageString.cs.meta new file mode 100644 index 0000000..12429ec --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SendMessage/ActionSendMessageString.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 41da87cb052d42618b329e4c4acb77dd +timeCreated: 1713987389 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SetActive.cs b/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SetActive.cs deleted file mode 100644 index 9cf64b0..0000000 --- a/Assets/com.fluid.dialogue/Runtime/Actions/Libraries/GameObjects/Actions/SetActive.cs +++ /dev/null @@ -1,39 +0,0 @@ -using CleverCrow.Fluid.Dialogues.GameObjectVariables; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { - [CreateMenu("GameObject/Set Active")] - public class SetActive : ActionDataBase { - private IDialogueController _dialogue; - - [SerializeField] - private KeyValueDefinitionGameObject _gameObject = null; - - [SerializeField] - private bool _setActive = false; - - public override void OnInit (IDialogueController dialogue) { - _dialogue = dialogue; - } - - public override void OnStart () { - var go = _dialogue.LocalDatabaseExtended.GameObjects.Get(_gameObject.key, _gameObject.defaultValue); - var goWrapper = new GameObjectWrapper(go); - - var setActive = new SetActiveInternal(goWrapper); - setActive.SetValue(_setActive); - } - } - - public class SetActiveInternal { - private readonly IGameObjectWrapper _go; - - public SetActiveInternal (IGameObjectWrapper go) { - _go = go; - } - - public void SetValue (bool value) { - _go.SetActive(value); - } - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/Conditions/ConditionRuntime.cs b/Assets/com.fluid.dialogue/Runtime/Conditions/ConditionRuntime.cs index 5ca44cb..dacf013 100644 --- a/Assets/com.fluid.dialogue/Runtime/Conditions/ConditionRuntime.cs +++ b/Assets/com.fluid.dialogue/Runtime/Conditions/ConditionRuntime.cs @@ -13,6 +13,7 @@ public class ConditionRuntime : ICondition { private bool _initTriggered; public string UniqueId { get; } + public IConditionData Data => _data; public ConditionRuntime (IDialogueController dialogueController, string uniqueId, IConditionData data) { _data = data; diff --git a/Assets/com.fluid.dialogue/Runtime/Conditions/ICondition.cs b/Assets/com.fluid.dialogue/Runtime/Conditions/ICondition.cs index 23b8b27..30034b8 100644 --- a/Assets/com.fluid.dialogue/Runtime/Conditions/ICondition.cs +++ b/Assets/com.fluid.dialogue/Runtime/Conditions/ICondition.cs @@ -2,6 +2,8 @@ namespace CleverCrow.Fluid.Dialogues.Conditions { public interface ICondition : IUniqueId { + IConditionData Data { get; } + bool GetIsValid (INode parent); } } diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/DatabaseInstanceExtended.cs b/Assets/com.fluid.dialogue/Runtime/DialogueController/DatabaseInstanceExtended.cs deleted file mode 100644 index dc6db80..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/DatabaseInstanceExtended.cs +++ /dev/null @@ -1,12 +0,0 @@ -using CleverCrow.Fluid.Databases; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues { - public class DatabaseInstanceExtended : DatabaseInstance, IDatabaseInstanceExtended { - public IKeyValueData GameObjects { get; } = new KeyValueDataGameObject(); - - public void ClearGameObjects () { - GameObjects.Clear(); - } - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/DatabaseInstanceExtended.cs.meta b/Assets/com.fluid.dialogue/Runtime/DialogueController/DatabaseInstanceExtended.cs.meta deleted file mode 100644 index 086e624..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/DatabaseInstanceExtended.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 8de5f62f9622487784009567eed71fc3 -timeCreated: 1585362377 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/DialogueController.cs b/Assets/com.fluid.dialogue/Runtime/DialogueController/DialogueController.cs index a8f17e3..3e1bd22 100644 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/DialogueController.cs +++ b/Assets/com.fluid.dialogue/Runtime/DialogueController/DialogueController.cs @@ -1,43 +1,85 @@ using System; using System.Collections.Generic; +using System.Linq; using CleverCrow.Fluid.Databases; using CleverCrow.Fluid.Dialogues.Choices; using CleverCrow.Fluid.Dialogues.Graphs; using CleverCrow.Fluid.Dialogues.Nodes; +using CleverCrow.Fluid.Dialogues.Nodes.PlayGraph; using UnityEngine; namespace CleverCrow.Fluid.Dialogues { public interface IDialogueController { IDatabaseInstance LocalDatabase { get; } - IDatabaseInstanceExtended LocalDatabaseExtended { get; } void PlayChild (IGraphData graph); } public class DialogueController : IDialogueController { private readonly Stack _activeDialogue = new Stack(); + private readonly List _parentHierarchy = new(); - [Obsolete("Use LocalDatabaseExtended instead")] public IDatabaseInstance LocalDatabase { get; } - public IDatabaseInstanceExtended LocalDatabaseExtended { get; } public IDialogueEvents Events { get; } = new DialogueEvents(); + + /// + /// Playback runtime that corresponds to the current graph definition (may be nested) + /// public IDialoguePlayback ActiveDialogue => _activeDialogue.Count > 0 ? _activeDialogue.Peek() : null; - [Obsolete("Use DatabaseInstanceExtended instead. Old databases do not support GameObjects")] + /// + /// Return the root of the currently playing dialogue + /// + public IGraphData RootGraph => _activeDialogue.Count > 0 ? _activeDialogue.ToArray().Last().Graph.Data : null; + + /// + /// Keeps track of the IDs of all nested graph node containers currently playing in order. Important for restoring nested + /// dialogue graphs that are currently playing from serialized data. + /// + public IReadOnlyList ParentHierarchy => _parentHierarchy; + + public DialogueController (IDatabaseInstance localDatabase) { LocalDatabase = localDatabase; } - public DialogueController (IDatabaseInstanceExtended localDatabase) { -#pragma warning disable 618 - LocalDatabase = localDatabase; -#pragma warning restore 618 + public void Play (IDialoguePlayback playback) { + PlaybackSetup(playback); + playback.Play(); + } + + // @NOTE gameObjectOverrides will be deprecated. It can easily be replaced with a send message system that looks up the target GameObject by string. This is a lot to maintain and messy + public void Play (IGraphData graph) { + var runtime = new GraphRuntime(this, graph); + Play(new DialoguePlayback(runtime, this, new DialogueEvents())); + } - LocalDatabaseExtended = localDatabase; + // @TODO Needs some tests + public void Play (IGraphData graph, IReadOnlyList parentHierarchy, string nodeId) { + var runtime = new GraphRuntime(this, graph); + + // Setup the root graph with all proper hooks + var origin = new DialoguePlayback(runtime, this, new DialogueEvents()); + PlaybackSetup(origin); + + var playback = origin; + foreach (var id in parentHierarchy) { + // Set and get the pointer + playback.SetPointer(id); + if (playback.Pointer is not NodePlayGraph node) { + throw new InvalidOperationException($"Parent hierarchy ID {id} does not contain a nested graph"); + } + + // Add the child playback runtime + AddChild(node.Graph as DialogueGraph); + playback = _activeDialogue.Peek() as DialoguePlayback; + } + + playback.SetPointerAndPlay(nodeId); } - public void Play (IDialoguePlayback playback, IGameObjectOverride[] gameObjectOverrides = null) { - SetupDatabases(gameObjectOverrides); + void PlaybackSetup (IDialoguePlayback playback) { + SetupDatabases(); Stop(); @@ -49,29 +91,33 @@ public void Play (IDialoguePlayback playback, IGameObjectOverride[] gameObjectOv playback.Events.End.AddListener(TriggerEnd); _activeDialogue.Push(playback); + } + + private void SetupDatabases () { + LocalDatabase.Clear(); + } + + public void PlayChild (IDialoguePlayback playback) { + SetupChild(playback); playback.Play(); } - public void Play (IGraphData graph, IGameObjectOverride[] gameObjectOverrides = null) { + public void PlayChild (IGraphData graph) { + // @TODO Test this + _parentHierarchy.Add(_activeDialogue.Peek().Pointer.UniqueId); + var runtime = new GraphRuntime(this, graph); - Play(new DialoguePlayback(runtime, this, new DialogueEvents()), gameObjectOverrides); + PlayChild(new DialoguePlayback(runtime, this, new DialogueEvents())); } - private void SetupDatabases (IGameObjectOverride[] gameObjectOverrides) { -#pragma warning disable 618 - LocalDatabase.Clear(); -#pragma warning restore 618 - - if (LocalDatabaseExtended == null) return; - LocalDatabaseExtended.ClearGameObjects(); + void AddChild (IGraphData graph) { + _parentHierarchy.Add(_activeDialogue.Peek().Pointer.UniqueId); - if (gameObjectOverrides == null) return; - foreach (var goOverride in gameObjectOverrides) { - LocalDatabaseExtended.GameObjects.Set(goOverride.Definition.Key, goOverride.Value); - } + var runtime = new GraphRuntime(this, graph); + SetupChild(new DialoguePlayback(runtime, this, new DialogueEvents())); } - public void PlayChild (IDialoguePlayback playback) { + void SetupChild (IDialoguePlayback playback) { if (ActiveDialogue == null) { throw new InvalidOperationException("Cannot trigger child dialogue, nothing is playing"); } @@ -87,12 +133,6 @@ public void PlayChild (IDialoguePlayback playback) { playback.Events.NodeEnter.AddListener(TriggerEnterNode); _activeDialogue.Push(playback); - playback.Play(); - } - - public void PlayChild (IGraphData graph) { - var runtime = new GraphRuntime(this, graph); - PlayChild(new DialoguePlayback(runtime, this, new DialogueEvents())); } private void TriggerBegin () { @@ -138,6 +178,40 @@ public void Stop () { } _activeDialogue.Clear(); + // @TODO Test this + _parentHierarchy.Clear(); + } + + // @TODO Write a test for this if possible, might not be easy + /// + /// Verifies a nested graph can be played. Not the most runtime friendly operation so use sparingly + /// + public bool CanPlay (IGraphData graph, List parentHierarchy, string nodeId) { + // Use the parent hierarchy to find the nested graph + var nestedGraph = graph; + foreach (var id in parentHierarchy) { + var node = GetNode(nestedGraph, id); + if (node == null) return false; + + if (node is NodePlayGraphData playGraph) { + nestedGraph = playGraph.dialogueGraph; + } else { + return false; + } + } + + // Check if the node exists in the nested graph + return GetNode(nestedGraph, nodeId) != null; + } + + INodeData GetNode (IGraphData graph, string id) { + foreach (var node in graph.Nodes) { + if (node.UniqueId == id) { + return node; + } + } + + return null; } } } diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/GameObjectOverride.cs b/Assets/com.fluid.dialogue/Runtime/DialogueController/GameObjectOverride.cs deleted file mode 100644 index 6bb73fe..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/GameObjectOverride.cs +++ /dev/null @@ -1,17 +0,0 @@ -using CleverCrow.Fluid.Databases; -using CleverCrow.Fluid.Dialogues.GameObjectVariables; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues { - [System.Serializable] - public class GameObjectOverride : IGameObjectOverride { - [SerializeField] - private KeyValueDefinitionGameObject _variable = null; - - [SerializeField] - private GameObject _gameObject = null; - - public IKeyValueDefinition Definition => _variable; - public GameObject Value => _gameObject; - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/GameObjectOverride.cs.meta b/Assets/com.fluid.dialogue/Runtime/DialogueController/GameObjectOverride.cs.meta deleted file mode 100644 index 6456455..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/GameObjectOverride.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 50d49f2682d544c8a0741da2103ba539 -timeCreated: 1585365476 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/IDatabaseInstanceExtended.cs b/Assets/com.fluid.dialogue/Runtime/DialogueController/IDatabaseInstanceExtended.cs deleted file mode 100644 index b381591..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/IDatabaseInstanceExtended.cs +++ /dev/null @@ -1,10 +0,0 @@ -using CleverCrow.Fluid.Databases; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues { - public interface IDatabaseInstanceExtended : IDatabaseInstance { - IKeyValueData GameObjects { get; } - - void ClearGameObjects (); - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/IDatabaseInstanceExtended.cs.meta b/Assets/com.fluid.dialogue/Runtime/DialogueController/IDatabaseInstanceExtended.cs.meta deleted file mode 100644 index d30a76e..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/IDatabaseInstanceExtended.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: fd66fca7c2984521ab5bb850cd37ed17 -timeCreated: 1585362264 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/IGameObjectOverride.cs b/Assets/com.fluid.dialogue/Runtime/DialogueController/IGameObjectOverride.cs deleted file mode 100644 index f37cdcc..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/IGameObjectOverride.cs +++ /dev/null @@ -1,9 +0,0 @@ -using CleverCrow.Fluid.Databases; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues { - public interface IGameObjectOverride { - IKeyValueDefinition Definition { get; } - GameObject Value { get; } - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/IGameObjectOverride.cs.meta b/Assets/com.fluid.dialogue/Runtime/DialogueController/IGameObjectOverride.cs.meta deleted file mode 100644 index 0092520..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/IGameObjectOverride.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: f4879d31907d42279d9d04c232da2426 -timeCreated: 1585364751 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/KeyValueDataGameObject.cs b/Assets/com.fluid.dialogue/Runtime/DialogueController/KeyValueDataGameObject.cs deleted file mode 100644 index c2967df..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/KeyValueDataGameObject.cs +++ /dev/null @@ -1,14 +0,0 @@ -using CleverCrow.Fluid.Databases; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues { - public class KeyValueDataGameObject : KeyValueDataBase { - public override string Save () { - throw new System.NotImplementedException(); - } - - public override void Load (string save) { - throw new System.NotImplementedException(); - } - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/DialogueController/KeyValueDataGameObject.cs.meta b/Assets/com.fluid.dialogue/Runtime/DialogueController/KeyValueDataGameObject.cs.meta deleted file mode 100644 index 3358a93..0000000 --- a/Assets/com.fluid.dialogue/Runtime/DialogueController/KeyValueDataGameObject.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: cf38a63e6712461ea9f2f70a8af53aca -timeCreated: 1585362444 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/DialoguePlayback.cs b/Assets/com.fluid.dialogue/Runtime/DialoguePlayback.cs index 392cc71..9f43977 100644 --- a/Assets/com.fluid.dialogue/Runtime/DialoguePlayback.cs +++ b/Assets/com.fluid.dialogue/Runtime/DialoguePlayback.cs @@ -2,12 +2,20 @@ using CleverCrow.Fluid.Dialogues.Actions; using CleverCrow.Fluid.Dialogues.Graphs; using CleverCrow.Fluid.Dialogues.Nodes; +using UnityEngine; namespace CleverCrow.Fluid.Dialogues { public interface IDialoguePlayback { IDialogueEvents Events { get; } IDialogueController ParentCtrl { get; } + IGraph Graph { get; } + + /// + /// Current node data being used for the runtime + /// + INode Pointer { get; } + void Next (); void Play (); void Tick (); @@ -23,6 +31,7 @@ public class DialoguePlayback : IDialoguePlayback { public IDialogueEvents Events { get;} public IDialogueController ParentCtrl { get; } public INode Pointer { get; private set; } + public IGraph Graph => _graph; public DialoguePlayback (IGraph graph, IDialogueController ctrl, IDialogueEvents events) { _graph = graph; @@ -119,5 +128,22 @@ public void SelectChoice (int index) { Pointer = choice.GetValidChildNode(); Next(current, Pointer); } + + public void SetPointer (string id) { + _playing = true; + Pointer = _graph.GetNodeByDataId(id); + + if (Pointer == null) { + Debug.LogError($"Pointer not found when maually setting pointer: {id}. This graph will instantly end when run"); + } + } + + // Allows playing the pointer from a nested location without crashing + public void SetPointerAndPlay (string id) { + SetPointer(id); + Events.Begin.Invoke(); + + Next(null, Pointer); + } } } diff --git a/Assets/com.fluid.dialogue/Runtime/GameObjectVariables.meta b/Assets/com.fluid.dialogue/Runtime/GameObjectVariables.meta deleted file mode 100644 index b5bc2a3..0000000 --- a/Assets/com.fluid.dialogue/Runtime/GameObjectVariables.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: dbe8d873b08c45b0bfae4ddde220562c -timeCreated: 1585278789 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/GameObjectVariables/KeyValueDefinitionGameObject.cs b/Assets/com.fluid.dialogue/Runtime/GameObjectVariables/KeyValueDefinitionGameObject.cs deleted file mode 100644 index dc450ea..0000000 --- a/Assets/com.fluid.dialogue/Runtime/GameObjectVariables/KeyValueDefinitionGameObject.cs +++ /dev/null @@ -1,11 +0,0 @@ -using CleverCrow.Fluid.Databases; -using UnityEngine; - -namespace CleverCrow.Fluid.Dialogues.GameObjectVariables { - [CreateAssetMenu( - menuName = CREATE_PATH + "/Key Value GameObject", - fileName = "KeyValueGameObject" - )] - public class KeyValueDefinitionGameObject : KeyValueDefinitionBase { - } -} diff --git a/Assets/com.fluid.dialogue/Runtime/GameObjectVariables/KeyValueDefinitionGameObject.cs.meta b/Assets/com.fluid.dialogue/Runtime/GameObjectVariables/KeyValueDefinitionGameObject.cs.meta deleted file mode 100644 index c8b69d6..0000000 --- a/Assets/com.fluid.dialogue/Runtime/GameObjectVariables/KeyValueDefinitionGameObject.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 20133dd9a8004ec68e82b7a342deb715 -timeCreated: 1585278810 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Graphs/GraphRuntime.cs b/Assets/com.fluid.dialogue/Runtime/Graphs/GraphRuntime.cs index d9d5758..7d09aee 100644 --- a/Assets/com.fluid.dialogue/Runtime/Graphs/GraphRuntime.cs +++ b/Assets/com.fluid.dialogue/Runtime/Graphs/GraphRuntime.cs @@ -7,6 +7,7 @@ public class GraphRuntime : IGraph { private readonly Dictionary _dataToRuntime; public INode Root { get; } + public IGraphData Data { get; } public GraphRuntime (IDialogueController dialogue, IGraphData data) { _dataToRuntime = data.Nodes.ToDictionary( @@ -14,10 +15,15 @@ public GraphRuntime (IDialogueController dialogue, IGraphData data) { v => v.GetRuntime(this, dialogue)); Root = GetCopy(data.Root); + Data = data; } public INode GetCopy (INodeData original) { return _dataToRuntime[original]; } + + public INode GetNodeByDataId (string id) { + return _dataToRuntime.FirstOrDefault(n => n.Key.UniqueId == id).Value; + } } } diff --git a/Assets/com.fluid.dialogue/Runtime/Graphs/IGraph.cs b/Assets/com.fluid.dialogue/Runtime/Graphs/IGraph.cs index 2556179..e3ac4d9 100644 --- a/Assets/com.fluid.dialogue/Runtime/Graphs/IGraph.cs +++ b/Assets/com.fluid.dialogue/Runtime/Graphs/IGraph.cs @@ -3,6 +3,9 @@ namespace CleverCrow.Fluid.Dialogues.Graphs { public interface IGraph { INode Root { get; } + IGraphData Data { get; } + INode GetCopy (INodeData nodeData); + INode GetNodeByDataId (string id); } } diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/ChoiceHub/NodeChoiceHub.cs b/Assets/com.fluid.dialogue/Runtime/Nodes/ChoiceHub/NodeChoiceHub.cs index d106a33..ddd1d69 100644 --- a/Assets/com.fluid.dialogue/Runtime/Nodes/ChoiceHub/NodeChoiceHub.cs +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/ChoiceHub/NodeChoiceHub.cs @@ -12,6 +12,7 @@ public class NodeChoiceHub : INode { public string UniqueId { get; } public List EnterActions { get; } public List ExitActions { get; } + public IReadOnlyList Conditions => _conditions; public virtual bool IsValid => _conditions.Find(c => !c.GetIsValid(this)) == null; diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/INode.cs b/Assets/com.fluid.dialogue/Runtime/Nodes/INode.cs index 0600007..a0af434 100644 --- a/Assets/com.fluid.dialogue/Runtime/Nodes/INode.cs +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/INode.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using CleverCrow.Fluid.Dialogues.Actions; using CleverCrow.Fluid.Dialogues.Choices; +using CleverCrow.Fluid.Dialogues.Conditions; namespace CleverCrow.Fluid.Dialogues.Nodes { public interface INode : IUniqueId { @@ -8,7 +9,11 @@ public interface INode : IUniqueId { List ExitActions { get; } bool IsValid { get; } List HubChoices { get; } + IReadOnlyList Conditions { get; } + /// + /// Returns the first valid child node + /// INode Next (); void Play (IDialoguePlayback playback); IChoice GetChoice (int index); diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/NodeBase.cs b/Assets/com.fluid.dialogue/Runtime/Nodes/NodeBase.cs index 8378acf..d4a5434 100644 --- a/Assets/com.fluid.dialogue/Runtime/Nodes/NodeBase.cs +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/NodeBase.cs @@ -18,6 +18,7 @@ public abstract class NodeBase : INode { _conditions.Find(c => !c.GetIsValid(this)) == null; public List HubChoices { get; } public string UniqueId { get; } + public IReadOnlyList Conditions => _conditions; protected List Children => _childrenRuntimeCache ?? diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/NodeDataBase.cs b/Assets/com.fluid.dialogue/Runtime/Nodes/NodeDataBase.cs index 514e836..7e951eb 100644 --- a/Assets/com.fluid.dialogue/Runtime/Nodes/NodeDataBase.cs +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/NodeDataBase.cs @@ -47,7 +47,9 @@ public abstract class NodeDataBase : ScriptableObject, INodeData { public string UniqueId => _uniqueId; protected virtual string DefaultName { get; } = "Untitled"; public IReadOnlyList Children => children; + public virtual bool HideConnections => false; public virtual bool HideInspectorActions => false; + public virtual bool HideInspectorConditions => false; public virtual string Text => ""; public virtual List Choices { get; } = new List(); diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/Note.meta b/Assets/com.fluid.dialogue/Runtime/Nodes/Note.meta new file mode 100644 index 0000000..7900a06 --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/Note.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8f9d607bf1aa4cdaa79a340358db94ea +timeCreated: 1713803227 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/Note/NodeNoteData.cs b/Assets/com.fluid.dialogue/Runtime/Nodes/Note/NodeNoteData.cs new file mode 100644 index 0000000..3b86ccc --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/Note/NodeNoteData.cs @@ -0,0 +1,25 @@ +using CleverCrow.Fluid.Dialogues.Graphs; +using UnityEngine; + +namespace CleverCrow.Fluid.Dialogues.Nodes { + // @TODO This should inherit a simpler NodeDataBase that doesn't have children, conditions, enterActions, exitActions, ect. + // This can be done by breaking down the base NodeDataBase into a separate NodeDataHierarchyBase class that inherits from a minimal NodeDataBase + // The editor display will also need to be adjusted accordingly + [CreateMenu("Note")] + public class NodeNoteData : NodeDataBase { + [TextArea] + public string note; + + protected override string DefaultName => "Note"; + public override string Text => note; + + public override bool HideConnections => true; + public override bool HideInspectorActions => true; + public override bool HideInspectorConditions => true; + + public override INode GetRuntime (IGraph graphRuntime, IDialogueController controller) { + // There is no runtime, this is an editor only note + return null; + } + } +} diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/Note/NodeNoteData.cs.meta b/Assets/com.fluid.dialogue/Runtime/Nodes/Note/NodeNoteData.cs.meta new file mode 100644 index 0000000..d3b9fca --- /dev/null +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/Note/NodeNoteData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9bde9a25e35e47d5bc8e840897ea28e6 +timeCreated: 1713803266 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Runtime/Nodes/PlayGraph/NodePlayGraph.cs b/Assets/com.fluid.dialogue/Runtime/Nodes/PlayGraph/NodePlayGraph.cs index 160bcc4..5ff82af 100644 --- a/Assets/com.fluid.dialogue/Runtime/Nodes/PlayGraph/NodePlayGraph.cs +++ b/Assets/com.fluid.dialogue/Runtime/Nodes/PlayGraph/NodePlayGraph.cs @@ -7,6 +7,8 @@ namespace CleverCrow.Fluid.Dialogues.Nodes.PlayGraph { public class NodePlayGraph : NodeBase { private readonly IGraphData _graph; + public IGraphData Graph => _graph; + public NodePlayGraph ( IGraph runtime, string uniqueId, diff --git a/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects.meta b/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects.meta deleted file mode 100644 index e1ecc5a..0000000 --- a/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 91995719d4d1456385367736d65dd2ce -timeCreated: 1585279417 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects/SetActiveTest.cs b/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects/SetActiveTest.cs deleted file mode 100644 index 67687ba..0000000 --- a/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects/SetActiveTest.cs +++ /dev/null @@ -1,28 +0,0 @@ -using NSubstitute; -using NUnit.Framework; - -namespace CleverCrow.Fluid.Dialogues.Actions.GameObjects { - public class SetActiveTest { - public class SetValueMethod { - [Test] - public void It_should_set_the_GameObject_active_to_true () { - var go = Substitute.For(); - - var setActive = new SetActiveInternal(go); - setActive.SetValue(true); - - go.Received(1).SetActive(true); - } - - [Test] - public void It_should_set_the_GameObject_active_to_false () { - var go = Substitute.For(); - - var setActive = new SetActiveInternal(go); - setActive.SetValue(false); - - go.Received(1).SetActive(false); - } - } - } -} diff --git a/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects/SetActiveTest.cs.meta b/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects/SetActiveTest.cs.meta deleted file mode 100644 index 5c27f17..0000000 --- a/Assets/com.fluid.dialogue/Tests/Editor/Actions/GameObjects/SetActiveTest.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: d01f8223ea034834b3d327579418d3cb -timeCreated: 1585279428 \ No newline at end of file diff --git a/Assets/com.fluid.dialogue/Tests/Editor/DialogueControllerTest.cs b/Assets/com.fluid.dialogue/Tests/Editor/DialogueControllerTest.cs index 90cd8be..003ffd7 100644 --- a/Assets/com.fluid.dialogue/Tests/Editor/DialogueControllerTest.cs +++ b/Assets/com.fluid.dialogue/Tests/Editor/DialogueControllerTest.cs @@ -3,52 +3,9 @@ using CleverCrow.Fluid.Dialogues.Builders; using NSubstitute; using NUnit.Framework; -using UnityEngine; -using Object = System.Object; namespace CleverCrow.Fluid.Dialogues { public class DialogueControllerTest { - public class WithExtendedDatabase { - public class PlayMethod : DialogueControllerTest { - private GameObject _gameObject; - - [Test] - public void It_should_call_clear_database_GameObjects () { - var database = Substitute.For(); - var ctrl = new DialogueController(database); - var playback = Substitute.For(); - - ctrl.Play(playback); - - database.Received(1).ClearGameObjects(); - } - - [Test] - public void It_allows_overriding_GameObjects_by_definition () { - var database = Substitute.For(); - var ctrl = new DialogueController(database); - var playback = Substitute.For(); - - var definition = Substitute.For>(); - definition.Key.Returns("My GameObject"); - _gameObject = new GameObject("test"); - - var gameObjectOverride = Substitute.For(); - gameObjectOverride.Definition.Returns(definition); - gameObjectOverride.Value.Returns(_gameObject); - - ctrl.Play(playback, new [] { gameObjectOverride }); - - database.GameObjects.Received(1).Set(definition.Key, _gameObject); - } - - [TearDown] - public void AfterEach () { - if (_gameObject != null) UnityEngine.Object.DestroyImmediate(_gameObject); - } - } - } - public class WithLocalDatabase { private DialogueController _ctrl; private IDialoguePlayback _playback; @@ -113,6 +70,18 @@ public void It_should_bind_dialogue_speak_events () { Assert.IsTrue(speakResult); } + [Test] + public void It_should_bind_dialogue_speak_with_audio_events () { + var speakResult = false; + _ctrl.Events.SpeakWithAudio.AddListener((x, y, _) => speakResult = true); + var playback = new DialoguePlayback(A.Graph.Build(), null, new DialogueEvents()); + + _ctrl.Play(playback); + playback.Events.SpeakWithAudio.Invoke(null, null, null); + + Assert.IsTrue(speakResult); + } + [Test] public void It_should_bind_dialogue_choice_events () { var choiceResult = false; @@ -170,6 +139,18 @@ public void It_should_bind_the_speak_event () { Assert.IsTrue(speakResult); } + [Test] + public void It_should_bind_the_speak_with_audio_event () { + var speakResult = false; + _ctrl.Events.SpeakWithAudio.AddListener((x, y, _) => speakResult = true); + var playback = new DialoguePlayback(A.Graph.Build(), null, new DialogueEvents()); + + _ctrl.PlayChild(playback); + playback.Events.SpeakWithAudio.Invoke(null, null, null); + + Assert.IsTrue(speakResult); + } + [Test] public void It_should_bind_the_choice_event () { var choiceResult = false; diff --git a/Assets/com.fluid.dialogue/Tests/Editor/DialoguePlaybackTest.cs b/Assets/com.fluid.dialogue/Tests/Editor/DialoguePlaybackTest.cs index b095c21..7eccf04 100644 --- a/Assets/com.fluid.dialogue/Tests/Editor/DialoguePlaybackTest.cs +++ b/Assets/com.fluid.dialogue/Tests/Editor/DialoguePlaybackTest.cs @@ -47,6 +47,21 @@ public void It_should_trigger_a_speak_event_with_the_root_child_dialogue () { _playback.Events.Speak.ReceivedWithAnyArgs(1).Invoke(null, null); } + [Test] + public void It_should_trigger_a_speak_with_audio_event_with_the_root_child_dialogue () { + var node = A.Node.Build(); + node.Play(Arg.Do(p => p.Events.SpeakWithAudio.Invoke(null, null, null))); + + _graph = A.Graph + .WithNextResult(node) + .Build(); + _playback = new DialoguePlayback(_graph, null, _events); + + _playback.Play(); + + _playback.Events.SpeakWithAudio.ReceivedWithAnyArgs(1).Invoke(null, null, null); + } + [Test] public void It_should_trigger_play_on_the_root_child () { var node = A.Node.Build(); diff --git a/Assets/com.fluid.dialogue/package.json b/Assets/com.fluid.dialogue/package.json index 87d528c..ad81442 100644 --- a/Assets/com.fluid.dialogue/package.json +++ b/Assets/com.fluid.dialogue/package.json @@ -1,6 +1,6 @@ { "name": "com.fluid.dialogue", - "version": "2.6.0", + "version": "3.0.0", "displayName": "Fluid Dialogue", "description": "A Unity dialogue system that features an easy to use drag and drop graph. ScriptableObject driven with the ability to write custom actions and conditions to create complex dialogue workflows.", "unity": "2019.1", diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ea2c5c..4274ff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,22 @@ -# [2.6.0](https://github.com/ashblue/fluid-dialogue/compare/v2.5.0...v2.6.0) (2022-09-20) +# [3.0.0](https://github.com/ashblue/fluid-dialogue/compare/v2.6.0...v3.0.0) (2024-04-24) ### Bug Fixes -* **spellcheck:** fixed a text spacing issue ([572ef1d](https://github.com/ashblue/fluid-dialogue/commit/572ef1dfa9be9b1de53b7427c8e6cedbf2426992)), closes [#29](https://github.com/ashblue/fluid-dialogue/issues/29) +* **dialogue editor:** no longer fires an error when deleting list items ([96449e8](https://github.com/ashblue/fluid-dialogue/commit/96449e8e5197829b68f11b84010a9eb80a87aeae)) ### Features -* dialogue nodes now include an audio file ([2a5b341](https://github.com/ashblue/fluid-dialogue/commit/2a5b34102a913d0c211e0d1977ae1ff84724380d)) +* added experimental nested graph playback restoration ([fb18251](https://github.com/ashblue/fluid-dialogue/commit/fb1825179ae46331067a340782d2d95b8dcc6cab)) +* **custom nodes:** users now have necessary hooks to create their own custom nodes (experimental) ([09e8596](https://github.com/ashblue/fluid-dialogue/commit/09e8596e660f0195ada3e180f4b8b97fb7eb3e01)) +* **graph creation:** can create new graphs externally now ([e92a3ca](https://github.com/ashblue/fluid-dialogue/commit/e92a3cae3192108045fc588356bd2ae9e68274bf)) +* **new node:** note nodes can now be added to graphs ([45585fe](https://github.com/ashblue/fluid-dialogue/commit/45585feae62a7fe23e100750efb1165f39e4fb5a)) +* **runtime gameobjects:** replaced game object overrides with a send message action API ([cef3f97](https://github.com/ashblue/fluid-dialogue/commit/cef3f97d21e7fdf0ca888f0b26d5b194e21b2fad)) + + +### BREAKING CHANGES + +* **runtime gameobjects:** You should remove all references to GameObject overrides, be ready to replace the +game object names with paths (write them down). After upgrading you'll need to swap or remove all +references to game object overrides from your project. diff --git a/Packages/manifest.json b/Packages/manifest.json index d077e0a..6309b2b 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -17,18 +17,18 @@ "com.fluid.unity-event-plus": "1.2.0", "com.unity.2d.sprite": "1.0.0", "com.unity.2d.tilemap": "1.0.0", - "com.unity.ads": "4.3.0", - "com.unity.analytics": "3.7.1", - "com.unity.collab-proxy": "1.17.2", - "com.unity.ext.nunit": "1.0.6", - "com.unity.ide.rider": "3.0.15", - "com.unity.ide.visualstudio": "2.0.16", - "com.unity.ide.vscode": "1.2.5", - "com.unity.purchasing": "4.4.1", - "com.unity.test-framework": "1.1.33", - "com.unity.textmeshpro": "3.0.6", - "com.unity.timeline": "1.7.1", - "com.unity.ugui": "1.0.0", + "com.unity.ads": "4.4.2", + "com.unity.ai.navigation": "2.0.0", + "com.unity.analytics": "3.8.1", + "com.unity.collab-proxy": "2.3.1", + "com.unity.ext.nunit": "2.0.5", + "com.unity.ide.rider": "3.0.28", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.purchasing": "4.11.0", + "com.unity.test-framework": "1.3.9", + "com.unity.timeline": "1.8.6", + "com.unity.ugui": "2.0.0", + "com.unity.modules.accessibility": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", "com.unity.modules.animation": "1.0.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 6012892..03f8bba 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -55,10 +55,13 @@ "version": "1.0.0", "depth": 0, "source": "builtin", - "dependencies": {} + "dependencies": { + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.uielements": "1.0.0" + } }, "com.unity.ads": { - "version": "4.3.0", + "version": "4.4.2", "depth": 0, "source": "registry", "dependencies": { @@ -66,8 +69,17 @@ }, "url": "https://packages.unity.com" }, + "com.unity.ai.navigation": { + "version": "2.0.0", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.com" + }, "com.unity.analytics": { - "version": "3.7.1", + "version": "3.8.1", "depth": 0, "source": "registry", "dependencies": { @@ -77,23 +89,21 @@ "url": "https://packages.unity.com" }, "com.unity.collab-proxy": { - "version": "1.17.2", + "version": "2.3.1", "depth": 0, "source": "registry", - "dependencies": { - "com.unity.services.core": "1.0.1" - }, + "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.ext.nunit": { - "version": "1.0.6", + "version": "2.0.5", "depth": 0, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.ide.rider": { - "version": "3.0.15", + "version": "3.0.28", "depth": 0, "source": "registry", "dependencies": { @@ -102,7 +112,7 @@ "url": "https://packages.unity.com" }, "com.unity.ide.visualstudio": { - "version": "2.0.16", + "version": "2.0.22", "depth": 0, "source": "registry", "dependencies": { @@ -110,78 +120,61 @@ }, "url": "https://packages.unity.com" }, - "com.unity.ide.vscode": { - "version": "1.2.5", - "depth": 0, - "source": "registry", - "dependencies": {}, - "url": "https://packages.unity.com" - }, "com.unity.nuget.newtonsoft-json": { - "version": "3.0.2", + "version": "3.2.1", "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.purchasing": { - "version": "4.4.1", + "version": "4.11.0", "depth": 0, "source": "registry", "dependencies": { "com.unity.ugui": "1.0.0", - "com.unity.modules.unityanalytics": "1.0.0", "com.unity.modules.unitywebrequest": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0", "com.unity.modules.androidjni": "1.0.0", - "com.unity.services.core": "1.3.1", - "com.unity.services.analytics": "4.0.1" + "com.unity.services.core": "1.8.2" }, "url": "https://packages.unity.com" }, "com.unity.services.analytics": { - "version": "4.2.0", + "version": "4.4.0", "depth": 1, "source": "registry", "dependencies": { "com.unity.ugui": "1.0.0", - "com.unity.services.core": "1.4.0" + "com.unity.services.core": "1.8.1", + "com.unity.nuget.newtonsoft-json": "3.0.2" }, "url": "https://packages.unity.com" }, "com.unity.services.core": { - "version": "1.4.2", + "version": "1.12.4", "depth": 1, "source": "registry", "dependencies": { "com.unity.modules.unitywebrequest": "1.0.0", - "com.unity.nuget.newtonsoft-json": "3.0.2", + "com.unity.nuget.newtonsoft-json": "3.2.1", "com.unity.modules.androidjni": "1.0.0" }, "url": "https://packages.unity.com" }, "com.unity.test-framework": { - "version": "1.1.33", + "version": "1.3.9", "depth": 0, "source": "registry", "dependencies": { - "com.unity.ext.nunit": "1.0.6", + "com.unity.ext.nunit": "2.0.3", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, "url": "https://packages.unity.com" }, - "com.unity.textmeshpro": { - "version": "3.0.6", - "depth": 0, - "source": "registry", - "dependencies": { - "com.unity.ugui": "1.0.0" - }, - "url": "https://packages.unity.com" - }, "com.unity.timeline": { - "version": "1.7.1", + "version": "1.8.6", "depth": 0, "source": "registry", "dependencies": { @@ -193,7 +186,7 @@ "url": "https://packages.unity.com" }, "com.unity.ugui": { - "version": "1.0.0", + "version": "2.0.0", "depth": 0, "source": "builtin", "dependencies": { @@ -201,6 +194,12 @@ "com.unity.modules.imgui": "1.0.0" } }, + "com.unity.modules.accessibility": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, "com.unity.modules.ai": { "version": "1.0.0", "depth": 0, @@ -248,6 +247,12 @@ "com.unity.modules.animation": "1.0.0" } }, + "com.unity.modules.hierarchycore": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, "com.unity.modules.imageconversion": { "version": "1.0.0", "depth": 0, @@ -337,17 +342,7 @@ "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.modules.uielementsnative": "1.0.0" - } - }, - "com.unity.modules.uielementsnative": { - "version": "1.0.0", - "depth": 1, - "source": "builtin", - "dependencies": { - "com.unity.modules.ui": "1.0.0", - "com.unity.modules.imgui": "1.0.0", - "com.unity.modules.jsonserialize": "1.0.0" + "com.unity.modules.hierarchycore": "1.0.0" } }, "com.unity.modules.umbra": { diff --git a/ProjectSettings/MultiplayerManager.asset b/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 0000000..8073753 --- /dev/null +++ b/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_ActiveMultiplayerRole: 0 diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset index 1dd8945..9b4f260 100644 --- a/ProjectSettings/PackageManagerSettings.asset +++ b/ProjectSettings/PackageManagerSettings.asset @@ -12,11 +12,13 @@ MonoBehaviour: m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} m_Name: m_EditorClassIdentifier: - m_EnablePreviewPackages: 0 - m_EnablePackageDependencies: 0 + m_EnablePreReleasePackages: 0 m_AdvancedSettingsExpanded: 1 m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + m_DismissPreviewPackagesInUse: 0 oneTimeWarningShown: 0 + oneTimeDeprecatedPopUpShown: 0 m_Registries: - m_Id: main m_Name: @@ -24,7 +26,8 @@ MonoBehaviour: m_Scopes: [] m_IsDefault: 1 m_Capabilities: 7 - - m_Id: scoped:NPM + m_ConfigSource: 0 + - m_Id: scoped:project:NPM m_Name: NPM m_Url: https://registry.npmjs.org m_Scopes: @@ -32,23 +35,12 @@ MonoBehaviour: - com.fluid m_IsDefault: 0 m_Capabilities: 0 - m_UserSelectedRegistryName: + m_ConfigSource: 4 + m_UserSelectedRegistryName: NPM m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: - m_ErrorMessage: - m_Original: - m_Id: scoped:NPM - m_Name: NPM - m_Url: https://registry.npmjs.org - m_Scopes: - - clever-crow - - com.fluid - m_IsDefault: 0 - m_Capabilities: 0 m_Modified: 0 - m_Name: NPM - m_Url: https://registry.npmjs.org - m_Scopes: - - clever-crow - - com.fluid - m_SelectedScopeIndex: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -850 + m_OriginalInstanceId: -854 + m_LoadAssets: 0 diff --git a/ProjectSettings/Packages/com.unity.services.core/Settings.json b/ProjectSettings/Packages/com.unity.services.core/Settings.json new file mode 100644 index 0000000..e69de29 diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 85a6ac0..c4b2d62 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 16 + serializedVersion: 27 productGUID: 246976e240ecc4f479e7f86c296c0826 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -48,13 +48,16 @@ PlayerSettings: defaultScreenHeightWeb: 600 m_StereoRenderingPath: 0 m_ActiveColorSpace: 0 + unsupportedMSAAFallback: 0 + m_SpriteBatchVertexThreshold: 300 m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 - iosAppInBackgroundBehavior: 0 - displayResolutionDialog: 0 - iosAllowHTTPDownload: 1 + iosUseCustomAppBackgroundBehavior: 0 allowedAutorotateToPortrait: 1 allowedAutorotateToPortraitUpsideDown: 1 allowedAutorotateToLandscapeRight: 1 @@ -65,7 +68,16 @@ PlayerSettings: disableDepthAndStencilBuffers: 0 androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 1 + androidUseSwappy: 0 androidBlitType: 0 + androidResizableWindow: 0 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + androidApplicationEntry: 1 defaultIsNativeResolution: 1 macRetinaSupport: 1 runInBackground: 1 @@ -77,13 +89,15 @@ PlayerSettings: hideHomeButton: 0 submitAnalytics: 1 usePlayerLog: 1 + dedicatedServerOptimizations: 0 bakeCollisionMeshes: 0 forceSingleInstance: 0 + useFlipModelSwapchain: 1 resizableWindow: 0 useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 1 - graphicsJobs: 0 + meshDeformation: 2 xboxPIXTextureCapture: 0 xboxEnableAvatar: 0 xboxEnableKinect: 0 @@ -91,7 +105,6 @@ PlayerSettings: xboxEnableFitness: 0 visibleInBackground: 1 allowFullscreenSwitch: 1 - graphicsJobMode: 0 fullscreenMode: 1 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 @@ -104,6 +117,7 @@ PlayerSettings: xboxOneMonoLoggingLevel: 0 xboxOneLoggingLevel: 1 xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 xboxOnePresentImmediateThreshold: 0 switchQueueCommandMemory: 0 switchQueueControlMemory: 16384 @@ -111,13 +125,18 @@ PlayerSettings: switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 + vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 - m_SupportedAspectRatios: - 4:3: 1 - 5:4: 1 - 16:10: 1 - 16:9: 1 - Others: 1 + vulkanEnablePreTransform: 0 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 bundleVersion: 0.1 preloadedAssets: [] metroInputSource: 0 @@ -126,42 +145,30 @@ PlayerSettings: xboxOneDisableKinectGpuReservation: 1 xboxOneEnable7thCore: 1 vrSettings: - cardboard: - depthFormat: 0 - enableTransitionView: 0 - daydream: - depthFormat: 0 - useSustainedPerformanceMode: 0 - enableVideoLayer: 0 - useProtectedVideoMemory: 0 - minimumSupportedHeadTracking: 0 - maximumSupportedHeadTracking: 1 - hololens: - depthFormat: 1 - depthBufferSharingEnabled: 1 - lumin: - depthFormat: 0 - frameTiming: 2 - enableGLCache: 0 - glCacheMaxBlobSize: 524288 - glCacheMaxFileSize: 8388608 - oculus: - sharedDepthBuffer: 1 - dashSupport: 1 enable360StereoCapture: 0 isWsaHolographicRemotingEnabled: 0 - protectGraphicsMemory: 0 enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 useHDRDisplay: 0 + hdrBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 - applicationIdentifier: {} - buildNumber: {} + androidMinAspectRatio: 1 + applicationIdentifier: + Standalone: com.DefaultCompany.fluid-dialogue + buildNumber: + Bratwurst: 0 + Standalone: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 16 + AndroidMinSdkVersion: 23 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: @@ -171,37 +178,24 @@ PlayerSettings: ForceInternetPermission: 0 ForceSDCardPermission: 0 CreateWallpaper: 0 - APKExpansionFiles: 0 + androidSplitApplicationBinary: 0 keepLoadedShadersAlive: 0 StripUnusedMeshComponents: 1 + strictShaderVariantMatching: 0 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 9.0 + iOSTargetOSVersionString: 13.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 9.0 + tvOSTargetOSVersionString: 13.0 + bratwurstSdkVersion: 0 + bratwurstTargetOSVersionString: 13.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 uIStatusBarHidden: 1 uIExitOnSuspend: 0 uIStatusBarStyle: 0 - iPhoneSplashScreen: {fileID: 0} - iPhoneHighResSplashScreen: {fileID: 0} - iPhoneTallHighResSplashScreen: {fileID: 0} - iPhone47inSplashScreen: {fileID: 0} - iPhone55inPortraitSplashScreen: {fileID: 0} - iPhone55inLandscapeSplashScreen: {fileID: 0} - iPhone58inPortraitSplashScreen: {fileID: 0} - iPhone58inLandscapeSplashScreen: {fileID: 0} - iPadPortraitSplashScreen: {fileID: 0} - iPadHighResPortraitSplashScreen: {fileID: 0} - iPadLandscapeSplashScreen: {fileID: 0} - iPadHighResLandscapeSplashScreen: {fileID: 0} - iPhone65inPortraitSplashScreen: {fileID: 0} - iPhone65inLandscapeSplashScreen: {fileID: 0} - iPhone61inPortraitSplashScreen: {fileID: 0} - iPhone61inLandscapeSplashScreen: {fileID: 0} appleTVSplashScreen: {fileID: 0} appleTVSplashScreen2x: {fileID: 0} tvOSSmallIconLayers: [] @@ -229,32 +223,48 @@ PlayerSettings: iOSLaunchScreeniPadFillPct: 100 iOSLaunchScreeniPadSize: 100 iOSLaunchScreeniPadCustomXibPath: - iOSUseLaunchScreenStoryboard: 0 iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: [] + macOSURLSchemes: [] iOSBackgroundModes: 0 iOSMetalForceHardShadows: 0 metalEditorSupport: 1 metalAPIValidation: 1 iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 appleDeveloperTeamID: iOSManualSigningProvisioningProfileID: tvOSManualSigningProvisioningProfileID: + bratwurstManualSigningProvisioningProfileID: iOSManualSigningProvisioningProfileType: 0 tvOSManualSigningProvisioningProfileType: 0 + bratwurstManualSigningProvisioningProfileType: 0 appleEnableAutomaticSigning: 0 iOSRequireARKit: 0 iOSAutomaticallyDetectAndAddCapabilities: 1 appleEnableProMotion: 0 + shaderPrecisionModel: 0 clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea templatePackageId: com.unity.template.3d@2.3.3 templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 AndroidTargetArchitectures: 1 + AndroidTargetDevices: 0 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: '{inproject}: ' AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidEnableArm64MTE: 0 AndroidBuildApkPerCpuArchitecture: 0 AndroidTVCompatibility: 0 AndroidIsGame: 1 @@ -267,7 +277,12 @@ PlayerSettings: height: 180 banner: {fileID: 0} androidGamepadSupportLevel: 0 - resolutionDialogBanner: {fileID: 0} + chromeosInputEmulation: 1 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + AndroidReportGooglePlayAppDependencies: 1 m_BuildTargetIcons: [] m_BuildTargetPlatformIcons: [] m_BuildTargetBatching: @@ -286,16 +301,59 @@ PlayerSettings: - m_BuildTarget: WebGL m_StaticBatching: 0 m_DynamicBatching: 0 + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 0 + - m_BuildTarget: PS5Player + m_GraphicsJobs: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 0 + - m_BuildTarget: GameCoreXboxOneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: GameCoreScarlettSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BratwurstPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: CloudRendering + m_GraphicsJobs: 0 + - m_BuildTarget: EmbeddedLinux + m_GraphicsJobs: 0 + - m_BuildTarget: QNX + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 m_BuildTargetGraphicsAPIs: - m_BuildTarget: AndroidPlayer m_APIs: 150000000b000000 - m_Automatic: 0 + m_Automatic: 1 - m_BuildTarget: iOSSupport m_APIs: 10000000 m_Automatic: 1 - m_BuildTarget: AppleTVSupport m_APIs: 10000000 - m_Automatic: 0 + m_Automatic: 1 - m_BuildTarget: WebGLSupport m_APIs: 0b000000 m_Automatic: 1 @@ -305,7 +363,8 @@ PlayerSettings: m_Devices: - Oculus - OpenVR - m_BuildTargetEnableVuforiaSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 openGLRequireES31: 0 openGLRequireES31AEP: 0 openGLRequireES32: 0 @@ -315,7 +374,11 @@ PlayerSettings: iPhone: 1 tvOS: 1 m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupHDRCubemapEncodingQuality: [] m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: [] playModeTestRunnerEnabled: 0 runPlayModeTestAsEditModeTest: 0 actionOnDotNetUnhandledException: 1 @@ -325,14 +388,20 @@ PlayerSettings: cameraUsageDescription: locationUsageDescription: microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 10.13.0 + switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 switchSocketAllocatorPoolSize: 128 switchSocketConcurrencyLimit: 14 switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 switchNSODependencies: + switchCompilerFlags: switchTitleNames_0: switchTitleNames_1: switchTitleNames_2: @@ -348,6 +417,7 @@ PlayerSettings: switchTitleNames_12: switchTitleNames_13: switchTitleNames_14: + switchTitleNames_15: switchPublisherNames_0: switchPublisherNames_1: switchPublisherNames_2: @@ -363,6 +433,7 @@ PlayerSettings: switchPublisherNames_12: switchPublisherNames_13: switchPublisherNames_14: + switchPublisherNames_15: switchIcons_0: {fileID: 0} switchIcons_1: {fileID: 0} switchIcons_2: {fileID: 0} @@ -378,6 +449,7 @@ PlayerSettings: switchIcons_12: {fileID: 0} switchIcons_13: {fileID: 0} switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} switchSmallIcons_0: {fileID: 0} switchSmallIcons_1: {fileID: 0} switchSmallIcons_2: {fileID: 0} @@ -393,6 +465,7 @@ PlayerSettings: switchSmallIcons_12: {fileID: 0} switchSmallIcons_13: {fileID: 0} switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} switchManualHTML: switchAccessibleURLs: switchLegalInformation: @@ -402,7 +475,6 @@ PlayerSettings: switchReleaseVersion: 0 switchDisplayVersion: 1.0.0 switchStartupUserAccount: 0 - switchTouchScreenUsage: 0 switchSupportedLanguagesMask: 0 switchLogoType: 0 switchApplicationErrorCodeCategory: @@ -424,6 +496,7 @@ PlayerSettings: switchRatingsInt_9: 0 switchRatingsInt_10: 0 switchRatingsInt_11: 0 + switchRatingsInt_12: 0 switchLocalCommunicationIds_0: switchLocalCommunicationIds_1: switchLocalCommunicationIds_2: @@ -443,6 +516,7 @@ PlayerSettings: switchNativeFsCacheSize: 32 switchIsHoldTypeHorizontal: 0 switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 switchSocketConfigEnabled: 0 switchTcpInitialSendBufferSize: 32 switchTcpInitialReceiveBufferSize: 64 @@ -453,7 +527,13 @@ PlayerSettings: switchSocketBufferEfficiency: 4 switchSocketInitializeEnabled: 1 switchNetworkInterfaceManagerInitializeEnabled: 1 - switchPlayerConnectionEnabled: 1 + switchDisableHTCSPlayerConnection: 0 + switchUseNewStyleFilepaths: 1 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: @@ -480,6 +560,7 @@ PlayerSettings: ps4ShareFilePath: ps4ShareOverlayImagePath: ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: ps4NPtitleDatPath: ps4RemotePlayKeyAssignment: -1 ps4RemotePlayKeyMappingDir: @@ -505,6 +586,7 @@ PlayerSettings: ps4UseResolutionFallback: 0 ps4ReprojectionSupport: 0 ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 ps4SocialScreenEnabled: 0 ps4ScriptOptimizationLevel: 0 ps4Audio3dVirtualSpeakerCount: 14 @@ -521,15 +603,21 @@ PlayerSettings: ps4disableAutoHideSplash: 0 ps4videoRecordingFeaturesUsed: 0 ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 spritePackerPolicy: webGLMemorySize: 16 webGLExceptionSupport: 1 webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 webGLDataCaching: 1 webGLDebugSymbols: 0 webGLEmscriptenArgs: @@ -538,21 +626,54 @@ PlayerSettings: webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 webGLLinkerTarget: 1 webGLThreadsSupport: 0 - webGLWasmStreaming: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLEnableWebGPU: 0 + webGLPowerPreference: 2 + webGLWebAssemblyTable: 0 + webGLWebAssemblyBigInt: 0 + webGLCloseOnQuit: 0 scriptingDefineSymbols: {} + additionalCompilerArguments: {} platformArchitecture: {} - scriptingBackend: {} + scriptingBackend: + Android: 0 il2cppCompilerConfiguration: {} - managedStrippingLevel: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: + Android: 1 + Bratwurst: 1 + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + QNX: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 allowUnsafeCode: 0 + useDeterministicCompilation: 1 additionalIl2CppArgs: scriptingRuntimeVersion: 1 gcIncremental: 0 gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: Template_3D @@ -582,6 +703,7 @@ PlayerSettings: metroFTAName: metroFTAFileTypes: [] metroProtocolName: + vcxProjDefaultLanguage: XboxOneProductId: XboxOneUpdateKey: XboxOneSandboxId: @@ -600,18 +722,16 @@ PlayerSettings: XboxOneCapability: [] XboxOneGameRating: {} XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 XboxOneEnableGPUVariability: 1 XboxOneSockets: {} XboxOneSplashScreen: {fileID: 0} XboxOneAllowedProductIds: [] XboxOnePersistentLocalStorageSize: 0 XboxOneXTitleMemory: 8 - xboxOneScriptCompiler: 1 XboxOneOverrideIdentityName: - vrEditorSettings: - daydream: - daydreamIconForeground: {fileID: 0} - daydreamIconBackground: {fileID: 0} + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} cloudServicesEnabled: UNet: 1 luminIcon: @@ -625,19 +745,24 @@ PlayerSettings: luminVersion: m_VersionCode: 1 m_VersionName: - facebookSdkVersion: 7.9.4 - facebookAppId: - facebookCookies: 1 - facebookLogging: 1 - facebookStatus: 1 - facebookXfbml: 0 - facebookFrictionlessRequests: 1 + hmiPlayerDataPath: + hmiForceSRGBBlit: 0 + embeddedLinuxEnableGamepadInput: 0 + hmiCpuConfiguration: + hmiLogStartupTiming: 0 + qnxGraphicConfPath: apiCompatibilityLevel: 6 + captureStartupLogs: {} + activeInputHandler: 0 + windowsGamepadBackendHint: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] projectName: organizationId: cloudEnabled: 0 - enableNativePlatformBackendsForNewInputSystem: 0 - disableOldInputManagerSupport: 0 legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 35273e6..cd8dbd1 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2022.1.16f1 -m_EditorVersionWithRevision: 2022.1.16f1 (7321c9670bc2) +m_EditorVersion: 2023.2.19f1 +m_EditorVersionWithRevision: 2023.2.19f1 (95c298372b1e) diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset index ebcc78b..78eb9eb 100644 --- a/ProjectSettings/QualitySettings.asset +++ b/ProjectSettings/QualitySettings.asset @@ -6,7 +6,7 @@ QualitySettings: serializedVersion: 5 m_CurrentQuality: 5 m_QualitySettings: - - serializedVersion: 2 + - serializedVersion: 4 name: Very Low pixelLightCount: 0 shadows: 0 @@ -19,16 +19,23 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 1 - textureQuality: 1 + globalTextureMipmapLimit: 1 + textureMipmapLimitSettings: [] anisotropicTextures: 0 antiAliasing: 0 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 vSyncCount: 0 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 lodBias: 0.3 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -40,8 +47,18 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: [] - - serializedVersion: 2 + - serializedVersion: 4 name: Low pixelLightCount: 0 shadows: 0 @@ -54,16 +71,23 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 2 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 0 antiAliasing: 0 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 vSyncCount: 0 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 lodBias: 0.4 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -75,8 +99,18 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: [] - - serializedVersion: 2 + - serializedVersion: 4 name: Medium pixelLightCount: 1 shadows: 1 @@ -89,16 +123,23 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 0 skinWeights: 2 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 1 antiAliasing: 0 softParticles: 0 softVegetation: 0 realtimeReflectionProbes: 0 billboardsFaceCameraPosition: 0 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 vSyncCount: 1 + realtimeGICPUUsage: 25 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 lodBias: 0.7 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -110,8 +151,18 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: [] - - serializedVersion: 2 + - serializedVersion: 4 name: High pixelLightCount: 2 shadows: 2 @@ -124,16 +175,23 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 skinWeights: 2 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 1 antiAliasing: 0 softParticles: 0 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 vSyncCount: 1 + realtimeGICPUUsage: 50 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 lodBias: 1 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -145,8 +203,18 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: [] - - serializedVersion: 2 + - serializedVersion: 4 name: Very High pixelLightCount: 3 shadows: 2 @@ -159,16 +227,23 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 skinWeights: 4 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 2 antiAliasing: 2 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 vSyncCount: 1 + realtimeGICPUUsage: 50 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 lodBias: 1.5 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -180,8 +255,18 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: [] - - serializedVersion: 2 + - serializedVersion: 4 name: Ultra pixelLightCount: 4 shadows: 2 @@ -194,16 +279,23 @@ QualitySettings: shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} shadowmaskMode: 1 skinWeights: 4 - textureQuality: 0 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] anisotropicTextures: 2 antiAliasing: 2 softParticles: 1 softVegetation: 1 realtimeReflectionProbes: 1 billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 vSyncCount: 1 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 lodBias: 2 maximumLODLevel: 0 + enableLODCrossFade: 1 streamingMipmapsActive: 0 streamingMipmapsAddAllCameras: 1 streamingMipmapsMemoryBudget: 512 @@ -215,5 +307,17 @@ QualitySettings: asyncUploadBufferSize: 16 asyncUploadPersistentBuffer: 1 resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 excludedTargetPlatforms: [] - m_PerPlatformDefaultQuality: {} + m_TextureMipmapLimitGroupNames: [] + m_PerPlatformDefaultQuality: + Standalone: 0 diff --git a/README.md b/README.md index 497d4ee..66069f5 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # Fluid Dialogue + +[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) + A Unity dialogue system that features an easy to use drag and drop graph. ScriptableObject driven with the ability to write custom actions and conditions to create complex dialogue workflows. @@ -25,7 +28,34 @@ First you'll need to [install](#installation) the package with Unity Package Man 1. Create -> Fluid -> Dialogue -> Graph 1. Click "Edit Dialogue" to customize your graph -To create a custom UI to display your graph, you'll need to handle a series of events emitted by the dialogue controller. You can find a full example of this in the [Examples](#examples) folder. +To create a custom UI to display your graph, you'll need to handle a series of events emitted by the dialogue controller. You can find a full example of this in the [Examples](#examples) folder. + +### Playing Dialogue + +To trigger dialogue playback you'll need the following snippet. This will turn your dialogue data into an ongoing conversation with events and variables. + +```csharp +using System.Collections; +using System.Linq; +using CleverCrow.Fluid.Databases; +using CleverCrow.Fluid.Dialogues.Graphs; +using CleverCrow.Fluid.Dialogues; +using UnityEngine; + +public class ExampleDialoguePlayback : MonoBehaviour { + private DialogueController _ctrl; + public DialogueGraph dialogue; + + private void Awake () { + var database = new DatabaseInstanceExtended(); + _ctrl = new DialogueController(database); + _ctrl.Events.Speak.AddListener((actor, text) => { Debug.Log($"{actor.DisplayName}: {text}"); }); + _ctrl.Play(dialogue); + } +} +``` + +For more details see the [`ExampleDialoguePlayback.cs`](https://github.com/ashblue/fluid-dialogue/blob/develop/Assets/Examples/BasicConversation/Scripts/ExampleDialoguePlayback.cs) file for a complete solution on how to manage dialogue in your game. ### Node Types @@ -65,6 +95,18 @@ Globals are mostly the same as local variables. The difference is these will be The GlobalDatabaseManager will be marked DoNotDestroyOnLoad to persist between scene loads. If you want to save it and write the contents to a file run `Save()` to return a string. You can then restore the database simply by calling `Load(returned save string)`. +### Interacting With Runtime GameObject(s) + +To interact with GameObject(s) at runtime use the "SendMessage" action suite. You cannot directly reference GameObjects in the dialogue graph as they are separately serialized. Instead, you can use the "SendMessage" action to send a message to a GameObject at runtime. + +It's strongly recommended when sending messages you use a consistent object name like "DIALOGUE_DIRECTOR" to keep things simple and write your own custom scripts to handle the messages. This will make it easier to maintain and debug your game. + +![send-message.png](docs/send-message.png) + +You can also use the "SetActive" action to toggle GameObjects on and off. This is a great low overhead way to manage dialogue scripts easily. + +If you need to do a lot of heavy lifting with tons of scripting on runtime GameObjects, it's recommended you write your own custom actions to handle this. See the APIs section for more details. + ### Examples To see the entire Fluid Dialogue workflow, it's highly recommended that you download this repo and run projects in the `Assets/Examples` folder. @@ -85,7 +127,7 @@ Fluid Dialogue is used through [Unity's Package Manager](https://docs.unity3d.co } ], "dependencies": { - "com.fluid.dialogue": "1.0.0" + "com.fluid.dialogue": "2.6.0" } } ``` @@ -150,6 +192,139 @@ public class CustomCondition : ConditionDataBase { } ``` +### Resuming Graph Playback + +Graph playback can be resumed from anywhere. This includes nested graphs and the exact node you want to resume from. + +```C# +var ctrl = new DialogueController(...); + +// Play your graph to generate runtime data and advance the graph to a specific node by hand +ctrl.Play(...); + +// Record the required serialized properties +var graph = ctrl.RootGraph; // Finds the root graph that is playing +var parentHierarchy = dialogue.Ctrl.ParentHierarchy; // Gets the IDs of all nodes the nested graphs that are playing +var nextNodeId = ctrl.ActiveDialogue.Pointer.Next()?.UniqueId; // You probably want the next node in your graph, not the current one + +// Create a new graph and resume playback +var newCtrl = new DialogueController(...); + +if (newCtrl.CanPlay(graph, parentHierarchy, nextNodeId)) { + // Failsafe that makes sure our graph playback data is valid + newCtrl.Play(graph, parentHierarchy, nextNodeId); +} else { + // If the data is invalid, just play the graph from the beginning or implement your own fallback logic + newCtrl.Play(graph); +} +``` + +### Custom Nodes (Experimental) + +You can create your own custom nodes with the following API. Please note this is experimental and missing some features. + +First you will need to setup the data layer. This is what will be converted to a nested ScriptableObject on demand for the graph. + +```c# +using System.Linq; +using CleverCrow.Fluid.Dialogues; +using CleverCrow.Fluid.Dialogues.Graphs; +using CleverCrow.Fluid.Dialogues.Nodes; + +namespace YourNamespaceHere { + // Changing this will customize the name in the graph editor creation menu + [CreateMenu("Example")] + public class NodeExampleData : NodeDataBase { + public string myMessage; + + // This is the default name the node will display in the graph editor + protected override string DefaultName => "Example"; + + public override INode GetRuntime (IGraph graphRuntime, IDialogueController dialogue) { + return new NodeCombat( + graphRuntime, + UniqueId, + myMessage, + children.ToList(), + conditions.Select(c => c.GetRuntime(graphRuntime, dialogue)).ToList(), + enterActions.Select(c => c.GetRuntime(graphRuntime, dialogue)).ToList(), + exitActions.Select(c => c.GetRuntime(graphRuntime, dialogue)).ToList() + ); + } + } +} +``` + +Next you will need to create the runtime node. This is what will be generated at runtime for every corresponding data object. + +```c# +using CleverCrow.Fluid.Dialogues; +using CleverCrow.Fluid.Dialogues.Graphs; +using CleverCrow.Fluid.Dialogues.Nodes; + +namespace YourNamespaceHere { + public class NodeExample : NodeBase { + readonly string _myMessage; + + public NodeCombat ( + IGraph runtime, + string uniqueId, + // We've added our new value here. You can pass in whatever values you need. Just add more parameters to the constructor + string myMessage, + System.Collections.Generic.List children, + System.Collections.Generic.List conditions, + System.Collections.Generic.List enterActions, + System.Collections.Generic.List exitActions) + // This is what handles all the messy setup we'd normally have to do + : base(runtime, uniqueId, children, conditions, enterActions, exitActions) { + + _myMessage = myMessage; + } + + // Handles what happens when the node is played + protected override void OnPlay (IDialoguePlayback playback) { + Debug.Log(_myMessage); + } + } +} +``` + +Lastly you will need to create a view layer. This is what will be displayed in the graph editor. Please note this must be nested in a folder called `Editor`. + +```c# +using CleverCrow.Fluid.Dialogues.Editors; +using CleverCrow.Fluid.Dialogues.Editors.NodeDisplays; +using UnityEditor; +using UnityEngine; + +namespace YourNamespaceHere { + [NodeType(typeof(NodeExampleData))] + public class NodeExampleEditor : NodeEditorBase { + protected override Color NodeColor { get; } = new(0.75f, 0.52f, 0f); + protected override float NodeWidth => 200; + + protected override void OnPrintBody (Event e) { + serializedObject.Update(); + + // This creates a dynamic input for the myMessage field + EditorGUILayout.PropertyField(serializedObject.FindProperty("myMessage"), GUIContent.none); + + serializedObject.ApplyModifiedProperties(); + } + } +} +``` + +And that's it. The node will now be available in the graph editor and print our message at runtime. It even supports conditions, actions, and parent/child connections. + +For more details please take a look at the source code for the different node types. This will give you a better idea of how to structure more complex custom nodes with multiple choices and other details. + +## Releases + +Please note that whatever node you're resuming from will play that exact node with enter actions and all previous nodes will not trigger anything. This is a direct reference and does not simulate the graph from the beginning. + +```c# + ## Releases Archives of specific versions and release notes are available on the [releases page](https://github.com/ashblue/fluid-dialogue/releases). @@ -189,3 +364,25 @@ npm run commit --- This project was generated with [Oyster Package Generator](https://github.com/ashblue/oyster-package-generator). + +## Contributors ✨ + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + + + + + + + + +
Richard Bryan Irwin
Richard Bryan Irwin

📖
+ + + + + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/docs/send-message.png b/docs/send-message.png new file mode 100644 index 0000000..d51266b Binary files /dev/null and b/docs/send-message.png differ diff --git a/package-lock.json b/package-lock.json index d1afb85..874214a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "com.fluid.dialogue", - "version": "2.6.0", + "version": "3.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "com.fluid.dialogue", - "version": "2.6.0", + "version": "3.0.0", "license": "MIT", "devDependencies": { "@commitlint/cli": "~17.1.2", diff --git a/package.json b/package.json index 8d802ce..365d3ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.fluid.dialogue", - "version": "2.6.0", + "version": "3.0.0", "unity": "2019.1", "displayName": "Fluid Dialogue", "description": "A Unity dialogue system that features an easy to use drag and drop graph. ScriptableObject driven with the ability to write custom actions and conditions to create complex dialogue workflows.", @@ -8,18 +8,14 @@ "scripts": { "build": "node build.js", "semantic-release": "semantic-release", - "commit": "git-cz" + "commit": "git-cz", + "prepare": "husky install" }, "keywords": [ "unity", "dialogue", "dialogue system" ], - "husky": { - "hooks": { - "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" - } - }, "repository": { "type": "git", "url": "git+https://github.com/ashblue/fluid-dialogue.git"