diff --git a/.gitignore b/.gitignore index 184d4873765c80af9bc0773b09aa01bffedab19c..26f571387f1c69514b44858ce2e2f7de7ce226ef 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,9 @@ UserSettings/ /Assets/Images/frameit_logo_512x512.png.meta /Assets/Images/ScreenCapture_1024x500.png.meta UserSettings/EditorUserSettings.asset + +# ignore FrameIT server +Assets/StreamingAssets/archives/ +Assets/StreamingAssets/archives.meta +Assets/StreamingAssets/frameit-mmt.jar +Assets/StreamingAssets/frameit-mmt.jar.meta diff --git a/.gitmodules b/.gitmodules index 33a218feea88a69725fc267c7c107c4a6b797ee5..a49babd763ba692ced0e3ef95f7b895a14896c13 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Assets/Plugins/JsonSubTypes"] path = Assets/Plugins/JsonSubTypes url = https://github.com/manuc66/JsonSubTypes +[submodule "Packages/bessw.unity.webview"] + path = Packages/bessw.unity.webview + url = https://gl.kwarc.info/FrameIT/unity-webview.git diff --git a/Assets/Resources/Prefabs/Stage_Default.prefab b/Assets/Resources/Prefabs/Stage_Default.prefab index f60a78e5214d52d0a31785273b522905fbfeb3ba..062e64483e63aec3cfa341ff8abea3eb03ffd8b4 100644 --- a/Assets/Resources/Prefabs/Stage_Default.prefab +++ b/Assets/Resources/Prefabs/Stage_Default.prefab @@ -2376,6 +2376,11 @@ PrefabInstance: propertyPath: m_AnchorMin.x value: 0 objectReference: {fileID: 0} + - target: {fileID: 861183263081594858, guid: b996060e27da25c498842defc1996d84, + type: 3} + propertyPath: m_RootOrder + value: 9 + objectReference: {fileID: 0} - target: {fileID: 947958301574655299, guid: b996060e27da25c498842defc1996d84, type: 3} propertyPath: m_IsActive diff --git a/Assets/Resources/Prefabs/UI/Facts/Factscreen.prefab b/Assets/Resources/Prefabs/UI/Facts/Factscreen.prefab index 8addc4b7fc81f8adcdffff90ba33456f23d06819..9dff07b6f55c9b75890a54c5f83648b1192ad7ea 100644 --- a/Assets/Resources/Prefabs/UI/Facts/Factscreen.prefab +++ b/Assets/Resources/Prefabs/UI/Facts/Factscreen.prefab @@ -507,7 +507,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: -180} + m_AnchoredPosition: {x: 0, y: 0.000030517578} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 1} --- !u!114 &8823539307371861913 diff --git a/Assets/Resources/Prefabs/UI/FrameITUI.prefab b/Assets/Resources/Prefabs/UI/FrameITUI.prefab index e570ddf7a13f5d0c5b183dc73e6280dbb6c15faa..a1609d901a39ae0cf6544a1861fb1e23141bf7ae 100644 --- a/Assets/Resources/Prefabs/UI/FrameITUI.prefab +++ b/Assets/Resources/Prefabs/UI/FrameITUI.prefab @@ -406,12 +406,12 @@ PrefabInstance: - target: {fileID: 8553388048532215990, guid: 884ac57de337c364391b247761071fb1, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 8553388048532215990, guid: 884ac57de337c364391b247761071fb1, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 8553388048532215990, guid: 884ac57de337c364391b247761071fb1, type: 3} @@ -503,6 +503,11 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 573039479540912931, guid: 292834880e6f0e54186b873acc62d3f2, + type: 3} + propertyPath: m_PresetInfoIsWorld + value: 1 + objectReference: {fileID: 0} - target: {fileID: 3716020922907832516, guid: 292834880e6f0e54186b873acc62d3f2, type: 3} propertyPath: m_SizeDelta.y @@ -556,7 +561,7 @@ PrefabInstance: - target: {fileID: 6500467619489830996, guid: 292834880e6f0e54186b873acc62d3f2, type: 3} propertyPath: m_AnchoredPosition.y - value: 1080 + value: 146554910 objectReference: {fileID: 0} - target: {fileID: 7849991042685492731, guid: 292834880e6f0e54186b873acc62d3f2, type: 3} @@ -606,7 +611,7 @@ PrefabInstance: - target: {fileID: 7989559431199338490, guid: 292834880e6f0e54186b873acc62d3f2, type: 3} propertyPath: m_AnchoredPosition.y - value: -59.999527 + value: -8136900 objectReference: {fileID: 0} - target: {fileID: 8004702056544321748, guid: 292834880e6f0e54186b873acc62d3f2, type: 3} diff --git a/Assets/Resources/Prefabs/UI/Ingame/FrameITUI_mobile.prefab b/Assets/Resources/Prefabs/UI/Ingame/FrameITUI_mobile.prefab index 31d6d0d00310add6747878f091b56d3ab22e558d..d789848f1792a669a3e2061c919f159aea604fca 100644 --- a/Assets/Resources/Prefabs/UI/Ingame/FrameITUI_mobile.prefab +++ b/Assets/Resources/Prefabs/UI/Ingame/FrameITUI_mobile.prefab @@ -4952,7 +4952,7 @@ PrefabInstance: - target: {fileID: 7989559431199338490, guid: 292834880e6f0e54186b873acc62d3f2, type: 3} propertyPath: m_AnchoredPosition.y - value: -0.000045776367 + value: -2400 objectReference: {fileID: 0} - target: {fileID: 8004702056544321748, guid: 292834880e6f0e54186b873acc62d3f2, type: 3} diff --git a/Assets/Resources/Prefabs/UI/Ingame/GadgetCanvas.prefab b/Assets/Resources/Prefabs/UI/Ingame/GadgetCanvas.prefab index f4fa3f780801052b4b41d65697dc2c72a75ef37a..b67e0e696ab7c32fac8cc4b402e330b0e01f0126 100644 --- a/Assets/Resources/Prefabs/UI/Ingame/GadgetCanvas.prefab +++ b/Assets/Resources/Prefabs/UI/Ingame/GadgetCanvas.prefab @@ -174,7 +174,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} + m_AnchoredPosition: {x: 940, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} --- !u!114 &6662492270148709753 @@ -538,7 +538,7 @@ MonoBehaviour: m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 0 + m_PresetInfoIsWorld: 1 --- !u!1001 &3122257488954702478 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/Resources/Prefabs/UI/Ingame/HidingCanvas.prefab b/Assets/Resources/Prefabs/UI/Ingame/HidingCanvas.prefab index c6dd0370ab27d0b96ea4c9f7f7e8aacaf4e5a5f3..d46918be32052d1850dd5431f381855637b54ca6 100644 --- a/Assets/Resources/Prefabs/UI/Ingame/HidingCanvas.prefab +++ b/Assets/Resources/Prefabs/UI/Ingame/HidingCanvas.prefab @@ -35,7 +35,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 14040} + m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 1, y: 1} --- !u!114 &6592514254180342026 @@ -109,10 +109,10 @@ RectTransform: m_Father: {fileID: 3853195430673864773} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 568.4, y: -208.64} + m_SizeDelta: {x: 1136.8, y: 217.28} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &8314331323416511131 CanvasRenderer: @@ -248,10 +248,10 @@ RectTransform: m_Father: {fileID: 3716020922907832516} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 578.4, y: -208.64} + m_SizeDelta: {x: 1156.8, y: 417.28} m_Pivot: {x: 0.5, y: 0.5} --- !u!222 &911570484790407906 CanvasRenderer: @@ -531,7 +531,7 @@ RectTransform: m_AnchorMin: {x: 0.5, y: 0} m_AnchorMax: {x: 0.5, y: 0} m_AnchoredPosition: {x: -0.008544922, y: 0.0002421254} - m_SizeDelta: {x: 1156.8, y: 0} + m_SizeDelta: {x: 1156.8, y: 417.28} m_Pivot: {x: 0.5, y: 0} --- !u!114 &6505282139119622248 MonoBehaviour: @@ -991,9 +991,9 @@ RectTransform: m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: -20} m_Pivot: {x: 0, y: 1} --- !u!222 &8004702056544321750 CanvasRenderer: @@ -1242,7 +1242,7 @@ RectTransform: m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 1} m_AnchorMax: {x: 0.5, y: 1} - m_AnchoredPosition: {x: 7478.3154, y: 0.000030517578} + m_AnchoredPosition: {x: 0, y: 0.000030517578} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 1} --- !u!114 &8004702056565720367 @@ -1454,7 +1454,7 @@ RectTransform: m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 20, y: 20} m_Pivot: {x: 0.5, y: 0.5} @@ -1617,8 +1617,8 @@ MonoBehaviour: m_TargetGraphic: {fileID: 8004702056618112985} m_HandleRect: {fileID: 8004702056618112982} m_Direction: 0 - m_Value: 1 - m_Size: 0.4705884 + m_Value: 0 + m_Size: 1 m_NumberOfSteps: 0 m_OnValueChanged: m_PersistentCalls: @@ -1924,7 +1924,7 @@ RectTransform: m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 8004702057932254677} - m_RootOrder: 7 + m_RootOrder: 8 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMax: {x: 0.5, y: 0.5} @@ -2160,7 +2160,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &8004702057540368335 RectTransform: m_ObjectHideFlags: 0 @@ -2175,7 +2175,7 @@ RectTransform: m_Children: - {fileID: 8004702057798297439} m_Father: {fileID: 8004702057932254677} - m_RootOrder: 5 + m_RootOrder: 6 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 0, y: 0} @@ -2464,9 +2464,6 @@ MonoBehaviour: parameterDisplayPrefab: {fileID: 8358525157842135574, guid: 0651df442e07acf439dd439c86c20e93, type: 3} mmtAnswerPopUp: {fileID: 6618856106128302243} - currentMmtAnswer: - DynamicScrollDescriptionsActive: 1 - AutomaticHintGenerationActive: 1 --- !u!114 &8004702057798297409 MonoBehaviour: m_ObjectHideFlags: 0 @@ -2828,6 +2825,8 @@ GameObject: - component: {fileID: 8004702057932254678} - component: {fileID: 8004702057932254679} - component: {fileID: 8004702057932254676} + - component: {fileID: 3671007757941716709} + - component: {fileID: 582397463733288183} m_Layer: 5 m_Name: HidingCanvas m_TagString: Untagged @@ -2852,6 +2851,7 @@ RectTransform: - {fileID: 8004702056565337459} - {fileID: 8004702057423300230} - {fileID: 8004702058016740899} + - {fileID: 154516623474793748} - {fileID: 8004702057540368335} - {fileID: 2050004651490542596} - {fileID: 8004702056853212489} @@ -2906,7 +2906,7 @@ MonoBehaviour: m_FallbackScreenDPI: 96 m_DefaultSpriteDPI: 96 m_DynamicPixelsPerUnit: 1 - m_PresetInfoIsWorld: 1 + m_PresetInfoIsWorld: 0 --- !u!114 &8004702057932254676 MonoBehaviour: m_ObjectHideFlags: 0 @@ -2924,6 +2924,64 @@ MonoBehaviour: m_BlockingMask: serializedVersion: 2 m_Bits: 4294967295 +--- !u!114 &3671007757941716709 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8004702057932254674} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 90c1c0815499367409841816e1485ec7, type: 3} + m_Name: + m_EditorClassIdentifier: + ScrollShowUI: {fileID: 8004702057540368332} + ScrollWebView: {fileID: 5843063412347785762} +--- !u!114 &582397463733288183 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8004702057932254674} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ae310511ad607a64e891bcb46517277b, type: 3} + m_Name: + m_EditorClassIdentifier: + OnButtonClick: + m_PersistentCalls: + m_Calls: [] + HintAvailableEvent: + m_PersistentCalls: + m_Calls: [] + OnFactAssignmentUpdated: + m_PersistentCalls: + m_Calls: [] + OnMMTServerComunicationError: + m_PersistentCalls: + m_Calls: [] + OnScrollDynamicInfoError: + m_PersistentCalls: + m_Calls: [] + OnScrollApplicationError: + m_PersistentCalls: + m_Calls: [] + OnCancelErrorState: + m_PersistentCalls: + m_Calls: [] + OnScrollSolved: + m_PersistentCalls: + m_Calls: [] + OnScrollChanged: + m_PersistentCalls: + m_Calls: [] + OnScrollDynamicInfoUpdated: + m_PersistentCalls: + m_Calls: [] + DynamicScrollDescriptionsActive: 1 + AutomaticHintGenerationActive: 1 --- !u!1 &8004702058016740896 GameObject: m_ObjectHideFlags: 0 @@ -3020,7 +3078,6 @@ MonoBehaviour: ScrollButtons: [] ScrollPrefab: {fileID: 3173330253721512196, guid: a6a9a3ebdb022e546a21d9f9ff148261, type: 3} - DetailScreen: {fileID: 8004702057798297436} scrollscreenContent: {fileID: 6500467619489830996} --- !u!114 &3490402746730127523 MonoBehaviour: @@ -3398,6 +3455,164 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1001 &3129137578625191326 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + m_TransformParent: {fileID: 8004702057932254677} + m_Modifications: + - target: {fileID: 2459857651630437765, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: targetUrl + value: http://127.0.0.1:5500/scrollView.html + objectReference: {fileID: 0} + - target: {fileID: 2459857651630437765, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: PageScaleFactor + value: 4 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_Pivot.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_Pivot.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_RootOrder + value: 5 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_AnchorMax.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_SizeDelta.x + value: 890 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 8825460134736404412, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + propertyPath: m_Name + value: WebViewComponent + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 1e9d514b702f5784791a4df8d22e1866, type: 3} +--- !u!224 &154516623474793748 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 2974656142881083530, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + m_PrefabInstance: {fileID: 3129137578625191326} + m_PrefabAsset: {fileID: 0} +--- !u!1 &5843063412347785762 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 8825460134736404412, guid: 1e9d514b702f5784791a4df8d22e1866, + type: 3} + m_PrefabInstance: {fileID: 3129137578625191326} + m_PrefabAsset: {fileID: 0} +--- !u!114 &5494409561197319113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5843063412347785762} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 534d25977ad35154781c29672ce2bb13, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1001 &3298748675541104415 PrefabInstance: m_ObjectHideFlags: 0 @@ -3438,7 +3653,7 @@ PrefabInstance: - target: {fileID: 3581652732795482907, guid: 49deb83b881477047bfac0ee629a7ae9, type: 3} propertyPath: m_RootOrder - value: 6 + value: 7 objectReference: {fileID: 0} - target: {fileID: 3581652732795482907, guid: 49deb83b881477047bfac0ee629a7ae9, type: 3} @@ -3538,7 +3753,7 @@ PrefabInstance: - target: {fileID: 4838871000058222821, guid: 49deb83b881477047bfac0ee629a7ae9, type: 3} propertyPath: m_AnchoredPosition.y - value: -780 + value: 0 objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 49deb83b881477047bfac0ee629a7ae9, type: 3} diff --git a/Assets/Scenes/Worlds/RiverWorld.unity b/Assets/Scenes/Worlds/RiverWorld.unity index 45555d2b40aae99c7444d735064ca11e2d374dd8..86592f5a4eef7b1200d4fa4abe918e488bfd798d 100644 --- a/Assets/Scenes/Worlds/RiverWorld.unity +++ b/Assets/Scenes/Worlds/RiverWorld.unity @@ -38,7 +38,7 @@ RenderSettings: m_ReflectionIntensity: 1 m_CustomReflection: {fileID: 0} m_Sun: {fileID: 0} - m_IndirectSpecularColor: {r: 0.44084534, g: 0.48955458, b: 0.56959116, a: 1} + m_IndirectSpecularColor: {r: 0.4410664, g: 0.4898227, b: 0.5699191, a: 1} m_UseRadianceAmbientProbe: 0 --- !u!157 &3 LightmapSettings: @@ -39839,6 +39839,18 @@ Transform: type: 3} m_PrefabInstance: {fileID: 1858641942} m_PrefabAsset: {fileID: 0} +--- !u!114 &1860195005 stripped +MonoBehaviour: + m_CorrespondingSourceObject: {fileID: 5465760683304490972, guid: b07552db700124a4680401e6fb94c186, + type: 3} + m_PrefabInstance: {fileID: 3020720018843181009} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ae310511ad607a64e891bcb46517277b, type: 3} + m_Name: + m_EditorClassIdentifier: --- !u!1001 &1862008647 PrefabInstance: m_ObjectHideFlags: 0 @@ -63789,6 +63801,11 @@ PrefabInstance: propertyPath: m_AnchoredPosition.y value: 0 objectReference: {fileID: 0} + - target: {fileID: 8063809797576254706, guid: b07552db700124a4680401e6fb94c186, + type: 3} + propertyPath: activeScroll + value: + objectReference: {fileID: 1860195005} - target: {fileID: 8111165885733284748, guid: b07552db700124a4680401e6fb94c186, type: 3} propertyPath: m_AnchorMax.y diff --git a/Assets/Scripts/InteractionEngine/CommunicationEvents.cs b/Assets/Scripts/InteractionEngine/CommunicationEvents.cs index bca75d877d64b9cf64721dd3808db7ac66663307..f9b0f0f3fed5882dc398f2fdd52b7eb6b95bfa9c 100644 --- a/Assets/Scripts/InteractionEngine/CommunicationEvents.cs +++ b/Assets/Scripts/InteractionEngine/CommunicationEvents.cs @@ -13,20 +13,15 @@ public static class CommunicationEvents public static UnityEvent<Fact> AddFactEvent = new(); public static UnityEvent<Fact> RemoveFactEvent = new(); - public static UnityEvent<REST_JSON_API.ScrollApplicationCheckingError[]> ScrollApplicationCheckingErrorEvent = new(); - public static UnityEvent PushoutFactFailEvent = new(); - public static UnityEvent gameSucceededEvent = new(); public static UnityEvent gameNotSucceededEvent = new(); - public static UnityEvent NewAssignmentEvent = new(); public static UnityEvent StartT0Event = new(); - - public static UnityEvent<string> ScrollFactHintEvent = new(); + /** <summary>Inform ui that it should animate the given fact with the given material.</summary> */ public static UnityEvent<string, FactWrapper.FactMaterials> AnimateExistingFactEvent = new(); + /** <summary>Start firework and invoke AnimateExistingFactEvent.</summary> */ public static UnityEvent<Fact, FactWrapper.FactMaterials> AnimateExistingAsSolutionEvent = new(); + /** <summary>Show a missing fact for a short time as hint for the user.</summary> */ public static UnityEvent<Fact> AnimateNonExistingFactEvent = new(); - public static UnityEvent<List<string>> HintAvailableEvent = new(); - //------------------------------------------------------------------------------------ diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/FactObjectUI.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/FactObjectUI.cs index 7a0449d0a3cb18953becd9dbff8b867262a9b32d..e90f6cc60b78d374a3a30f15d0c3fafee9fc2516 100644 --- a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/FactObjectUI.cs +++ b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/FactObjectUI.cs @@ -1,7 +1,8 @@ +using bessw.Unity.WebView; using System.Linq; using UnityEngine.UI; -public class FactObjectUI : FactObject +public class FactObjectUI : FactObject, BrowserDropable { public Image[] Images; diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs index 6a362b1c51890dbe89f8af53b9793cc87d33d1b5..cb0f1d45327d6e11bd74542ba5cd986af97ec388 100644 --- a/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs +++ b/Assets/Scripts/InteractionEngine/FactHandling/FactWrapper/RenderedScrollFact.cs @@ -1,5 +1,6 @@ using REST_JSON_API; using System.Collections.Generic; +using System.Linq; using TMPro; using UnityEngine; using UnityEngine.EventSystems; @@ -66,9 +67,9 @@ protected override void FactUpdated() if (VerboseURI) Debug.Log(nameof(RenderedScrollFact) + " recieved Fact: " + URI); - NewAssignmentEvent.Invoke(); ResetPayload(); base.FactUpdated(); + SwitchScrollUI.activeScrollData.AssignFact(ScrollFactURI, Fact); } private void ResetPayload() @@ -97,19 +98,21 @@ protected override void _DeleteFactEvent(Fact fact) protected override void _OnEnable() { - HintAvailableEvent.AddListener(OnHintAvailable); + SwitchScrollUI.activeScrollData.HintAvailableEvent.AddListener(OnHintAvailable); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.AddListener(OnScrollUpdated); ResetPayload(); } protected override void _OnDisable() { - HintAvailableEvent.RemoveListener(OnHintAvailable); + SwitchScrollUI.activeScrollData.HintAvailableEvent.RemoveListener(OnHintAvailable); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.RemoveListener(OnScrollUpdated); } public void Populate(Scroll scroll, string scroll_fact_uri) { - _Scroll = scroll; - _ScrollFactURI = scroll_fact_uri; + ScrollFactURI = scroll_fact_uri; + Scroll = scroll; _URI = ScrollFactURI; ResetPayload(); @@ -120,12 +123,22 @@ private void SetLabel(string label) LabelMesh.text = label ?? Scroll?.requiredFacts[ID].label ?? "Err"; } + private void OnScrollUpdated(Scroll rendered) { + // this if has been copied during refactoring, I don't know if we need it^^ + if(SwitchScrollUI.activeScrollData.DynamicScrollDescriptionsActive && + rendered.requiredFacts.Any(rf => rf.@ref.uri == ScrollFactURI)) + { + // Update ScrollParameter label (side effect of setting the property "Scroll") + Scroll = rendered; + } + } + public void OnClickHintButton() { - ScrollFactHintEvent.Invoke(URI); + SwitchScrollUI.activeScrollData.ButtonClicked(new HintScrollButton(URI)); } - public void OnHintAvailable(List<string> uris) + private void OnHintAvailable(IReadOnlyList<string> uris) { HintButton.SetActive(uris.Contains(ScrollFactURI)); } diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs index 83aa7854ffc649a2b70af504e21d6049dd551aa2..1bafe7d92f05ca815c92640cde3a0a0a82075981 100644 --- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs +++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs @@ -262,6 +262,7 @@ public string GetLabel(FactRecorder name_space) ? _CustomLabel : generateLabel(name_space)); } + [JsonProperty("Label")] protected internal string _LastLabel = "NaN"; public bool SetLabel(string value, FactRecorder name_space) diff --git a/Assets/Scripts/InteractionEngine/Gadgets/GadgetBehaviour.cs b/Assets/Scripts/InteractionEngine/Gadgets/GadgetBehaviour.cs index 57c0ebacd3cbeebd2982c0f6dfcc416775274b95..2c96847470cb283ebca9b4a9bbbed5807da99206 100644 --- a/Assets/Scripts/InteractionEngine/Gadgets/GadgetBehaviour.cs +++ b/Assets/Scripts/InteractionEngine/Gadgets/GadgetBehaviour.cs @@ -5,7 +5,6 @@ using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; -using static UIconfig; public class GadgetBehaviour : MonoBehaviour, ISerializationCallbackReceiver diff --git a/Assets/Scripts/InteractionEngine/ShinyThings.cs b/Assets/Scripts/InteractionEngine/ShinyThings.cs index 37993ee77fe3c40f372e5b296bf9577d3c7823af..4d33baf625a1d63c964ca9ef048aacb508b1854f 100644 --- a/Assets/Scripts/InteractionEngine/ShinyThings.cs +++ b/Assets/Scripts/InteractionEngine/ShinyThings.cs @@ -28,13 +28,19 @@ public GameObject private void OnEnable() { - CommunicationEvents.PushoutFactFailEvent.AddListener(LetItRain); + SwitchScrollUI.OnActiveScrollDataInitialized.AddListener(OnActiveScrollDataInitialized); CommunicationEvents.AnimateExistingAsSolutionEvent.AddListener(HighlightWithFireworks); } + private void OnActiveScrollDataInitialized() + { + SwitchScrollUI.activeScrollData.OnScrollApplicationError.AddListener(LetItRain); + SwitchScrollUI.OnActiveScrollDataInitialized.RemoveListener(OnActiveScrollDataInitialized); + } + private void OnDisable() { - CommunicationEvents.PushoutFactFailEvent.RemoveListener(LetItRain); + SwitchScrollUI.activeScrollData.OnScrollApplicationError.RemoveListener(LetItRain); CommunicationEvents.AnimateExistingAsSolutionEvent.RemoveListener(HighlightWithFireworks); } @@ -117,7 +123,7 @@ IEnumerator _BlossomAndDie() } } - public void LetItRain() + public void LetItRain(REST_JSON_API.ScrollApplicationCheckingError[] _) { // check if couroutine is waiting or finished if (!rain_wait.MoveNext() || !rain.MoveNext()) diff --git a/Assets/Scripts/InventoryStuff/ActiveScroll.cs b/Assets/Scripts/InventoryStuff/ActiveScroll.cs new file mode 100644 index 0000000000000000000000000000000000000000..20d585471bd178177af92e3ca9dec507ce3c934e --- /dev/null +++ b/Assets/Scripts/InventoryStuff/ActiveScroll.cs @@ -0,0 +1,503 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using REST_JSON_API; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.Networking; + +#nullable enable annotations + +/// <summary> +/// This class keeps track of the currently active scroll and comunicates with the FrameIT Server. +/// It represents the model of the Model-View-Controler pattern. +/// </summary> +[Serializable] +public class ActiveScroll : MonoBehaviour +{ + + /** <summary>Event that is invoked when a scroll button is clicked, e.g. magic button. You can use it to handle custom buttons.</summary> */ + public UnityEvent<ScrollButton> OnButtonClick = new(); + /** <summary>Notifies about availible hints.</summary> */ + public UnityEvent<IReadOnlyList<string>> HintAvailableEvent = new(); + /** <summary>Event that is invoked when a fact has been assigned to a slot and the ui needs to update.</summary> */ + public UnityEvent<string,SlotAssignment> OnFactAssignmentUpdated = new(); + /** <summary>Event that is invoked when the MMT server returned an error.</summary> */ + public UnityEvent<string> OnMMTServerComunicationError = new(); + /** <summary>Event that is invoked when the scroll dynamic info returned errors in the current scroll assignment.</summary> */ + public UnityEvent<ScrollApplicationCheckingError[]> OnScrollDynamicInfoError = new(); + /** <summary>Event that is invoked when the scroll application returned errors in the current assignment.</summary> */ + public UnityEvent<ScrollApplicationCheckingError[]> OnScrollApplicationError = new(); + /** <summary>Event that is invoked when the OnMMTServerError or OnScrollApplicationFailed error state has been resolved and e.g. the error popup can be cloesed.</summary> */ + public UnityEvent OnCancelErrorState = new(); + /** <summary>Event that is invoked when the scroll has been solved.</summary> */ + public UnityEvent<IReadOnlyList<Fact>> OnScrollSolved = new(); + /** <summary>Event that is invoked when an other scroll has been selected.</summary> */ + public UnityEvent<Scroll> OnScrollChanged = new(); + /** <summary>Event that is invoked when the dynamic info of the scroll has been updated e.g. because a fact has been assigned.</summary> */ + public UnityEvent<Scroll> OnScrollDynamicInfoUpdated = new(); + + + public bool DynamicScrollDescriptionsActive = true; + public bool AutomaticHintGenerationActive = true; + + private readonly IReadOnlyList<string> NoDynamicScroll = new List<string>() + { + // Insert ScrollURIS that are poorly optimized + }; + + + /// <summary> + /// Variable used to block that only one SendView is running at a time. + /// </summary> + private bool SendingViewDone = true; + /// <summary> + /// this is true while a fact assignment is enqueued + /// </summary> + private bool DynamicScrollInQue = false; + /// <summary> + /// this is true while a scroll application via magic button is enqueued + /// </summary> + private bool MagicInQue = false; + private string currentMmtAnswer; + + /** <summary>List of available hints for the current partial assignment.</summary> */ + private List<Fact> LatestRenderedHints; + /** <summary>List of available auto comletions for the current partial assignment. Used to generate hints.</summary> */ + private List<ScrollAssignment> LatestBackwartsCompletions; + + private Scroll _Scroll; + /// <summary> + /// The currently active scroll + /// </summary> + public Scroll Scroll + { + get => _Scroll; + set { + _Scroll = value; + + // initialize the assignments dictionary with the references to the required fact slots as keys + // and an empty SlottAssignment + _Assignments = value.requiredFacts + .ToDictionary(fact => fact.@ref.uri, _ => new SlotAssignment()); + + // apply fact assignments that are pre defined by the stage (defaults or constrains), if there are any + if (StageStatic.stage.solution.ScrollOverwrites + .TryGetValue(value.ScrollReference, out (string, int, bool)[] population) + && population.Length > 0) + { + foreach ((string Id, int index, bool show) in population) + { + var key = value.requiredFacts[index].@ref.uri; + _Assignments[key].fact = FactRecorder.AllFacts[Id]; + _Assignments[key].IsVisible = show; + } + } + // notify the observers that the scroll has changed + OnScrollChanged.Invoke(value); + } + } + /// <summary> + /// The currently active scroll with rendered description and backward_completions (hints) + /// </summary> + public Scroll RenderedScroll { get; private set; } + + public class SlotAssignment + { + public Fact? fact = null; + public bool IsVisible = true; + public bool IsSet => fact is not null; + } + + /// <summary> + /// Maps the required facts (keys) to the assigned facts (values) + /// </summary> + private Dictionary<string, SlotAssignment> _Assignments = new(); + + /// <summary> + /// Maps the required facts (keys) to the assigned facts (values). + /// </summary> + public IReadOnlyDictionary<string, SlotAssignment> Assignments => _Assignments; + + /// <summary> + /// The ScrollView should call this method when a button is clicked + /// </summary> + public void ButtonClicked(ScrollButton button) + { + switch (button) + { + // Magic button to apply the scroll + case MagicScrollButton: + if ((Scroll is not null) && ! MagicInQue) StartCoroutine(SendScrollApplication()); + break; + case HintScrollButton: + HintButtonPressed((HintScrollButton)button); + break; + // add cases for future additional buttons here + } + // notify observers that a button was clicked + OnButtonClick.Invoke(button); + } + + /// <summary> + /// Assigns the given fact to the given slotUri and calls the OnFactAssignmentUpdated Event + /// </summary> + /// <param name="slotUri"></param> + /// <param name="fact"></param> + /// <exception cref="ArgumentException"></exception> + public void AssignFact(string slotUri, Fact fact) + { + if (Assignments.ContainsKey(slotUri)) + { + var slot = _Assignments[slotUri]; + + // return if the slot is already assigned to the given value (avoid unnecessary ui updates and frameit Server requests) + //if ((fact is null && !slot.IsSet) || (slot.IsSet && slot.fact.Id == fact.Id)) return; + if (fact is null && !slot.IsSet) return; + + slot.fact = fact; + SendCurrentFactAssignments(); + OnFactAssignmentUpdated.Invoke(slotUri, slot); + } else { + throw new ArgumentException($"Can't assign fact, the given slot doesn't exist on the current scroll: '{slotUri}'"); + } + } + + /// <summary> + /// If the fact is not already assigned, assign it to the next empty slot, otherwise unassign it. + /// And calls the OnFactAssignmentUpdated Event. + /// </summary> + /// <param name="fact"></param> + /// <returns></returns> + public string? AssignOrRemoveFactToNextEmptySlot(Fact fact) + { + // unassign the fact if it is already assigned and return + try { + var assignedSlot = _Assignments.First(pair => pair.Value.fact == fact).Key; + AssignFact(assignedSlot, null); + return null; + } catch (Exception) { + // the fact has not been assigned yet => continue + } + + // find the first empty slot and assign the fact to it + try { + KeyValuePair<string, SlotAssignment> emptySlot = _Assignments.First(pair => !pair.Value.IsSet); + AssignFact(emptySlot.Key, fact); + return emptySlot.Key; + } catch (Exception) { + return null; + } + } + + + #region MagicButton + private IEnumerator SendScrollApplication() + { + // there is already a MagicButton coroutine waiting => exit + if (MagicInQue) yield break; + + MagicInQue = true; + // wait if SendView is not yet done or dynamic scroll is in the queue + while (!SendingViewDone || DynamicScrollInQue) + yield return null; + MagicInQue = false; + + yield return SendView("/scroll/apply"); + + if (currentMmtAnswer == null) + { + // OnMMTServerComunicationError is already invoked in SendView + Debug.LogError("Magic FAILED"); + yield break; + } + else + { + if (CommunicationEvents.VerboseURI) + Debug.Log("Magic answers:\n" + currentMmtAnswer); + + System.DateTime deserializeTime = System.DateTime.UtcNow; + ScrollApplicationInfo scrollApplication = JsonConvert.DeserializeObject<ScrollApplicationInfo>(currentMmtAnswer); + Debug.LogFormat($"Answerd deserialized in : {(System.DateTime.UtcNow - deserializeTime).TotalMilliseconds}ms"); + + if (scrollApplication.acquiredFacts.Count == 0 + || scrollApplication.errors.Length > 0) + { + OnScrollApplicationError.Invoke(scrollApplication.errors); + } + else + { + OnCancelErrorState.Invoke(); + } + + var new_facts = __GenerateUnityFactsForAcquiredMMTFacts(scrollApplication.acquiredFacts); + if (scrollApplication.acquiredFacts.Count >= 0 || scrollApplication.errors.Length == 0) + { + OnScrollSolved.Invoke(new_facts); + } + } + } + + private List<Fact> __GenerateUnityFactsForAcquiredMMTFacts(List<MMTFact> pushoutFacts) + { + List<Fact> new_facts = new(); + Dictionary<string, string> old_to_new = new(); + System.DateTime parseTime = System.DateTime.UtcNow; + + bool samestep = false; + for (int i = 0; i < pushoutFacts.Count; i++) + { + List<Fact> new_list = Fact.MMTFactory(pushoutFacts[i].MapURIs(old_to_new)); + + if (new_list.Count == 0) + { + Debug.LogWarning("Parsing on pushout-fact returned empty List -> One of the dependent facts does not exist or parsing failed"); + continue; + } + + foreach (Fact new_fact in new_list) + { + Fact added = FactAdder.AddFactIfNotFound(new_fact, out bool exists, samestep, null, Scroll.label); + if (!exists) + { + new_facts.Add(added); + CommunicationEvents.AnimateExistingFactEvent.Invoke(added.Id, FactWrapper.FactMaterials.Solution); + samestep = true; + } + else + { + // AnimateExistingFactEvent.Invoke(_new, FactWrapper.FactMaterials.Hint); // Automaticly done in FactRecorder + old_to_new.Add(new_fact.Id, added.Id); + } + } + + //yield return null; + } + + Debug.Log($"Facts parsed within {(System.DateTime.UtcNow - parseTime).TotalMilliseconds}ms"); + return new_facts; + } + + #endregion MagicButton + + #region HintButton + + private void HintButtonPressed(HintScrollButton hintButton) + { + if (FactRecorder.AllFacts.ContainsKey(hintButton.SlotUri)) + { + CommunicationEvents.AnimateExistingFactEvent.Invoke( + hintButton.SlotUri, + FactWrapper.FactMaterials.Hint + ); + } + + Fact hintFact = LatestRenderedHints.Find(x => x.Id == hintButton.SlotUri); // "Dictionary" + + ScrollAssignment suitableCompletion = + LatestBackwartsCompletions.Find((ScrollAssignment x) => x.fact.uri == hintButton.SlotUri); // "Dictionary" + + if (suitableCompletion != null && suitableCompletion.assignment is OMS assignment) + { + if (FactRecorder.AllFacts.ContainsKey(assignment.uri)) + { + CommunicationEvents.AnimateExistingFactEvent.Invoke( + assignment.uri, + FactWrapper.FactMaterials.Hint + ); + } + } + else if (hintFact != null) + { + if (FactRecorder.FindEquivalent(StageStatic.stage.factState.MyFactSpace, hintFact, out string found_key, out Fact _, out bool _, false)) + // existing fact -> Animate that + CommunicationEvents.AnimateExistingFactEvent.Invoke( + found_key, + FactWrapper.FactMaterials.Hint + ); + + else + { // Generate new FactRepresentation and animate it + CommunicationEvents.AnimateNonExistingFactEvent.Invoke(hintFact); + CommunicationEvents.AnimateExistingFactEvent.Invoke( + hintButton.SlotUri, + FactWrapper.FactMaterials.Hint + ); + } + } + } + #endregion HintButton + + #region FactAssignment + + public void SendCurrentFactAssignments() + { + if (Scroll?.ScrollReference == null + || NoDynamicScroll.Contains(Scroll.ScrollReference)) + return; + + if (AutomaticHintGenerationActive || DynamicScrollDescriptionsActive) + StartCoroutine(_SendAssignments()); + } + + private IEnumerator _SendAssignments() + { + if (DynamicScrollInQue) + yield break; // only need next in que to finish + + DynamicScrollInQue = true; + while (!SendingViewDone) + yield return null; // if we dont wait => server will crash + DynamicScrollInQue = false; + + yield return SendView("/scroll/dynamic"); + + if (currentMmtAnswer == null) + { + // OnMMTServerComunicationError is already invoked in SendView + Debug.LogError("Dynamic Scroll FAILED"); + yield break; + } + else + { + ScrollDynamicInfo scrollDynamicInfo; + try + { + scrollDynamicInfo = JsonConvert.DeserializeObject<ScrollDynamicInfo>(currentMmtAnswer); + //scrollDynamicInfo = IJSONsavable<ScrollDynamicInfo>.postprocess(scrollDynamicInfo); // DON'T! will remove hints + } + catch (JsonSerializationException ex) + { + Debug.LogException(ex); + Debug.LogError("Could not Deserialize MMT aswer for /scroll/dynamic\n" + currentMmtAnswer); + OnMMTServerComunicationError.Invoke("MMT Server communication error: could not deserialize message."); + yield break; + } + + ScrollApplicationCheckingError[] errors = scrollDynamicInfo.errors + .Where(err => err.kind != "nonTotal") // expected + .ToArray(); + + if (errors.Length > 0) OnScrollDynamicInfoError.Invoke(errors); + + _ProcessScrollDynamicInfo(scrollDynamicInfo); + } + } + + private void _ProcessScrollDynamicInfo(ScrollDynamicInfo scrollDynamicInfo) + { + //TODO: more hints available in scrollDynamicInfo.rendered.requiredFacts + + LatestBackwartsCompletions = scrollDynamicInfo.backward_completions.Count > 0 + ? scrollDynamicInfo.backward_completions[0] + : new List<ScrollAssignment>(); + + List<string> hintUris = LatestBackwartsCompletions + .Select(completion => completion.fact.uri) + .ToList(); + + //Update Scroll, process data for later hints and update Uri-List for which hints are available + _processRenderedScroll(scrollDynamicInfo.rendered, hintUris); + + if (AutomaticHintGenerationActive) + //Show that Hint is available for ScrollParameter + HintAvailableEvent.Invoke(hintUris); + + return; + + void _processRenderedScroll(Scroll rendered, List<string> hintUris) + { + OnScrollDynamicInfoUpdated.Invoke(rendered); + + LatestRenderedHints = new(); + foreach (var requiredFact in rendered.requiredFacts) + { + //If ScrollFact is not assigned -> enable hint button + if (Assignments.TryGetValue(requiredFact.@ref.uri, out SlotAssignment assignedFact) && ! assignedFact.IsSet) + { + List<Fact> HintFactList = Fact.MMTFactory(requiredFact); + + foreach (Fact HintFact in HintFactList) + { + hintUris.Add(HintFact.Id); // == rendered.requiredFacts[i].@ref.uri + LatestRenderedHints.Add(HintFact); + } + } + } + + return; + } + } + + + #endregion FactAssignment + + /// <summary> + /// Only one instance of the SendView coroutine should run at a time. + /// </summary> + private IEnumerator SendView(string endpoint) + { + SendingViewDone = false; + + //while (ParameterDisplays == null) // Wait for server + // yield return null; + + string body = prepareScrollAssignments(); + + using UnityWebRequest www = UnityWebRequest.Put(CommunicationEvents.ServerAdress + endpoint, body); + www.method = UnityWebRequest.kHttpVerbPOST; + www.SetRequestHeader("Content-Type", "application/json"); + + System.DateTime sendTime = System.DateTime.UtcNow; + yield return www.SendWebRequest(); + //if (VerboseURI) + Debug.LogFormat("Server answerd in : {0}ms" + , (System.DateTime.UtcNow - sendTime).TotalMilliseconds); + + if (www.result == UnityWebRequest.Result.ConnectionError + || www.result == UnityWebRequest.Result.ProtocolError) + { + Debug.LogWarning(www.error); + currentMmtAnswer = null; + OnMMTServerComunicationError.Invoke($"Server communication error: {www.error}"); + SendingViewDone = true; + yield break; + } + else + { + while (!www.downloadHandler.isDone) + yield return null; + + currentMmtAnswer = www.downloadHandler.text + .Replace("\"float\":null", "\"float\":0.0"); // cannot convert null to value type + } + + SendingViewDone = true; + yield break; + + /// <summary>Maps the assigned slots to ScrollAssignment objects. + /// Returns json serialized ScrollApplication containing the list of ScrollAssignments.</summary> + string prepareScrollAssignments() + { + List<ScrollAssignment> assignmentList = Assignments.Where(assignment => assignment.Value.IsSet) + .Select(assignment => new ScrollAssignment(assignment.Key, assignment.Value.fact.ServerDefinition)) + .ToList(); + + return JsonConvert.SerializeObject(new ScrollApplication(Scroll.ScrollReference, assignmentList)); + } + } +} + +/// <summary> +/// Parrent class for all scroll buttons, inherit from this class to implement custom buttons. +/// </summary> +public abstract class ScrollButton {} + +public class MagicScrollButton : ScrollButton {} +public class HintScrollButton : ScrollButton +{ + public readonly string SlotUri; + public HintScrollButton(string slotUri) => SlotUri = slotUri; +} \ No newline at end of file diff --git a/Assets/Scripts/InventoryStuff/ActiveScroll.cs.meta b/Assets/Scripts/InventoryStuff/ActiveScroll.cs.meta new file mode 100644 index 0000000000000000000000000000000000000000..9098ea197710bb798ddbc60676934b8ee348d9d1 --- /dev/null +++ b/Assets/Scripts/InventoryStuff/ActiveScroll.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae310511ad607a64e891bcb46517277b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/InventoryStuff/DisplayScrolls.cs b/Assets/Scripts/InventoryStuff/DisplayScrolls.cs index a9ec4ddcd40579c81b51392a78755b72348b1695..d9c6616d47d2496ff554d8d38d969dc5d2d3845b 100644 --- a/Assets/Scripts/InventoryStuff/DisplayScrolls.cs +++ b/Assets/Scripts/InventoryStuff/DisplayScrolls.cs @@ -10,7 +10,6 @@ public class DisplayScrolls : MonoBehaviour static public List<REST_JSON_API.Scroll> AllowedScrolls; public GameObject[] ScrollButtons; public GameObject ScrollPrefab; - public GameObject DetailScreen; public Transform scrollscreenContent; @@ -35,13 +34,11 @@ void BuildScrollGUI() { var obj = Instantiate(ScrollPrefab, scrollscreenContent); obj.GetComponent<ScrollClickedScript>().scroll = AllowedScrolls[i]; - obj.GetComponent<ScrollClickedScript>().DetailScreen = this.DetailScreen; obj.transform.GetChild(0).gameObject.GetComponent<TextMeshProUGUI>().text = AllowedScrolls[i].label; ScrollButtons[i] = obj; } REST_JSON_API.Scroll preferredStartScroll = AllowedScrolls.Find(x => x.label.Equals(preferredStartScrollName)); - if (preferredStartScroll != null) - ScrollDetails.Instance?.SetScroll(preferredStartScroll); + if (preferredStartScroll != null) SwitchScrollUI.activeScrollData.Scroll = preferredStartScroll; } } diff --git a/Assets/Scripts/InventoryStuff/ScrollClickedScript.cs b/Assets/Scripts/InventoryStuff/ScrollClickedScript.cs index 50ee8f5cc4580e4a7731308fa8ddafee21525f2b..7936ebbe44968473174c1e9e2f5707ec5a86d89d 100644 --- a/Assets/Scripts/InventoryStuff/ScrollClickedScript.cs +++ b/Assets/Scripts/InventoryStuff/ScrollClickedScript.cs @@ -5,10 +5,9 @@ public class ScrollClickedScript : MonoBehaviour, IPointerDownHandler { public Scroll scroll; - public GameObject DetailScreen; public void OnPointerDown(PointerEventData eventData) { - this.DetailScreen.GetComponent<ScrollDetails>().SetScroll(this.scroll); + SwitchScrollUI.activeScrollData.Scroll = this.scroll; } } diff --git a/Assets/Scripts/InventoryStuff/ScrollDetails.cs b/Assets/Scripts/InventoryStuff/ScrollDetails.cs deleted file mode 100644 index 0b0afd18ea4fd37ab8b5c33d2246f2d325bb2156..0000000000000000000000000000000000000000 --- a/Assets/Scripts/InventoryStuff/ScrollDetails.cs +++ /dev/null @@ -1,446 +0,0 @@ -using Newtonsoft.Json; -using REST_JSON_API; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using TMPro; -using UnityEngine; -using UnityEngine.Networking; -using static CommunicationEvents; - -public class ScrollDetails : MonoBehaviour -{ - public static ScrollDetails Instance - { - get => _Instance; - set - { - if (_Instance != value) - Destroy(_Instance); - - _Instance = value; - } - } - private static ScrollDetails _Instance; - - public WorldCursor cursor; - public GameObject parameterDisplayPrefab; - public static Scroll ActiveScroll { get; private set; } - public GameObject mmtAnswerPopUp; - private PopupBehavior Popup; - - public static List<RenderedScrollFact> ParameterDisplays { get; private set; } - private static List<ScrollAssignment> LatestBackwartsCompletions; - private static List<Fact> LatestRenderedHints; - - public string currentMmtAnswer; - - public bool DynamicScrollDescriptionsActive = true; - public bool AutomaticHintGenerationActive = true; - - private bool SendingViewDone = true; - private bool DynamicScrollInQue = false; - private bool MagicInQue = false; - - private readonly IReadOnlyList<string> NoDynamicScroll = new List<string>() - { - // Insert ScrollURIS that are poorly optimized - }; - - void Awake() - { - Instance = this; - - if (cursor == null) - cursor = FindObjectOfType<WorldCursor>(); - - Popup = mmtAnswerPopUp.GetComponent<PopupBehavior>(); - Popup.gameObject.SetActive(true); // force Awake - } - - private void OnEnable() - { - ScrollFactHintEvent.AddListener(animateHint); - NewAssignmentEvent.AddListener(NewAssignmentTrigger); - } - - private void OnDisable() - { - ScrollFactHintEvent.RemoveListener(animateHint); - NewAssignmentEvent.RemoveListener(NewAssignmentTrigger); - } - - private void OnDestroy() - { - _Instance = null; - } - - public void SetScroll(Scroll scroll_to_set) - { - ActiveScroll = scroll_to_set; - - Transform originalScroll = gameObject.transform.GetChild(1); - Transform originalScrollView = originalScroll.GetChild(1); - Transform originalViewport = originalScrollView.GetChild(0); - - //Clear all current ScrollFacts - originalViewport.GetChild(0).gameObject.DestroyAllChildren(); - - originalScroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = ActiveScroll.description; - - //ParameterDisplays.ForEach(gameObj => Destroy(gameObj)); - ParameterDisplays = new(); - for (int i = 0; i < ActiveScroll.requiredFacts.Count; i++) - { - GameObject originalObj = - Instantiate(parameterDisplayPrefab, originalViewport.GetChild(0)); - - RenderedScrollFact originalRSF = - originalObj.GetComponentInChildren<RenderedScrollFact>(); - - ParameterDisplays.Add(originalRSF); - - originalRSF.Populate(ActiveScroll, ActiveScroll.requiredFacts[i].@ref.uri); - } - - if (StageStatic.stage.solution.ScrollOverwrites - .TryGetValue(ActiveScroll.ScrollReference, out (string, int, bool)[] population) - && population.Length > 0) - { - DynamicScrollInQue = true; // block update on population - - foreach ((string Id, int index, bool show) in population) - { - ParameterDisplays[index].URI = Id; - ParameterDisplays[index].transform.parent.gameObject.SetActive(show); - } - - DynamicScrollInQue = false; // unblock - } - - NewAssignmentEvent.Invoke(); // init display - } - - public bool SetNextEmptyTo(FactObjectUI activator) - { - RenderedScrollFact check = ParameterDisplays - .Find(RSF => RSF != null - && RSF.Payload != null - && RSF.Payload.Equals(activator)); - - if (check != null) - { - check.URI = null; - return false; - } - - RenderedScrollFact empty = ParameterDisplays - .Find(RSF => !RSF.IsSet); - - if (empty == null) - return false; - - empty.SetByFactObject(activator); - return true; - } - - public void MagicButtonTrigger() - { - if (ActiveScroll == null) - return; - - StartCoroutine(_MagicButton()); - - IEnumerator _MagicButton() - { - if (MagicInQue) - yield break; // only need next in que to finish - - MagicInQue = true; - while (!SendingViewDone || DynamicScrollInQue) - yield return null; // Wait for last assignment - MagicInQue = false; - - yield return SendView("/scroll/apply"); - - if (currentMmtAnswer == null) - { - Debug.LogError("Magic FAILED"); - ScrollApplicationCheckingErrorEvent.Invoke(null); - } - else - { - if (VerboseURI) - Debug.Log("Magic answers:\n" + currentMmtAnswer); - - System.DateTime serializeTime = System.DateTime.UtcNow; - ScrollApplicationInfo pushout = JsonConvert.DeserializeObject<ScrollApplicationInfo>(currentMmtAnswer); - Debug.LogFormat($"Answerd serialized in : {(System.DateTime.UtcNow - serializeTime).TotalMilliseconds}ms"); - - if (pushout.acquiredFacts.Count == 0 - || pushout.errors.Length > 0) - { - ScrollApplicationCheckingErrorEvent.Invoke(pushout.errors); - PushoutFactFailEvent.Invoke(); - } - else - Popup.HidePopUp(); //close error Window - - yield return __GeneratePushoutFacts(pushout.acquiredFacts); - } - } - - IEnumerator __GeneratePushoutFacts(List<MMTFact> pushoutFacts) - { - List<Fact> new_facts = new(); - Dictionary<string, string> old_to_new = new(); - System.DateTime parseTime = System.DateTime.UtcNow; - - bool samestep = false; - for (int i = 0; i < pushoutFacts.Count; i++) - { - List<Fact> new_list = Fact.MMTFactory(pushoutFacts[i].MapURIs(old_to_new)); - - if (new_list.Count == 0) - { - Debug.LogWarning("Parsing on pushout-fact returned empty List -> One of the dependent facts does not exist or parsing failed"); - continue; - } - - foreach (Fact new_fact in new_list) - { - Fact added = FactAdder.AddFactIfNotFound(new_fact, out bool exists, samestep, null, ActiveScroll.label); - if (!exists) - { - new_facts.Add(added); - AnimateExistingFactEvent.Invoke(added.Id, FactWrapper.FactMaterials.Solution); - samestep = true; - } - else - { - // AnimateExistingFactEvent.Invoke(_new, FactWrapper.FactMaterials.Hint); // Automaticly done in FactRecorder - old_to_new.Add(new_fact.Id, added.Id); - } - } - - //yield return null; - } - - Debug.Log($"Facts parsed within {(System.DateTime.UtcNow - parseTime).TotalMilliseconds}ms"); - yield break; - } - } - - public void NewAssignmentTrigger() - { - //return; //if you read this, delete this line! - - if (ActiveScroll?.ScrollReference == null - || NoDynamicScroll.Contains(ActiveScroll.ScrollReference)) - return; - - if (AutomaticHintGenerationActive || DynamicScrollDescriptionsActive) - StartCoroutine(_NewAssignment()); - - IEnumerator _NewAssignment() - { - if (DynamicScrollInQue) - yield break; // only need next in que to finish - - DynamicScrollInQue = true; - while (!SendingViewDone) - yield return null; // if we dont wait => server will crash - DynamicScrollInQue = false; - - yield return SendView("/scroll/dynamic"); - - if (currentMmtAnswer == null) - { - Debug.LogError("Dynamic Scroll FAILED"); - } - else - { - ScrollDynamicInfo scrollDynamicInfo; - try - { - scrollDynamicInfo = JsonConvert.DeserializeObject<ScrollDynamicInfo>(currentMmtAnswer); - //scrollDynamicInfo = IJSONsavable<ScrollDynamicInfo>.postprocess(scrollDynamicInfo); // DON'T! will remove hints - } - catch (JsonSerializationException ex) - { - Debug.LogException(ex); - Debug.LogError("Could not Deserialize MMT aswer for /scroll/dynamic\n" + currentMmtAnswer); - yield break; - } - - ScrollApplicationCheckingError[] errors = scrollDynamicInfo.errors - .Where(err => err.kind != "nonTotal") // expected - .ToArray(); - - if (errors.Length > 0) - ScrollApplicationCheckingErrorEvent.Invoke(errors); - - processScrollDynamicInfo(scrollDynamicInfo); - } - } - } - - private IEnumerator SendView(string endpoint) - { - SendingViewDone = false; - - while (ParameterDisplays == null) // Wait for server - yield return null; - - string body = prepareScrollAssignments(); - - using UnityWebRequest www = UnityWebRequest.Put(ServerAdress + endpoint, body); - www.method = UnityWebRequest.kHttpVerbPOST; - www.SetRequestHeader("Content-Type", "application/json"); - - System.DateTime sendTime = System.DateTime.UtcNow; - yield return www.SendWebRequest(); - //if (VerboseURI) - Debug.LogFormat("Server answerd in : {0}ms" - , (System.DateTime.UtcNow - sendTime).TotalMilliseconds); - - if (www.result == UnityWebRequest.Result.ConnectionError - || www.result == UnityWebRequest.Result.ProtocolError) - { - Debug.LogWarning(www.error); - currentMmtAnswer = null; - } - else - { - while (!www.downloadHandler.isDone) - yield return null; - - currentMmtAnswer = www.downloadHandler.text - .Replace("\"float\":null", "\"float\":0.0"); // cannot convert null to value type - } - - SendingViewDone = true; - yield break; - - string prepareScrollAssignments() - { - List<ScrollAssignment> assignmentList = new(); - - for (int i = 0; i < ParameterDisplays.Count; i++) - { - Fact tempFact = ParameterDisplays[i].Fact; - if (tempFact != null) - assignmentList.Add(new ScrollAssignment(ActiveScroll.requiredFacts[i].@ref.uri, tempFact.Id)); - } - - return JsonConvert.SerializeObject(new ScrollApplication(ActiveScroll.ScrollReference, assignmentList)); - } - } - - private void processScrollDynamicInfo(ScrollDynamicInfo scrollDynamicInfo) - { - //TODO: more hints available in scrollDynamicInfo.rendered.requiredFacts - - LatestBackwartsCompletions = scrollDynamicInfo.backward_completions.Count > 0 - ? scrollDynamicInfo.backward_completions[0] - : new List<ScrollAssignment>(); - - List<string> hintUris = LatestBackwartsCompletions - .Select(completion => completion.fact.uri) - .ToList(); - - //Update Scroll, process data for later hints and update Uri-List for which hints are available - _processRenderedScroll(scrollDynamicInfo.rendered, hintUris); - - if (AutomaticHintGenerationActive) - //Show that Hint is available for ScrollParameter - HintAvailableEvent.Invoke(hintUris); - - return; - - void _processRenderedScroll(Scroll rendered, List<string> hintUris) - { - if (DynamicScrollDescriptionsActive) - { // Update scroll-description - Transform scroll = gameObject.transform.GetChild(1).transform; - scroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = rendered.description; - } - - LatestRenderedHints = new(); - for (int i = 0; i < rendered.requiredFacts.Count; i++) - { - RenderedScrollFact RenderedScrollFact = ParameterDisplays - .Find(RSF => RSF.ScrollFactURI == rendered.requiredFacts[i].@ref.uri); - - if (RenderedScrollFact == null) - { // e.g. FUNCs - //if(CommunicationEvents.VerboseScroll) - // Debug.Log($"Descrapancy between requiredFacts and displayed facts:" + - // $"Could not find display with ref: {rendered.requiredFacts[i].@ref.uri}"); - continue; - } - - if (DynamicScrollDescriptionsActive) - //Update ScrollParameter label - RenderedScrollFact.Scroll = rendered; - - //If ScrollFact is assigned -> No Hint - if (!RenderedScrollFact.IsSet) - { - List<Fact> HintFactList = Fact.MMTFactory(rendered.requiredFacts[i]); - - foreach (Fact HintFact in HintFactList) - { - hintUris.Add(HintFact.Id); // == rendered.requiredFacts[i].@ref.uri - LatestRenderedHints.Add(HintFact); - } - } - } - - return; - } - } - - public void animateHint(string scrollParameterUri) - { - if (FactRecorder.AllFacts.ContainsKey(scrollParameterUri)) - AnimateExistingFactEvent.Invoke( - scrollParameterUri, - FactWrapper.FactMaterials.Hint - ); - - Fact hintFact = LatestRenderedHints.Find(x => x.Id == scrollParameterUri); // "Dictionary" - - ScrollAssignment suitableCompletion = - LatestBackwartsCompletions.Find((ScrollAssignment x) => x.fact.uri == scrollParameterUri); // "Dictionary" - - if (suitableCompletion != null && suitableCompletion.assignment is OMS assignment) - { - if (FactRecorder.AllFacts.ContainsKey(assignment.uri)) - { - AnimateExistingFactEvent.Invoke( - assignment.uri, - FactWrapper.FactMaterials.Hint - ); - } - } - else if (hintFact != null) - { - if (FactRecorder.FindEquivalent(StageStatic.stage.factState.MyFactSpace, hintFact, out string found_key, out Fact _, out bool _, false)) - // existing fact -> Animate that - AnimateExistingFactEvent.Invoke( - found_key, - FactWrapper.FactMaterials.Hint - ); - - else - { // Generate new FactRepresentation and animate it - AnimateNonExistingFactEvent.Invoke(hintFact); - AnimateExistingFactEvent.Invoke( - scrollParameterUri, - FactWrapper.FactMaterials.Hint - ); - } - } - } -} diff --git a/Assets/Scripts/Loading/StreamingAssetLoader.cs b/Assets/Scripts/Loading/StreamingAssetLoader.cs index 0f5d00a1a2f6012347fa190ff88664de463e3cba..e8ad2dfa932003f47d6c0f271bbe1c622e765680 100644 --- a/Assets/Scripts/Loading/StreamingAssetLoader.cs +++ b/Assets/Scripts/Loading/StreamingAssetLoader.cs @@ -142,6 +142,7 @@ public static void NetworkJSON_Save() myObject.camRotatingSensitivity = UIconfig.camRotatingSensitivity; myObject.MouseKeepingInWindow = UIconfig.MouseKeepingInWindow; myObject.scrolldirection = UIconfig.scrolldirection; + myObject.scrollViewVersion = UIconfig.scrollViewVersion; @@ -478,6 +479,10 @@ public static void NetworkJSON_Load_x(string path) { UIconfig.scrolldirection = myObjs.scrolldirection; } + if (! string.IsNullOrEmpty(myObjsOnlyStrings.scrollViewVersion)) + { + UIconfig.scrollViewVersion = myObjs.scrollViewVersion; + } } diff --git a/Assets/Scripts/UI/FactExplorer/OpenFactExplorer.cs b/Assets/Scripts/UI/FactExplorer/OpenFactExplorer.cs index 4f1afd71217476405c1192363a2be484336b2112..f407a6c7723059f5a1123af6b129e17aaad7161a 100644 --- a/Assets/Scripts/UI/FactExplorer/OpenFactExplorer.cs +++ b/Assets/Scripts/UI/FactExplorer/OpenFactExplorer.cs @@ -109,7 +109,7 @@ private void DoOpenFactExplorer() } private bool DoSetActive() - => ScrollDetails.Instance.SetNextEmptyTo(CachedFactWrapper as FactObjectUI); + => SwitchScrollUI.activeScrollData.AssignOrRemoveFactToNextEmptySlot(CachedFactWrapper.Fact) is not null; #endregion Implementation } diff --git a/Assets/Scripts/UI/HideUI_mobile.cs b/Assets/Scripts/UI/HideUI_mobile.cs index 6dc8e19d776412227474451adcb734717ae06d13..face97d01a5249fd56be092a0936009bdb7020ba 100644 --- a/Assets/Scripts/UI/HideUI_mobile.cs +++ b/Assets/Scripts/UI/HideUI_mobile.cs @@ -3,7 +3,6 @@ using UnityEngine.InputSystem; using static CommunicationEvents; using static UIconfig; -using static updateMouseCursor; public class HideUI_mobile : MonoBehaviour { diff --git a/Assets/Scripts/UI/InGame/PopupBehavior.cs b/Assets/Scripts/UI/InGame/PopupBehavior.cs index 6685ced25ec25e476f35190ac058fce7e44508f6..6ef35929273be86489540383caf4c3b4ff452e16 100644 --- a/Assets/Scripts/UI/InGame/PopupBehavior.cs +++ b/Assets/Scripts/UI/InGame/PopupBehavior.cs @@ -24,10 +24,25 @@ public string MessageText private string errorMessage; #region UnityMethods - void Awake() + + void OnEnable() { - CommunicationEvents.ScrollApplicationCheckingErrorEvent.AddListener(OnFailedScrollInput); + SwitchScrollUI.activeScrollData.OnMMTServerComunicationError.AddListener(OnShowErrorMessage); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoError.AddListener(OnFailedScrollInput); + SwitchScrollUI.activeScrollData.OnScrollApplicationError.AddListener(OnFailedScrollInput); + SwitchScrollUI.activeScrollData.OnCancelErrorState.AddListener(HidePopUp); + } + void OnDisable() + { + SwitchScrollUI.activeScrollData.OnMMTServerComunicationError.RemoveListener(OnShowErrorMessage); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoError.RemoveListener(OnFailedScrollInput); + SwitchScrollUI.activeScrollData.OnScrollApplicationError.RemoveListener(OnFailedScrollInput); + SwitchScrollUI.activeScrollData.OnCancelErrorState.RemoveListener(HidePopUp); + } + + void Awake() + { CloseButton.onClick.RemoveAllListeners(); CloseButton.onClick.AddListener(HidePopUp); @@ -60,6 +75,15 @@ public void OnFailedScrollInput(ScrollApplicationCheckingError[] errorInfo) MessageText = generateHelpfulMessageAndAnimateScrollParam(errorInfo); ShowTimedPopUp(); } + /// <summary> + /// this method gets an error message as parameter and shows it in a popup. + /// </summary> + /// <param name="errorMsg"></param> + public void OnShowErrorMessage(string errorMsg) + { + MessageText = errorMsg; + ShowTimedPopUp(); + } private string generateHelpfulMessageAndAnimateScrollParam(ScrollApplicationCheckingError[] errorInfo) { @@ -141,7 +165,7 @@ private MMTFact parseFactFromError(ScrollApplicationCheckingError error) factUri += "?" + factLabel; //find the required fact in the active scroll thats invalidly assigned - return ScrollDetails.ActiveScroll?.requiredFacts + return SwitchScrollUI.activeScrollData.Scroll.requiredFacts .Find(decl => decl.@ref.uri == error.fact.uri); } } diff --git a/Assets/Scripts/UI/InGame/ScrollDetails.cs b/Assets/Scripts/UI/InGame/ScrollDetails.cs new file mode 100644 index 0000000000000000000000000000000000000000..0ff048e7ede4f73f4ce5a498980fd295a013edf3 --- /dev/null +++ b/Assets/Scripts/UI/InGame/ScrollDetails.cs @@ -0,0 +1,121 @@ +using REST_JSON_API; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using TMPro; +using UnityEngine; + +public class ScrollDetails : ScrollView +{ + public static ScrollDetails Instance + { + get => _Instance; + set + { + if (_Instance != value) + Destroy(_Instance); + + _Instance = value; + } + } + private static ScrollDetails _Instance; + + public WorldCursor cursor; + public GameObject parameterDisplayPrefab; + public GameObject mmtAnswerPopUp; + private PopupBehavior Popup; + + public static List<RenderedScrollFact> ParameterDisplays { get; private set; } + + void Awake() + { + Instance = this; + + if (cursor == null) cursor = FindObjectOfType<WorldCursor>(); + + Popup = mmtAnswerPopUp.GetComponent<PopupBehavior>(); + Popup.gameObject.SetActive(true); // force Awake + } + + private void OnEnable() + { + SwitchScrollUI.activeScrollData.OnScrollChanged.AddListener(ShowScroll); + SwitchScrollUI.activeScrollData.OnFactAssignmentUpdated.AddListener(OnFactAssignmentUpdated); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.AddListener(UpdateScrollDescription); + } + + private void OnDisable() + { + SwitchScrollUI.activeScrollData.OnScrollChanged.RemoveListener(ShowScroll); + SwitchScrollUI.activeScrollData.OnFactAssignmentUpdated.RemoveListener(OnFactAssignmentUpdated); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.RemoveListener(UpdateScrollDescription); + } + + private void OnDestroy() + { + _Instance = null; + } + + /// <summary> + /// Update the scroll details screen to display the currently active scroll + /// </summary> + /// <param name="activeScroll"></param> + private void ShowScroll(Scroll newScroll) + { + Transform originalScroll = gameObject.transform.GetChild(1); + Transform originalScrollView = originalScroll.GetChild(1); + Transform originalViewport = originalScrollView.GetChild(0); + + //Clear all current ScrollFacts + originalViewport.GetChild(0).gameObject.DestroyAllChildren(); + + var description = newScroll.description; + // if description is a html description, extract the alternative text representation + if (Regex.IsMatch(newScroll.description, ".*<scroll-description.*")) + { + description = Regex.Match(newScroll.description, "<scroll-description [^>]* alt=((?>\\\")|(?>\\'))([^>]*?)\\1[^>]*>").Groups[2].Value; + } + originalScroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = description; + + //ParameterDisplays.ForEach(gameObj => Destroy(gameObj)); + ParameterDisplays = new(); + // generate parameter display slots + foreach (var slot in SwitchScrollUI.activeScrollData.Assignments) + { + GameObject originalObj = + Instantiate(parameterDisplayPrefab, originalViewport.GetChild(0)); + + RenderedScrollFact originalRSF = + originalObj.GetComponentInChildren<RenderedScrollFact>(); + + ParameterDisplays.Add(originalRSF); + + originalRSF.Populate(newScroll, slot.Key); + originalRSF.transform.parent.gameObject.SetActive(slot.Value.IsVisible); + } + } + + private void UpdateScrollDescription(Scroll rendered) + { + if (SwitchScrollUI.activeScrollData.DynamicScrollDescriptionsActive) + { // Update scroll-description + Transform scroll = gameObject.transform.GetChild(1).transform; + scroll.GetChild(0).GetComponent<TextMeshProUGUI>().text = rendered.description; + } + } + + private void OnFactAssignmentUpdated(string slotUri, ActiveScroll.SlotAssignment slotAssignment) + { + RenderedScrollFact changed = ParameterDisplays.Find(RSF => RSF.ScrollFactURI == slotUri); + + // check if the RenderedScrollFact already contains the assigend fact + // this is to prevent an endless loop because updating the Fact property will trigger the NewAssignmentEvent + // TODO: BE: find an other solution beacause this results in requesting the scroll dynamic update twice from the server + if (changed != null && ( + (!slotAssignment.IsSet && changed.IsSet) || + (slotAssignment.IsSet && changed.URI != slotAssignment.fact?.Id) + )) + { + changed.Fact = slotAssignment.fact; + } + } +} diff --git a/Assets/Scripts/InventoryStuff/ScrollDetails.cs.meta b/Assets/Scripts/UI/InGame/ScrollDetails.cs.meta similarity index 100% rename from Assets/Scripts/InventoryStuff/ScrollDetails.cs.meta rename to Assets/Scripts/UI/InGame/ScrollDetails.cs.meta diff --git a/Assets/Scripts/UI/InGame/ScrollView.cs b/Assets/Scripts/UI/InGame/ScrollView.cs new file mode 100644 index 0000000000000000000000000000000000000000..e3e95c89aa3afbb1265ac06b89ee31f05f2de1c7 --- /dev/null +++ b/Assets/Scripts/UI/InGame/ScrollView.cs @@ -0,0 +1,5 @@ +using UnityEngine; + +public abstract class ScrollView : MonoBehaviour +{ +} diff --git a/Assets/Scripts/UI/InGame/ScrollView.cs.meta b/Assets/Scripts/UI/InGame/ScrollView.cs.meta new file mode 100644 index 0000000000000000000000000000000000000000..29da970a91abe10cbf192b20ffd7a0cbc15be4bf --- /dev/null +++ b/Assets/Scripts/UI/InGame/ScrollView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01651b93334ae6f46a3b05f7cfe34543 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/InGame/SwitchScrollUI.cs b/Assets/Scripts/UI/InGame/SwitchScrollUI.cs new file mode 100644 index 0000000000000000000000000000000000000000..2d6c39b947c32a078e722f40158686a7b5697c62 --- /dev/null +++ b/Assets/Scripts/UI/InGame/SwitchScrollUI.cs @@ -0,0 +1,38 @@ +using UnityEngine; +using UnityEngine.Events; + +public class SwitchScrollUI : MonoBehaviour +{ + /// <summary> + /// Reference to the data of the active scroll displayed in the scroll UI + /// </summary> + public static ActiveScroll activeScrollData; + public static UnityEvent OnActiveScrollDataInitialized = new(); + + public GameObject ScrollShowUI; + public GameObject ScrollWebView; + + private void Awake() + { + activeScrollData = GetComponent<ActiveScroll>(); + OnActiveScrollDataInitialized.Invoke(); + } + void OnEnable() + { + switch (UIconfig.scrollViewVersion) + { + case UIconfig.ScrollViewVersion.ScrollShow: + ScrollWebView.SetActive(false); + ScrollShowUI.SetActive(true); + break; + case UIconfig.ScrollViewVersion.ScrollWebView: + ScrollShowUI.SetActive(false); + ScrollWebView.SetActive(true); + break; + default: + ScrollShowUI.SetActive(false); + ScrollWebView.SetActive(true); + break; + } + } +} diff --git a/Assets/Scripts/UI/InGame/SwitchScrollUI.cs.meta b/Assets/Scripts/UI/InGame/SwitchScrollUI.cs.meta new file mode 100644 index 0000000000000000000000000000000000000000..4adc3448cdf51e8610c52c7b028dc37f257f3f7c --- /dev/null +++ b/Assets/Scripts/UI/InGame/SwitchScrollUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90c1c0815499367409841816e1485ec7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/InGame/WebViewController.cs b/Assets/Scripts/UI/InGame/WebViewController.cs new file mode 100644 index 0000000000000000000000000000000000000000..f6b3c582fc82d249e0b533dc74a78104e5614c46 --- /dev/null +++ b/Assets/Scripts/UI/InGame/WebViewController.cs @@ -0,0 +1,265 @@ +using bessw.Unity.WebView; +using bessw.Unity.WebView.ChromeDevTools; +using bessw.Unity.WebView.ChromeDevTools.Protocol.DOM; +using MoreLinq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using REST_JSON_API; +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using UnityEngine; + +public class WebViewController : ScrollView +{ + private WebViewComponent webViewComponent; + private DomNodeWrapper[] dropzones; + + private void Awake() + { + Debug.LogWarning("awake Webview Controller"); + webViewComponent = GetComponent<WebViewComponent>(); + WebViewComponent.serializerSettings.Converters.Add(new FactObjectUIConverter()); + webViewComponent.targetUrl = Path.Join(CommunicationEvents.Get_DataPath(), "scrollView.html"); + webViewComponent.OnWebViewComponentReady += OnWebViewComponentReady; + + // TODO: handle webViewComponent.onDomDocumentUpdated + } + private void OnWebViewComponentReady() + { + webViewComponent.onDomDocumentUpdated += DocumentUpdatedHandler; + SwitchScrollUI.activeScrollData.OnScrollChanged.AddListener(SetScrollContent); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.AddListener(SetScrollContent); + SwitchScrollUI.activeScrollData.HintAvailableEvent.AddListener(OnHintAvailable); + webViewComponent.tab.AddJSBinding("applyScroll", ApplyScrollHandler); + webViewComponent.tab.AddJSBinding("getHint", GetHintHandler); + if (SwitchScrollUI.activeScrollData.Scroll is not null) + { + SetScrollContent(SwitchScrollUI.activeScrollData.Scroll); + } + RegisterBrowserEventhandlers(); + } + private void OnDisable() + { + webViewComponent.onDomDocumentUpdated -= DocumentUpdatedHandler; + SwitchScrollUI.activeScrollData.OnScrollChanged.RemoveListener(SetScrollContent); + SwitchScrollUI.activeScrollData.OnScrollDynamicInfoUpdated.RemoveListener(SetScrollContent); + webViewComponent.tab.RemoveJSBinding("applyScroll"); + webViewComponent.tab.RemoveJSBinding("getHint"); + DeRegisterBrowserEventhandlers(); + } + + private void DocumentUpdatedHandler(documentUpdatedEvent _) + { + // all old DomNodeWrapper objects are invalid, because the whole document has been updated + dropzones = null; + RegisterBrowserEventhandlers(); + } + + private async void RegisterBrowserEventhandlers() + { + // register js event handlers in the browser + _ = webViewComponent.tab.Evaluate("addDropZoneEventListeners()"); + + // register c# event handlers + // get the dropzones from the scroll and add the event handler to track when something is dropped + DomNodeWrapper document = await webViewComponent.tab.Document; + dropzones = await document.querySelectorAllAsync("[dropzone='copy']"); + dropzones.ForEach(dropzone => dropzone.OnAttributeModified += DropzoneAttributeModifiedHandler); + } + + private void DeRegisterBrowserEventhandlers() + { + dropzones?.ForEach(dropzone => dropzone.OnAttributeModified -= DropzoneAttributeModifiedHandler); + } + + /// <summary> + /// sets or updates the content of the scroll container dom element + /// </summary> + /// <param name="scrollHTML"></param> + private async void SetScrollContent(Scroll scroll) + { + // update scroll container content + DomNodeWrapper document = await webViewComponent.tab.Document; + DomNodeWrapper scrollContainer = await document.querySelectorAsync("#scrollContainer"); + + var description = scroll.description; + if (Regex.IsMatch(description, ".*<scroll-description.*")) + { + // replace slot templates + description = Regex.Replace(description, "<scroll-slot([^>]*)>([^<]*)</scroll-slot>", match => + { + var extraAttributes = match.Groups[1].Value; + var slotId = match.Groups[2].Value; + var assignment = SwitchScrollUI.activeScrollData.Assignments[slotId]; + /** label of the assigned fact, or the slot label if nothing assigned */ + var label = assignment.IsSet ? assignment.fact.GetLabel(StageStatic.stage.factState) : scroll.requiredFacts.Find(fact => fact.@ref.uri == slotId).label; + return $"<mi dropzone='copy' data-slot-id='{slotId}' {(assignment.IsSet ? $"data-fact-id='{assignment.fact.Id}'" : "")} {extraAttributes}>{label}</mi>"; + }); + // replace solution templates + description = Regex.Replace(description, "<scroll-solution([^>]*)>([^<]*)</scroll-solution>", match => + { + var extraAttributes = match.Groups[1].Value; + var solutionId = match.Groups[2].Value; + return $"<mi data-solution-id='{solutionId}' {extraAttributes}>{scroll.acquiredFacts.Find(fact => fact.@ref.uri == solutionId).label}</mi>"; + }); + } + else + { + // scroll is a lagacy plain text scroll, generate html with slots for the required facts + var factSlots = SwitchScrollUI.activeScrollData.Assignments + .Where(pair => pair.Value.IsVisible) + .Select(pair => + @$"<span class='lagacySlot' dropzone='copy' data-slot-id='{pair.Key}' {(pair.Value.IsSet ? $"data-fact-id='{pair.Value.fact.Id}'" : "")}> + {(pair.Value.IsSet ? + pair.Value.fact.GetLabel(StageStatic.stage.factState) : + scroll.requiredFacts.Find(fact => fact.@ref.uri == pair.Key).label )} + </span>"); + + description = $"<scroll-description><p>{scroll.description}</p><div id='lagacySlots'>{String.Join("", factSlots)}</div></scroll-description>"; + } + // display the scroll description + dropzones = null; + await scrollContainer.setOuterHtmlAsync($"<div id='scrollContainer'>{description}</div>"); + + RegisterBrowserEventhandlers(); + } + + private async void DropzoneAttributeModifiedHandler(attributeModifiedEvent attributeModifiedEvent) + { + Debug.LogWarning($"dropzoneAtrributeModifiedHandler: '{attributeModifiedEvent.name}'"); + + // call the onFactAssignment event if the data-fact-id attribute was modified + if (attributeModifiedEvent.name == "data-fact-id") + { + // get the slot id + var node = await webViewComponent.tab.GetNode(attributeModifiedEvent.nodeId); + if (! (node.Node.attributes.TryGetValue("data-slot-id", out string slot) + || (await node.getAttributesAsync()).TryGetValue("data-slot-id", out slot))) + { + Debug.LogError($"dropzoneAtrributeModifiedHandler: data-slot-id attribute not found on dropzone"); + throw new Exception("data-slot-id attribute not found on dropzone"); + } + + // if fact has been unasigned from the scroll + if (attributeModifiedEvent.value == "null") + { + // remove fact from slot + SwitchScrollUI.activeScrollData.AssignFact(slot, null); + return; + } + + // get the fact from the fact id + if (!FactRecorder.AllFacts.TryGetValue(attributeModifiedEvent.value, out Fact fact)) + { + Debug.LogError($"dropzoneAtrributeModifiedHandler: fact with id '{attributeModifiedEvent.value}' not found"); + throw new Exception($"fact with id '{attributeModifiedEvent.value}' not found"); + } + + // assign fact to slot + SwitchScrollUI.activeScrollData.AssignFact(slot, fact); + } + } + + private async void OnHintAvailable(IReadOnlyList<string> url) + { + dropzones = await (await webViewComponent.tab.Document).querySelectorAllAsync("[dropzone='copy']"); + foreach (var dropzone in dropzones) + { + if (url.Contains(dropzone.Node.attributes["data-slot-id"])) + { + _ = dropzone.setAttributeValue("data-hint-available", "true"); + } + else if (dropzone.Node.attributes.ContainsKey("data-hint-available")) + { + _ = dropzone.removeAttributeAsync("data-hint-available"); + } + } + } + + private void ApplyScrollHandler(string button) + { + SwitchScrollUI.activeScrollData.ButtonClicked(new MagicScrollButton()); + } + + private void GetHintHandler(string url) + { + SwitchScrollUI.activeScrollData.ButtonClicked(new HintScrollButton(url)); + } + + public string[] GetFactAssignments() + { + return dropzones.Select(dropzone => dropzone.Node.attributes.GetValueOrDefault("data-fact-id", null)).ToArray(); + } + + [Obsolete()] + private async void GetDropzoneStateAsync() + { + // alternative way to get the dropzone state + DomNodeWrapper document = await DomNodeWrapper.getDocumentAsync(webViewComponent.tab); + Debug.LogWarning($"dropzone 1: '{document}'"); + var dropzones = await document.querySelectorAllAsync("[dropzone='copy']"); + + Debug.LogWarning($"dropzone 2: '{dropzones.Index().Aggregate("", (currentString, dropzone) => $"{currentString}, {dropzone.Key}: {dropzone.Value.Node.attributes.GetValueOrDefault("data-fact-id")}")}'"); + + string[] factIDs = new string[dropzones.Length]; + + // get attributes for each dropzone + //for (int i = 0; i < dropzones.Length; i++) + //{ + // factIDs[i] = ( await dropzones[i].getAttributesAsync() ).GetValueOrDefault("data-fact-id", null); + //} + //Debug.LogWarning($"dropzone 3: '{string.Join(", ", factIDs)}'"); + } + + + /// <summary> + /// First try to get the dropzone state using coroutines. + /// Doesn't work because coroutines can't access method local temporary variables. + /// </summary> + /// <returns></returns> + [Obsolete("Use getDropzoneStateAsync instead")] + private IEnumerator GetDropzoneState() + { + Debug.LogWarning($"dropzone pre"); + + DomNodeWrapper doc = null; + yield return DomNodeWrapper.getDocument(webViewComponent.tab, (document) => { + Debug.LogWarning($"dropzone 1: '{document}'"); + doc = document; + + StartCoroutine(document.querySelectorAll("[dropzone='copy']", (dropzones) => { + foreach (var dropzone in dropzones) + { + Debug.LogWarning($"dropzone 2: Node is Null?: '{dropzone.Node == null}'"); + StartCoroutine(dropzone.getAttributes((attributes) => + { + Debug.LogWarning($"dropzone 3 getAttributes: '{string.Join(", ", attributes.Values)}'"); + })); + } + })); + }); + Debug.LogWarning($"dropzone post: '{doc}'"); + } +} + +public class FactObjectUIConverter : JsonConverter<FactObjectUI> +{ + public override void WriteJson(JsonWriter writer, FactObjectUI value, JsonSerializer serializer) + { + //serializer.Serialize(writer, value.Fact); + JObject o = JObject.FromObject(value.Fact, WebViewComponent.serializer); + o.AddFirst(new JProperty("id", value.Fact.Id)); + + o.WriteTo(writer); + } + public override FactObjectUI ReadJson(JsonReader reader, Type objectType, FactObjectUI existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var factObject = new FactObjectUI(); + factObject.Fact = serializer.Deserialize<Fact>(reader); + return factObject; + } +} diff --git a/Assets/Scripts/UI/InGame/WebViewController.cs.meta b/Assets/Scripts/UI/InGame/WebViewController.cs.meta new file mode 100644 index 0000000000000000000000000000000000000000..89c76d258b39805e0515ab474f6103502c953732 --- /dev/null +++ b/Assets/Scripts/UI/InGame/WebViewController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 534d25977ad35154781c29672ce2bb13 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/NetwMenu/StartMenu_mobile.cs b/Assets/Scripts/UI/NetwMenu/StartMenu_mobile.cs index c844693e5a414033e8be2d232be6935e7e9de6fe..264b5dd9454b4ab36f0dfb4ddaf799615e93480b 100644 --- a/Assets/Scripts/UI/NetwMenu/StartMenu_mobile.cs +++ b/Assets/Scripts/UI/NetwMenu/StartMenu_mobile.cs @@ -119,7 +119,7 @@ void start2_CheckOS_CheckConfig() NetworkJSON_Load(); if (!checkDataPath() && false) - Debug.Log("Todo: Pr�fen auf Bugs bzl DataPath"); + Debug.Log("Todo: Pr�fen auf Bugs bzl DataPath"); if (!checkDataPath() || true) { @@ -210,11 +210,19 @@ void changeSettingsToOS() { case OperationSystem.Windows: UIconfig.controlMode = ControlMode.Keyboard; - if (autoSettingsAdaption == 2) { UIconfig.FrameITUIversion = 1; } + if (autoSettingsAdaption == 2) + { + UIconfig.FrameITUIversion = 1; + UIconfig.scrollViewVersion = ScrollViewVersion.ScrollWebView; + } break; case OperationSystem.Android: UIconfig.controlMode = ControlMode.Mobile; - if (autoSettingsAdaption == 2) { UIconfig.FrameITUIversion = 2; } + if (autoSettingsAdaption == 2) + { + UIconfig.FrameITUIversion = 2; + UIconfig.scrollViewVersion = ScrollViewVersion.ScrollShow; + } break; default: break; diff --git a/Assets/Scripts/UI/UIconfig.cs b/Assets/Scripts/UI/UIconfig.cs index 4250cb104355a82048fce2cb3426eb7b6b717595..a9fe37caa108cfe4f9566939e55be91bdab26ceb 100644 --- a/Assets/Scripts/UI/UIconfig.cs +++ b/Assets/Scripts/UI/UIconfig.cs @@ -6,6 +6,12 @@ public static class UIconfig { public static int FrameITUIversion = 2; // 1= FrameITUI; 2= FrameITUI_mobil + public static ScrollViewVersion scrollViewVersion = ScrollViewVersion.ScrollShow; + public enum ScrollViewVersion + { + ScrollShow = 1, + ScrollWebView = 2, + } public static int InputManagerVersion = 1; // 1= InputManager, 2=InputSystemPackage ; 3=overConfigfile public static int EventSystemModule = 2;// 1= InputManager, 2=InputSystemPackage ; 3=overConfigfile public static int GameplayMode = 5; //5=First Person, 4=third, 3=third+, 2=Escaperoom, 1=Sidescroller, 0=Sidescroller+ @@ -125,6 +131,7 @@ public class NetworkJSON public float camRotatingSensitivity; //Sensitivity to inputs. public bool MouseKeepingInWindow; public int scrolldirection; + public ScrollViewVersion scrollViewVersion; } public class NetworkJSONonlyString @@ -150,6 +157,7 @@ public class NetworkJSONonlyString public string camRotatingSensitivity; //Sensitivity to inputs. public string MouseKeepingInWindow; public string scrolldirection; + public string scrollViewVersion; } //------------------------------------------------------------------------------------------------------ diff --git a/Assets/Standard Assets/Utility/AutoMobileShaderSwitch.cs b/Assets/Standard Assets/Utility/AutoMobileShaderSwitch.cs index db3c18145b6b6e0263df206e343b33e2f793cb5d..e430a2d455510cee4ef301713157d624957ac468 100644 --- a/Assets/Standard Assets/Utility/AutoMobileShaderSwitch.cs +++ b/Assets/Standard Assets/Utility/AutoMobileShaderSwitch.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; diff --git a/Assets/StreamingAssets/StreamToDataPath_withHandler/scrollView.html b/Assets/StreamingAssets/StreamToDataPath_withHandler/scrollView.html new file mode 100644 index 0000000000000000000000000000000000000000..28a9b5d18221a4fcba5a049a209417c0d31b41b1 --- /dev/null +++ b/Assets/StreamingAssets/StreamToDataPath_withHandler/scrollView.html @@ -0,0 +1,315 @@ +<!DOCTYPE html> +<head> + <meta charset="utf-8"> + <title>Scroll View</title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <style> + [dropzone] { + background-color: grey; + margin: 1px; + border-width: 1px; + border-style: dashed; + } + [data-fact-id] { + background-color: lightgray; + } + [data-hint-available] { + background-color: yellow + } + math { + display: inline-flex; + align-items: center; + flex-wrap: wrap; + } + .lagacySlot { + width: 100px; + height: 100px; + margin: 50px; + border-width: 1px; + } + #rectangle { + width: 10px; + height: 10px; + position: absolute; + background-color: red; + } + </style> +</head> +<body> + <div id="scrollContainer"> + <div>No scroll selected</div> + <math> + <mi>E</mi> + <mo>=</mo> + <mfenced> + <mtable> + <mtr> + <mtd> + <mi dropzone="copy" data-allowed-types="PointFact,AngleFact" data-slot-id="http://mathhub.info/FrameIT/frameworld?Example?A">a</mi> + </mtd> + <mtd> + <mi dropzone="copy" data-slot-id="http://mathhub.info/FrameIT/frameworld?Example?B">b</mi> + </mtd> + <mtd> + <mn>0</mn> + </mtd> + </mtr> + <mtr> + <mtd> + <mn>0</mn> + </mtd> + <mtd> + <mn>1</mn> + </mtd> + <mtd> + <mn>0</mn> + </mtd> + </mtr> + <mtr> + <mtd> + <mn>0</mn> + </mtd> + <mtd> + <mn>0</mn> + </mtd> + <mtd> + <mn>1</mn> + </mtd> + </mtr> + </mtable> + </math> + </div> + <button type="button" title="Apply the scroll" onclick="applyScroll('')">Magic</button><br> + <p>You can right click on yellow slots to get a hint.</p> +</body> + <script> + /** + * @typedef Point + * @type {object} + * @property {number} x + * @property {number} y + * @property {number} z + */ + + /** + * @property {Point} point + * @property {Point} normal + * @property {string} s_type + * @property {string} label + * @property {string|null} _CustomLabel + * @property {boolean} hasCustomLabel + * @property {number} labelId + */ + + class Fact { + /** @property {string} id Fact id */ + id = "" + /** @property {string} s_type Fact type */ + s_type = "" + /** @property {string} label used in unity */ + label = "" + /** @property {string | null} _CustomLabel Custom label */ + _CustomLabel = null + /** @property {boolean} hasCustomLabel */ + hasCustomLabel = false + /** @property {number} labelId */ + labelId = 0 + } + + class Point { + /** @property {number} x */ + x = 0 + /** @property {number} y */ + y = 0 + /** @property {number} z */ + z = 0 + } + /** + s_type: PointFact, + label: A, + _CustomLabel: null, + hasCustomLabel: false, + labelId: 0, + point: {x: -1.66086578, y: -0.00494432449, z: -2.17682648}, + normal: {x: 0, y: 1, z: 0} + */ + class PointFact extends Fact { + s_type = "PointFact"; + /** @property {Point} point */ + point = new Point() + /** @property {Point} normal */ + normal = new Point() + } + + /** + * pid1: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact252, + pid2: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact254, + pid3: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact256, + s_type: AngleFact, + label: ∠BDF, + _CustomLabel: null, + is_right_angle: false, + hasCustomLabel: false, + labelId: 0 + */ + class AngleFact extends Fact { + s_type = "AngleFact"; + pid1 = ""; + pid2 = ""; + pid3 = ""; + is_right_angle = false; + } + + /** + * s_type: LineFact, + pid1: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact255, + pid2: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact256, + dir: [object Object], + label: [EF], + _CustomLabel: null, + hasCustomLabel: false, + labelId: 0 + */ + class LineFact extends Fact { + s_type = "LineFact"; + pid1 = ""; + pid2 = ""; + dir = new Point(); + } + + /** + * s_type: RayFact, + pid1: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact256, + pid2: http://mathhub.info/FrameIT/frameworld?DefaultSituationSpace/SituationTheory1?fact252, + dir: [object Object], + label: FB, + _CustomLabel: null, + hasCustomLabel: false, + labelId: 0 + */ + class RayFact extends Fact { + s_type = "RayFact"; + pid1 = ""; + pid2 = ""; + dir = new Point(); + } + + + + /** @param {DragEvent} event */ + function dropHandler(event) { + event.preventDefault() + console.log("dropHandler", event) + + const data = event.dataTransfer.getData("application/json") + //const data = event.dataTransfer.getData("text/plain") + console.log(`Droped data: '${event.dataTransfer.types}'`, event.dataTransfer.types) + + /** @type {Fact} */ + const fact = JSON.parse(data) + console.warn(`Droped Fact '${fact.label}':`, fact) + + /** @type {HTMLElement} */ + const element = event.target + + if (element.hasAttribute("data-allowed-types")) { + //const allowedTypesStr = element.dataset["allowed-types"] + const allowedTypesStr = element.getAttribute("data-allowed-types") + const allowedTypes = allowedTypesStr.split(",") + + if (!allowedTypes.includes(fact.s_type)) { + console.warn(`The drop target data-type '${fact.s_type}' is not a member of the allowed types '${allowedTypesStr}'`) + return + } + } + + element.innerHTML = fact.label + element.fact = fact + element.dataset.factId = fact.id + } + + /** @param {MouseEvent} event */ + function clickHandler(event) { + event.preventDefault() + console.log("clickHandler") + console.log("clickHandler", event) + switch (event.button) { + case 0: + console.log("Left button clicked") + event.target.fact = null + event.target.dataset.factId = null + break + case 1: + console.log("Middle button clicked") + break + case 2: + console.log("Right button clicked") + getHint(event.target.dataset.slotId) + break + default: + console.log("Unknown button clicked") + } + } + + /* + * register the drag event listeners + */ + //document.addEventListener("dragstart", ev => printHandler(ev, "DragStartEvent")) + //document.addEventListener("dragenter", ev => printHandler(ev, "DragEnterEvent")) + //document.addEventListener("drag", ev => printHandler(ev, "DragEvent")) + document.addEventListener("dragover", ev => ev.preventDefault()) + //document.addEventListener("dragover", ev => printPreventDefaultHandler(ev, "DragOverEvent")) + //document.addEventListener("dragleave", ev => printHandler(ev, "DragLeaveEvent")) + //document.addEventListener("dragend", ev => printHandler(ev, "DragEndEvent")) + + // select all dropzones and add drop event listeners + //let dropZones = document.querySelectorAll('[dropzone="copy"]') + //dropZones.forEach( dropZone => dropZone.addEventListener("drop", ev => dropHandler(ev, "DropEvent")) ) + + /** select all dropzones and add drop event listeners */ + function addDropZoneEventListeners() { + console.log("addDropZoneEventListeners") + document.querySelectorAll('[dropzone="copy"]') + .forEach( dropZone => { + dropZone.removeEventListener("drop", dropHandler) + dropZone.removeEventListener("click", clickHandler) + dropZone.removeEventListener("contextmenu", clickHandler) + //dropZone.addEventListener("dragover", ev => ev.preventDefault()) + dropZone.addEventListener("drop", dropHandler) + dropZone.addEventListener("click", clickHandler) + dropZone.addEventListener("contextmenu", clickHandler) + }) + } + //addDropZoneEventListeners() + </script> + + + + + <!--<script src="visualiseCursor.mjs" defer type="module"></script>--> + <!--<script> + /* mouse and pointer event handling */ + const rectangle = document.createElement("div"); + rectangle.id = "rectangle"; + + console.log("appendChild to", document.body) + document.body.appendChild(rectangle); + + function followCursor(event) { + const cursorX = event.clientX; + const cursorY = event.clientY +5; + //console.log(`MouseEvent X: ${cursorX}, Y: ${cursorY}, Event type: ${event.type}`, event); + rectangle.style.left = `${cursorX}px`; + rectangle.style.top = `${cursorY}px`; + } + + document.addEventListener("mousemove", followCursor); + document.addEventListener("pointermove", followCursor); + + document.addEventListener("mouseover", followCursor); + document.addEventListener("pointerover", followCursor); + + document.addEventListener("mouseout", followCursor); + document.addEventListener("pointerout", followCursor); + </script>--> +</html> diff --git a/Assets/StreamingAssets/StreamToDataPath_withHandler/scrollView.html.meta b/Assets/StreamingAssets/StreamToDataPath_withHandler/scrollView.html.meta new file mode 100644 index 0000000000000000000000000000000000000000..02831017e860ae19925171910bdd1ab72f79f6a7 --- /dev/null +++ b/Assets/StreamingAssets/StreamToDataPath_withHandler/scrollView.html.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1d3e2132e24f19e41970733210b72ac6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/StreamingAssets/StreamToPersistentDataPath/Config/Network.JSON b/Assets/StreamingAssets/StreamToPersistentDataPath/Config/Network.JSON index eb50d80634abf076304e51be7fcbd575c0dea88c..14c02347d1ddf2ecac930d239269c7f639c98a4c 100644 --- a/Assets/StreamingAssets/StreamToPersistentDataPath/Config/Network.JSON +++ b/Assets/StreamingAssets/StreamToPersistentDataPath/Config/Network.JSON @@ -19,5 +19,6 @@ "cursorSize": 0.03125, "camRotatingSensitivity": 2.0, "MouseKeepingInWindow": true, - "scrolldirection": -1 + "scrolldirection": -1, + "scrollViewVersion": 2 } \ No newline at end of file diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index 46042a32bf9677b1bb0405eadd44bf65e83997ad..339a6304c6f32a083fd1b546b57dde5d7467bd13 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -1,5 +1,11 @@ { "dependencies": { + "bessw.unity.webview": { + "version": "file:bessw.unity.webview", + "depth": 0, + "source": "embedded", + "dependencies": {} + }, "com.github-glitchenzo.nugetforunity": { "version": "https://github.com/GlitchEnzo/NuGetForUnity.git?path=/src/NuGetForUnity", "depth": 0,