From d78ad49762ea2d306a04b892473dd2cbfef79975 Mon Sep 17 00:00:00 2001 From: hyperion51 Date: Fri, 29 May 2020 23:06:35 +0100 Subject: [PATCH] Survey Controller & Drone Feedback Implemented task and control module for surveying resources Implemented behavior for resource scanner Resources aren't shown until they have been surveyed Entities can now display messages, used to provide drone state feedback Orbital entities now provide correct velocity, improving drone docking precision --- .../.idea/contentModel.xml | 3 + Assets/Prefabs/Entity.prefab | 208 +++++++++++++++++ Assets/Prefabs/Planet.prefab | 210 +++++++++++++++++- Assets/Prefabs/Ship.prefab | 208 +++++++++++++++++ Assets/Scenes/Main.unity | 13 -- .../Scripts/ServerShared/Agents/AgentTask.cs | 1 + Assets/Scripts/ServerShared/Agents/Aim.cs | 34 +++ .../Scripts/ServerShared/Agents/Aim.cs.meta | 11 + .../Scripts/ServerShared/Agents/Locomotion.cs | 1 - Assets/Scripts/ServerShared/Agents/Mining.cs | 8 - .../ServerShared/Agents/StationTowing.cs | 8 - Assets/Scripts/ServerShared/Agents/Survey.cs | 16 ++ .../ServerShared/Agents/Survey.cs.meta | 11 + .../ServerShared/Behaviors/Behaviors.cs | 2 + .../ServerShared/Behaviors/Controller.cs | 15 +- .../Behaviors/MiningController.cs | 10 +- .../ServerShared/Behaviors/ResourceScanner.cs | 69 +++++- .../Behaviors/SurveyController.cs | 159 +++++++++++++ .../Behaviors/SurveyController.cs.meta | 11 + .../Behaviors/TowingController.cs | 8 +- Assets/Scripts/ServerShared/DatabaseItems.cs | 3 + Assets/Scripts/ServerShared/Entity.cs | 19 +- Assets/Scripts/ServerShared/Extensions.cs | 25 +++ Assets/Scripts/ServerShared/GameContext.cs | 37 ++- Assets/Scripts/ServerShared/GlobalData.cs | 6 + Assets/Scripts/ServerShared/OrbitalEntity.cs | 2 +- Assets/Scripts/StrategyGameManager.cs | 94 +++++++- Assets/Scripts/UI/ReadOnlyPropertiesPanel.cs | 5 +- Assets/Scripts/UI/ZoneObject.cs | 2 + Economy.Shared.Unity.csproj | 3 + 30 files changed, 1136 insertions(+), 66 deletions(-) create mode 100644 Assets/Scripts/ServerShared/Agents/Aim.cs create mode 100644 Assets/Scripts/ServerShared/Agents/Aim.cs.meta create mode 100644 Assets/Scripts/ServerShared/Agents/Survey.cs create mode 100644 Assets/Scripts/ServerShared/Agents/Survey.cs.meta create mode 100644 Assets/Scripts/ServerShared/Behaviors/SurveyController.cs create mode 100644 Assets/Scripts/ServerShared/Behaviors/SurveyController.cs.meta diff --git a/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml b/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml index a7599e1d4..1d9d86846 100644 --- a/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml +++ b/.idea/.idea.Aetheria-Economy/.idea/contentModel.xml @@ -1244,9 +1244,11 @@ + + @@ -1273,6 +1275,7 @@ + diff --git a/Assets/Prefabs/Entity.prefab b/Assets/Prefabs/Entity.prefab index 222b543e9..c981cb3fb 100644 --- a/Assets/Prefabs/Entity.prefab +++ b/Assets/Prefabs/Entity.prefab @@ -1,5 +1,210 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &235155884317602032 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4644834953993757301} + - component: {fileID: 1859458984701215649} + - component: {fileID: 3439515216706641237} + - component: {fileID: 3170441533209407059} + - component: {fileID: 3150651635148382191} + m_Layer: 0 + m_Name: Message + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4644834953993757301 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235155884317602032} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 7667578565413050542} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.6} + m_SizeDelta: {x: 1, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!23 &1859458984701215649 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235155884317602032} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 21677577810600300, guid: ef74c4c30ca5ced4489f28b914006aad, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &3439515216706641237 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235155884317602032} + m_Mesh: {fileID: 0} +--- !u!222 &3170441533209407059 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235155884317602032} + m_CullTransparentMesh: 0 +--- !u!114 &3150651635148382191 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235155884317602032} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Something just happened, now I''m telling you about it. + + Something just happened, now I''m telling you about it.' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: ef74c4c30ca5ced4489f28b914006aad, type: 2} + m_sharedMaterial: {fileID: 21677577810600300, guid: ef74c4c30ca5ced4489f28b914006aad, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 2.5 + m_fontSizeBase: 2.5 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 1026 + m_characterSpacing: 1.38 + m_wordSpacing: 0 + m_lineSpacing: 7.09 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_firstOverflowCharacterIndex: 0 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_isTextTruncated: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_VertexBufferAutoSizeReduction: 1 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 3150651635148382191} + characterCount: 109 + spriteCount: 0 + spaceCount: 17 + wordCount: 18 + linkCount: 0 + lineCount: 2 + pageCount: 1 + materialCount: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_hasFontAssetChanged: 0 + m_renderer: {fileID: 1859458984701215649} + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_maskType: 0 --- !u!1 &7667578565016065614 GameObject: m_ObjectHideFlags: 0 @@ -135,6 +340,7 @@ Transform: m_Children: - {fileID: 7667578565016065613} - {fileID: 7667578566386612334} + - {fileID: 4644834953993757301} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -152,6 +358,8 @@ MonoBehaviour: m_EditorClassIdentifier: Icon: {fileID: 7667578565016065612} Label: {fileID: 7667578566386612333} + Message: {fileID: 3150651635148382191} + Children: [] --- !u!1 &7667578566386612335 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/Planet.prefab b/Assets/Prefabs/Planet.prefab index 53ffa64e5..09c80e995 100644 --- a/Assets/Prefabs/Planet.prefab +++ b/Assets/Prefabs/Planet.prefab @@ -1,5 +1,210 @@ %YAML 1.1 %TAG !u! tag:unity3d.com,2011: +--- !u!1 &4176311944753611310 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1093865191529778971} + - component: {fileID: 956320758189013213} + - component: {fileID: 6189203536709783203} + - component: {fileID: 688008198251117811} + - component: {fileID: 6196070888394201391} + m_Layer: 0 + m_Name: Message + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1093865191529778971 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4176311944753611310} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 5321404118521994135} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.6} + m_SizeDelta: {x: 1, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!23 &956320758189013213 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4176311944753611310} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 21677577810600300, guid: ef74c4c30ca5ced4489f28b914006aad, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &6189203536709783203 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4176311944753611310} + m_Mesh: {fileID: 0} +--- !u!222 &688008198251117811 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4176311944753611310} + m_CullTransparentMesh: 0 +--- !u!114 &6196070888394201391 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4176311944753611310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Something just happened, now I''m telling you about it. + + Something just happened, now I''m telling you about it.' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: ef74c4c30ca5ced4489f28b914006aad, type: 2} + m_sharedMaterial: {fileID: 21677577810600300, guid: ef74c4c30ca5ced4489f28b914006aad, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 2.5 + m_fontSizeBase: 2.5 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 1026 + m_characterSpacing: 1.38 + m_wordSpacing: 0 + m_lineSpacing: 7.09 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_firstOverflowCharacterIndex: 0 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_isTextTruncated: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_VertexBufferAutoSizeReduction: 1 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 6196070888394201391} + characterCount: 109 + spriteCount: 0 + spaceCount: 17 + wordCount: 18 + linkCount: 0 + lineCount: 2 + pageCount: 1 + materialCount: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_hasFontAssetChanged: 0 + m_renderer: {fileID: 956320758189013213} + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_maskType: 0 --- !u!1 &5321404118521994134 GameObject: m_ObjectHideFlags: 0 @@ -31,6 +236,7 @@ Transform: - {fileID: 5321404120083801960} - {fileID: 5321404118931821940} - {fileID: 5321404119494867799} + - {fileID: 1093865191529778971} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -46,9 +252,11 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 17a379c98cd100d4c8548e22c676d246, type: 3} m_Name: m_EditorClassIdentifier: - GravityMesh: {fileID: 5321404120083801962} Icon: {fileID: 5321404118931821941} Label: {fileID: 5321404119494867796} + Message: {fileID: 6196070888394201391} + Children: [] + GravityMesh: {fileID: 5321404120083801962} --- !u!1 &5321404118931821943 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/Ship.prefab b/Assets/Prefabs/Ship.prefab index 32ea87fd0..34867f7bf 100644 --- a/Assets/Prefabs/Ship.prefab +++ b/Assets/Prefabs/Ship.prefab @@ -61,6 +61,7 @@ Transform: m_Children: - {fileID: 752969731239391542} - {fileID: 752969731603226389} + - {fileID: 2376444423840420930} m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -78,6 +79,8 @@ MonoBehaviour: m_EditorClassIdentifier: Icon: {fileID: 752969731239391543} Label: {fileID: 752969731603226390} + Message: {fileID: 2269191731601446379} + Children: [] Thruster: {fileID: 6634195572313526987} --- !u!1 &752969731239391541 GameObject: @@ -467,3 +470,208 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 +--- !u!1 &8284500064616352456 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2376444423840420930} + - component: {fileID: 9122382316357193139} + - component: {fileID: 2978801183465297864} + - component: {fileID: 7740350830631187417} + - component: {fileID: 2269191731601446379} + m_Layer: 0 + m_Name: Message + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2376444423840420930 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8284500064616352456} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 752969730562965461} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0.6} + m_SizeDelta: {x: 1, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!23 &9122382316357193139 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8284500064616352456} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 21677577810600300, guid: ef74c4c30ca5ced4489f28b914006aad, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &2978801183465297864 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8284500064616352456} + m_Mesh: {fileID: 0} +--- !u!222 &7740350830631187417 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8284500064616352456} + m_CullTransparentMesh: 0 +--- !u!114 &2269191731601446379 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8284500064616352456} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: 'Something just happened, now I''m telling you about it. + + Something just happened, now I''m telling you about it.' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: ef74c4c30ca5ced4489f28b914006aad, type: 2} + m_sharedMaterial: {fileID: 21677577810600300, guid: ef74c4c30ca5ced4489f28b914006aad, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_outlineColor: + serializedVersion: 2 + rgba: 4278190080 + m_fontSize: 2.5 + m_fontSizeBase: 2.5 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_textAlignment: 1026 + m_characterSpacing: 1.38 + m_wordSpacing: 0 + m_lineSpacing: 7.09 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_firstOverflowCharacterIndex: 0 + m_linkedTextComponent: {fileID: 0} + m_isLinkedTextComponent: 0 + m_isTextTruncated: 0 + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + m_isCullingEnabled: 0 + m_ignoreRectMaskCulling: 0 + m_ignoreCulling: 1 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_VertexBufferAutoSizeReduction: 1 + m_firstVisibleCharacter: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_textInfo: + textComponent: {fileID: 2269191731601446379} + characterCount: 109 + spriteCount: 0 + spaceCount: 17 + wordCount: 18 + linkCount: 0 + lineCount: 2 + pageCount: 1 + materialCount: 1 + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_spriteAnimator: {fileID: 0} + m_hasFontAssetChanged: 0 + m_renderer: {fileID: 9122382316357193139} + m_subTextObjects: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + m_maskType: 0 diff --git a/Assets/Scenes/Main.unity b/Assets/Scenes/Main.unity index 7e21f5e64..67e05e97c 100644 --- a/Assets/Scenes/Main.unity +++ b/Assets/Scenes/Main.unity @@ -3392,7 +3392,6 @@ GameObject: m_Component: - component: {fileID: 435654367} - component: {fileID: 435654368} - - component: {fileID: 435654369} m_Layer: 0 m_Name: Zone View m_TagString: Untagged @@ -3431,18 +3430,6 @@ MonoBehaviour: m_EditorClassIdentifier: TabGroup: {fileID: 143833105} TabButton: {fileID: 618245060} ---- !u!114 &435654369 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 435654366} - m_Enabled: 0 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0ae6f9307731b8f469a018c69d95d2ba, type: 3} - m_Name: - m_EditorClassIdentifier: --- !u!1 &456371627 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/ServerShared/Agents/AgentTask.cs b/Assets/Scripts/ServerShared/Agents/AgentTask.cs index 87518d9d7..8aeccaed8 100644 --- a/Assets/Scripts/ServerShared/Agents/AgentTask.cs +++ b/Assets/Scripts/ServerShared/Agents/AgentTask.cs @@ -9,6 +9,7 @@ using UnityEngine; [MessagePackObject, Union(0, typeof(StationTowing)), Union(1, typeof(Mining)), + Union(2, typeof(Survey)), JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] public abstract class AgentTask : DatabaseEntry { diff --git a/Assets/Scripts/ServerShared/Agents/Aim.cs b/Assets/Scripts/ServerShared/Agents/Aim.cs new file mode 100644 index 000000000..644f8dd36 --- /dev/null +++ b/Assets/Scripts/ServerShared/Agents/Aim.cs @@ -0,0 +1,34 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +public class Aim : AgentBehavior +{ + public float2 Objective; + + private Thruster _thrust; + private Turning _turning; + private VelocityLimit _velocityLimit; + private int _thrustAxis; + private int _turningAxis; + + public Aim(GameContext context, Entity entity, ControllerData controllerData) : base(context, entity, controllerData) + { + _velocityLimit = Entity.GetBehaviors().FirstOrDefault(); + _thrust = Entity.GetBehaviors().FirstOrDefault(); + _turning = Entity.GetBehaviors().FirstOrDefault(); + _thrustAxis = Entity.GetAxis(); + _turningAxis = Entity.GetAxis(); + } + public override void Update(float delta) + { + if (_thrust != null && _turning != null) + { + float2 diff = Objective - Entity.Position; + Entity.Axes[_turningAxis].Value = TurningInput(diff); + Entity.Axes[_thrustAxis].Value = 0; + } + } +} diff --git a/Assets/Scripts/ServerShared/Agents/Aim.cs.meta b/Assets/Scripts/ServerShared/Agents/Aim.cs.meta new file mode 100644 index 000000000..ed9441448 --- /dev/null +++ b/Assets/Scripts/ServerShared/Agents/Aim.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4daff8784b3444a4ab5466da3368cd7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ServerShared/Agents/Locomotion.cs b/Assets/Scripts/ServerShared/Agents/Locomotion.cs index c2fba4235..7e6d3e9ec 100644 --- a/Assets/Scripts/ServerShared/Agents/Locomotion.cs +++ b/Assets/Scripts/ServerShared/Agents/Locomotion.cs @@ -8,7 +8,6 @@ using static Unity.Mathematics.math; public class Locomotion : AgentBehavior { public float2 Objective; - private const float Sensitivity = 1; private const float TangentSensitivity = 2; private Thruster _thrust; diff --git a/Assets/Scripts/ServerShared/Agents/Mining.cs b/Assets/Scripts/ServerShared/Agents/Mining.cs index c5280d352..4138fe92a 100644 --- a/Assets/Scripts/ServerShared/Agents/Mining.cs +++ b/Assets/Scripts/ServerShared/Agents/Mining.cs @@ -13,12 +13,4 @@ public class Mining : AgentTask [JsonProperty("asteroids"), Key(4)] public Guid Asteroids; - - // public StationTowing(Guid zone, Guid station, Guid orbitParent, float orbitDistance) - // { - // Zone = zone; - // Station = station; - // OrbitParent = orbitParent; - // OrbitDistance = orbitDistance; - // } } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Agents/StationTowing.cs b/Assets/Scripts/ServerShared/Agents/StationTowing.cs index 800b742c5..99aba9264 100644 --- a/Assets/Scripts/ServerShared/Agents/StationTowing.cs +++ b/Assets/Scripts/ServerShared/Agents/StationTowing.cs @@ -19,12 +19,4 @@ public class StationTowing : AgentTask [JsonProperty("orbitDistance"), Key(6)] public float OrbitDistance; - - // public StationTowing(Guid zone, Guid station, Guid orbitParent, float orbitDistance) - // { - // Zone = zone; - // Station = station; - // OrbitParent = orbitParent; - // OrbitDistance = orbitDistance; - // } } diff --git a/Assets/Scripts/ServerShared/Agents/Survey.cs b/Assets/Scripts/ServerShared/Agents/Survey.cs new file mode 100644 index 000000000..e273b9fd5 --- /dev/null +++ b/Assets/Scripts/ServerShared/Agents/Survey.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using JsonKnownTypes; +using MessagePack; +using Newtonsoft.Json; + +[MessagePackObject, + JsonObject(MemberSerialization.OptIn), JsonConverter(typeof(JsonKnownTypesConverter))] +public class Survey : AgentTask +{ + [IgnoreMember] public override TaskType Type => TaskType.Explore; + + [JsonProperty("station"), Key(4)] + public List Planets; +} \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Agents/Survey.cs.meta b/Assets/Scripts/ServerShared/Agents/Survey.cs.meta new file mode 100644 index 000000000..9d2d44161 --- /dev/null +++ b/Assets/Scripts/ServerShared/Agents/Survey.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7e87dcf21f32dd49907439f53f7e5e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs index db2967c21..8e4e54401 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs @@ -91,6 +91,8 @@ public abstract class PersistentBehaviorData Union(24, typeof(EnergyDrawData)), Union(25, typeof(MiningControllerData)), Union(26, typeof(MiningToolData)), + Union(27, typeof(SurveyControllerData)), + Union(28, typeof(ResourceScannerData)), JsonConverter(typeof(JsonKnownTypesConverter)), JsonObject(MemberSerialization.OptIn)] public abstract class BehaviorData { diff --git a/Assets/Scripts/ServerShared/Behaviors/Controller.cs b/Assets/Scripts/ServerShared/Behaviors/Controller.cs index e75b5e01f..7dcd78d8e 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Controller.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Controller.cs @@ -36,6 +36,7 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh protected Locomotion Locomotion; protected VelocityMatch VelocityMatch; + protected Aim Aim; protected Func TargetPosition; protected Func TargetVelocity; protected bool MatchVelocity; @@ -60,6 +61,7 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh { Locomotion = new Locomotion(_context, _entity, _controllerData); VelocityMatch = new VelocityMatch(_context, _entity, _controllerData); + Aim = new Aim(_context, _entity, _controllerData); _context.CorporationControllers[_entity.Corporation].Add(this); } @@ -89,21 +91,23 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh { if(_entity.Parent!=Guid.Empty) _context.RemoveParent(_entity); - - var distance = length(TargetPosition() - _entity.Position); + + var targetPosition = TargetPosition(); + var distance = length(targetPosition - _entity.Position); if (MatchVelocity) { - VelocityMatch.TargetVelocity = TargetVelocity(); + var targetVelocity = TargetVelocity(); + VelocityMatch.TargetVelocity = targetVelocity; if (_movementPhase == MovementPhase.Locomotion) { var matchDistanceTime = VelocityMatch.MatchDistanceTime; - Locomotion.Objective = TargetPosition() + TargetVelocity() * matchDistanceTime.y; + Locomotion.Objective = targetPosition + targetVelocity * matchDistanceTime.y; Locomotion.Update(delta); if (distance < matchDistanceTime.x) { _movementPhase = MovementPhase.Slowdown; - _context.Log($"Controller {_entity.Name} has entered slowdown phase."); + //_context.Log($"Controller {_entity.Name} has entered slowdown phase."); VelocityMatch.Clear(); VelocityMatch.OnMatch += () => { @@ -114,6 +118,7 @@ public abstract class ControllerBase : IBehavior, IController, IInitializableBeh } else { + VelocityMatch.TargetVelocity = targetVelocity; VelocityMatch.Update(delta); } } diff --git a/Assets/Scripts/ServerShared/Behaviors/MiningController.cs b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs index 273765f5a..be800ddef 100644 --- a/Assets/Scripts/ServerShared/Behaviors/MiningController.cs +++ b/Assets/Scripts/ServerShared/Behaviors/MiningController.cs @@ -64,7 +64,7 @@ public class MiningController : ControllerBase, IBehavior, IPersistentBehavior, var asteroidTransform = _context.GetAsteroidTransform(miningTask.Asteroids, _asteroid); if (length(_entity.Position - asteroidTransform.xy) - asteroidTransform.w > _miningTool.Range) { - _context.Log($"Mining Controller {_entity.Name} is out of range, moving to target asteroid."); + _entity.SetMessage("Moving to target asteroid."); MoveTo(() => _context.GetAsteroidTransform(miningTask.Asteroids, _asteroid).xy, () => _context.GetAsteroidVelocity(miningTask.Asteroids, _asteroid)); _toolSwitch.Activated = false; @@ -76,20 +76,22 @@ public class MiningController : ControllerBase, IBehavior, IPersistentBehavior, _miningTool.AsteroidBelt = miningTask.Asteroids; _miningTool.Asteroid = _asteroid; _toolSwitch.Activated = true; + Aim.Objective = _context.GetAsteroidTransform(miningTask.Asteroids, _asteroid).xy; + Aim.Update(delta); } else NextAsteroid(); } } else { - _context.Log($"Mining Controller {_entity.Name} is out of cargo space. Returning home to offload cargo."); + _entity.SetMessage("Out of cargo space. Returning home to offload cargo."); GoHome(() => { var homeEntity = _context.Cache.Get(HomeEntity); if (!_entity.Cargo.ToArray().All(ii => _context.MoveCargo(_entity, homeEntity, _context.Cache.Get(ii)))) { - _context.Log($"Mining Controller {_entity.Name} has run out of cargo space in parent. Closing Task."); + homeEntity.SetMessage("Colony is out of cargo space. Closing Mining Task."); FinishTask(); _taskStarted = false; } @@ -105,7 +107,7 @@ public class MiningController : ControllerBase, IBehavior, IPersistentBehavior, { var miningTask = _context.Cache.Get(Task); _asteroid = _context.NearestAsteroid(miningTask.Asteroids, _entity.Position); - _context.Log($"Mining Controller {_entity.Name} selecting new asteroid."); + _entity.SetMessage("Selecting new asteroid."); } public PersistentBehaviorData Store() diff --git a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs index 89e83ddd9..21e83ce64 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ResourceScanner.cs @@ -2,6 +2,8 @@ using System.Linq; using MessagePack; using Newtonsoft.Json; +using Unity.Mathematics; +using static Unity.Mathematics.math; [InspectableField, MessagePackObject, JsonObject(MemberSerialization.OptIn)] public class ResourceScannerData : BehaviorData @@ -12,21 +14,44 @@ public class ResourceScannerData : BehaviorData [InspectableField, JsonProperty("minDensity"), Key(2)] public PerformanceStat MinimumDensity = new PerformanceStat(); + [InspectableField, JsonProperty("scanDuration"), Key(3)] + public PerformanceStat ScanDuration = new PerformanceStat(); + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) { return new ResourceScanner(context, this, entity, item); } } -public class ResourceScanner : IBehavior +public class ResourceScanner : IBehavior, IAlwaysUpdatedBehavior { + public int Asteroid = -1; + private ResourceScannerData _data; + private float _scanTime; + private Guid _scanTarget; private Entity Entity { get; } private Gear Item { get; } private GameContext Context { get; } public BehaviorData Data => _data; + public float Range { get; private set; } + public float MinimumDensity { get; private set; } + public float ScanDuration { get; private set; } + + public Guid ScanTarget + { + get => _scanTarget; + set + { + if (value != _scanTarget) + { + _scanTarget = value; + _scanTime = 0; + } + } + } public ResourceScanner(GameContext context, ResourceScannerData data, Entity entity, Gear item) { @@ -38,7 +63,45 @@ public class ResourceScanner : IBehavior public bool Update(float delta) { - // TODO: Implement resource scanners! - return true; + var planetData = Context.Cache.Get(ScanTarget); + if (planetData != null) + { + if (planetData.Belt) + { + if(Asteroid > -1 && + Asteroid < planetData.Asteroids.Length && + length(Entity.Position - Context.GetAsteroidTransform(ScanTarget, Asteroid).xy) < Range) + { + _scanTime += delta; + if (_scanTime > ScanDuration) + { + Context.Cache.Get(Entity.Corporation).PlanetSurveyFloor[ScanTarget] = MinimumDensity; + _scanTime = 0; + } + return true; + } + } + else + { + if(length(Entity.Position - Context.GetOrbitPosition(planetData.Orbit)) < Range) + { + _scanTime += delta; + if (_scanTime > ScanDuration) + { + Context.Cache.Get(Entity.Corporation).PlanetSurveyFloor[ScanTarget] = MinimumDensity; + _scanTime = 0; + } + return true; + } + } + } + return false; + } + + public void AlwaysUpdate(float delta) + { + Range = Context.Evaluate(_data.Range, Item, Entity); + MinimumDensity = Context.Evaluate(_data.MinimumDensity, Item, Entity); + ScanDuration = Context.Evaluate(_data.ScanDuration, Item, Entity); } } \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Behaviors/SurveyController.cs b/Assets/Scripts/ServerShared/Behaviors/SurveyController.cs new file mode 100644 index 000000000..f6e11516e --- /dev/null +++ b/Assets/Scripts/ServerShared/Behaviors/SurveyController.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using MessagePack; +using Newtonsoft.Json; +using RethinkDb.Driver.Ast; +using Unity.Mathematics; +using static Unity.Mathematics.math; + +[MessagePackObject, JsonObject(MemberSerialization.OptIn), EntityTypeRestriction(HullType.Ship), Order(-100)] +public class SurveyControllerData : ControllerData +{ + public override IBehavior CreateInstance(GameContext context, Entity entity, Gear item) + { + return new SurveyController(context, this, entity, item); + } +} + +public class SurveyController : ControllerBase, IBehavior, IPersistentBehavior, IInitializableBehavior +{ + public override TaskType TaskType => TaskType.Explore; + public BehaviorData Data => _data; + + private SurveyControllerData _data; + private GameContext _context; + private Entity _entity; + private Gear _item; + private bool _taskStarted; + private ResourceScanner _scanningTool; + private Switch _toolSwitch; + private Guid _targetPlanet; + private int _asteroid = -1; + + public SurveyController(GameContext context, SurveyControllerData data, Entity entity, Gear item) : base(context, data, entity) + { + _context = context; + _data = data; + _entity = entity; + _item = item; + } + + public new void Initialize() + { + _scanningTool = _entity.GetBehaviors().First(); + _toolSwitch = _entity.GetSwitch(_scanningTool); + base.Initialize(); + } + + public new bool Update(float delta) + { + var surveyTask = _context.Cache.Get(Task); + var corporation = _context.Cache.Get(_entity.Corporation); + if (surveyTask != null) + { + if (!_taskStarted) + { + if (surveyTask.Planets.Any()) + { + _entity.SetMessage("Moving to survey target."); + NextPlanet(); + _scanningTool.ScanTarget = _targetPlanet; + _scanningTool.Asteroid = _asteroid; + if (!corporation.PlanetSurveyFloor.ContainsKey(_targetPlanet) || + corporation.PlanetSurveyFloor[_targetPlanet] + .5f < _scanningTool.MinimumDensity) + { + var planetData = _context.Cache.Get(_targetPlanet); + MoveTo(() => + { + var target = GetPosition(planetData, _asteroid); + var targetToUs = _entity.Position - target; + return target + normalize(targetToUs) * _scanningTool.Range / 2; + }, + () => GetVelocity(planetData, _asteroid), + () => _entity.SetMessage("Arrived at target. Scanning for resources.")); + _taskStarted = true; + } + else + surveyTask.Planets.Remove(_targetPlanet); + } + else + { + _entity.SetMessage("Survey complete. Returning Home."); + FinishTask(); + } + } + else + { + if (!Moving) + { + var planetData = _context.Cache.Get(_targetPlanet); + if ((!corporation.PlanetSurveyFloor.ContainsKey(_targetPlanet) || + corporation.PlanetSurveyFloor[_targetPlanet] + .5f < _scanningTool.MinimumDensity) && + length(_entity.Position - GetPosition(planetData, _asteroid)) < _scanningTool.Range) + { + _toolSwitch.Activated = true; + Aim.Objective = GetPosition(planetData, _asteroid); + Aim.Update(delta); + } + else + { + _toolSwitch.Activated = false; + _taskStarted = false; + } + } + } + } + return base.Update(delta); + } + + private void NextPlanet() + { + var surveyTask = _context.Cache.Get(Task); + var planets = surveyTask.Planets.Select(id => _context.Cache.Get(id)); + var nearestPlanet = planets.MinBy(p => lengthsq(_entity.Position - GetPosition(p))); + _asteroid = nearestPlanet.Belt ? _context.NearestAsteroid(nearestPlanet.ID, _entity.Position) : -1; + _targetPlanet = nearestPlanet.ID; + } + + private float2 GetPosition(PlanetData planet, int asteroid = -1) + { + if (planet.Belt) + { + if(asteroid == -1) asteroid = _context.NearestAsteroid(planet.ID, _entity.Position); + return _context.GetAsteroidTransform(planet.ID, asteroid).xy; + } + return _context.GetOrbitPosition(planet.Orbit); + } + + private float2 GetVelocity(PlanetData planet, int asteroid = -1) + { + if (planet.Belt) + { + if(asteroid == -1) asteroid = _context.NearestAsteroid(planet.ID, _entity.Position); + return _context.GetAsteroidVelocity(planet.ID, asteroid); + } + return _context.GetOrbitVelocity(planet.Orbit); + } + + public PersistentBehaviorData Store() + { + return new SurveyControllerPersistence + { + Task = Task + }; + } + + public void Restore(PersistentBehaviorData data) + { + var surveyControllerPersistence = data as SurveyControllerPersistence; + Task = surveyControllerPersistence.Task; + } +} + +public class SurveyControllerPersistence : PersistentBehaviorData +{ + [JsonProperty("task"), Key(0)] + public Guid Task; +} \ No newline at end of file diff --git a/Assets/Scripts/ServerShared/Behaviors/SurveyController.cs.meta b/Assets/Scripts/ServerShared/Behaviors/SurveyController.cs.meta new file mode 100644 index 000000000..bd420756e --- /dev/null +++ b/Assets/Scripts/ServerShared/Behaviors/SurveyController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1511795bf85d6e41ab89cb05c7cec84 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ServerShared/Behaviors/TowingController.cs b/Assets/Scripts/ServerShared/Behaviors/TowingController.cs index 163ecf1c3..04c6b5c5a 100644 --- a/Assets/Scripts/ServerShared/Behaviors/TowingController.cs +++ b/Assets/Scripts/ServerShared/Behaviors/TowingController.cs @@ -44,12 +44,12 @@ public class TowingController : ControllerBase, IBehavior, IPersistentBehavior { MoveTo(towingTask.Zone, () => { - _context.Log($"Towing Controller {_entity.Name} has entered pickup phase."); + _entity.SetMessage("Entering pickup phase."); MoveTo(_context.Cache.Get(towingTask.Station), true, () => { var target = _context.ZoneEntities[_entity.Zone][towingTask.Station] as OrbitalEntity; _context.SetParent(target, _entity); - _context.Log($"Towing Controller {_entity.Name} has entered delivery phase."); + _entity.SetMessage("Entering delivery phase."); MoveTo(() => { var orbitParent = _context.GetOrbitPosition(towingTask.OrbitParent); @@ -58,9 +58,9 @@ public class TowingController : ControllerBase, IBehavior, IPersistentBehavior }, () => _context.GetOrbitVelocity(towingTask.OrbitParent), () => { _context.RemoveParent(target); - _context.Log($"Towing Controller {_entity.Name} has delivered the target. Returning Home."); + _entity.SetMessage("Target delivered. Returning Home."); - var orbit = _context.CreateOrbit(towingTask.OrbitParent, _entity.Position); + var orbit = _context.CreateOrbit(towingTask.Zone, towingTask.OrbitParent, _entity.Position); target.OrbitData = orbit.ID; FinishTask(); diff --git a/Assets/Scripts/ServerShared/DatabaseItems.cs b/Assets/Scripts/ServerShared/DatabaseItems.cs index 9ce26ce91..ca097f03d 100644 --- a/Assets/Scripts/ServerShared/DatabaseItems.cs +++ b/Assets/Scripts/ServerShared/DatabaseItems.cs @@ -82,6 +82,9 @@ public class Corporation : DatabaseEntry, INamedEntry [JsonProperty("tasks"), Key(3)] public List Tasks = new List(); + [JsonProperty("planetSurveyFloor"), Key(4)] + public Dictionary PlanetSurveyFloor = new Dictionary(); + [IgnoreMember] public string EntryName { get => Name; diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index 55bc9bd8b..fefc82ca6 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -37,6 +37,7 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR [IgnoreMember] public Dictionary Axes; [IgnoreMember] public Dictionary AxisOverrides = new Dictionary(); [IgnoreMember] public readonly Dictionary VisibilitySources = new Dictionary(); + [IgnoreMember] public readonly Dictionary Messages = new Dictionary(); private Dictionary GearData; private Dictionary> ItemBehaviors; @@ -214,6 +215,10 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR foreach(var behavior in group) if(!behavior.Update(delta)) break; + + foreach (var behaviors in Behaviors.Values) + foreach (var behavior in behaviors.Where(b => b is IAlwaysUpdatedBehavior).Cast()) + behavior.AlwaysUpdate(delta); foreach (var item in EquippedItems .Select(item => Context.Cache.Get(item)) @@ -234,7 +239,14 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR OnBeforeSerialize(); OnAfterDeserialize(); } - + + foreach (var message in Messages.Keys.ToArray()) + { + Messages[message] = Messages[message] - delta; + if (Messages[message] < 0) + Messages.Remove(message); + } + // Here's the PITA way // foreach (var staleItem in GearData // .Where(kvp=>kvp.Key.ItemData!=kvp.Value) @@ -289,6 +301,11 @@ public abstract class Entity : DatabaseEntry, IMessagePackSerializationCallbackR // } } + public void SetMessage(string message) + { + Messages[message] = Context.GlobalData.MessageDuration; + } + public void OnBeforeSerialize() { // Filter item behavior collections by those with any persistent behaviors diff --git a/Assets/Scripts/ServerShared/Extensions.cs b/Assets/Scripts/ServerShared/Extensions.cs index 69da1a0e3..b71003c7a 100644 --- a/Assets/Scripts/ServerShared/Extensions.cs +++ b/Assets/Scripts/ServerShared/Extensions.cs @@ -245,6 +245,31 @@ public static class Extensions return maxItem; } + + public static T MinBy(this IEnumerable items, Func selector) + { + if (!items.Any()) + { + throw new InvalidOperationException("Empty input sequence"); + } + + var comparer = Comparer.Default; + T maxItem = items.First(); + U maxValue = selector(maxItem); + + foreach (T item in items.Skip(1)) + { + // Get the value of the item and compare it to the current max. + U value = selector(item); + if (comparer.Compare(value, maxValue) < 0) + { + maxValue = value; + maxItem = item; + } + } + + return maxItem; + } } // https://github.com/Burtsev-Alexey/net-object-deep-copy diff --git a/Assets/Scripts/ServerShared/GameContext.cs b/Assets/Scripts/ServerShared/GameContext.cs index 9fba85edf..389e2e6c3 100644 --- a/Assets/Scripts/ServerShared/GameContext.cs +++ b/Assets/Scripts/ServerShared/GameContext.cs @@ -34,6 +34,7 @@ public class GameContext private Dictionary _previousAsteroidTransforms = new Dictionary(); // x, y, rotation, scale private Dictionary<(Guid, int), float> _asteroidRespawnTimers = new Dictionary<(Guid, int), float>(); private Dictionary<(Guid, int), float> _asteroidDamage = new Dictionary<(Guid, int), float>(); + private Dictionary<(Guid, Guid, int), float> _asteroidMiningAccumulator = new Dictionary<(Guid, Guid, int), float>(); private Dictionary _asteroidPositionsUpdated = new Dictionary(); private Guid _forceLoadZone; private Type[] _statObjects; @@ -303,19 +304,27 @@ public class GameContext var orbitPosition = GetOrbitPosition(orbitData.Parent); for (var i = 0; i < planetData.Asteroids.Length; i++) { + var size = planetData.Asteroids[i].Size; + if(_asteroidRespawnTimers.ContainsKey((planetDataID, i))) size = 0; + else if (_asteroidDamage.ContainsKey((planetDataID, i))) + { + var hpLerp = unlerp(GlobalData.AsteroidSizeMin, GlobalData.AsteroidSizeMax, size); + var asteroidHitpoints = lerp(GlobalData.AsteroidHitpointsMin, GlobalData.AsteroidHitpointsMax, pow(hpLerp, GlobalData.AsteroidHitpointsPower)); + var sizeLerp = (asteroidHitpoints - _asteroidDamage[(planetDataID, i)]) / asteroidHitpoints; + size = lerp(GlobalData.AsteroidSizeMin, size, sizeLerp); + } + _asteroidTransforms[planetDataID][i] = float4( OrbitData.Evaluate((float) frac(Time / OrbitalPeriod(planetData.Asteroids[i].Distance) * GlobalData.OrbitSpeedMultiplier + planetData.Asteroids[i].Phase)) * planetData.Asteroids[i].Distance + orbitPosition, - (float) (Time * planetData.Asteroids[i].RotationSpeed % 360.0), - _asteroidRespawnTimers.ContainsKey((planetDataID, i)) ? 0 : planetData.Asteroids[i].Size); + (float) (Time * planetData.Asteroids[i].RotationSpeed % 360.0), size); } _asteroidPositionsUpdated[planetDataID] = true; } - public OrbitData CreateOrbit(Guid parent, float2 position) + public OrbitData CreateOrbit(Guid zone, Guid parent, float2 position) { - var parentOrbit = Cache.Get(parent); var parentPosition = GetOrbitPosition(parent); var delta = position - parentPosition; var distance = length(delta); @@ -331,9 +340,10 @@ public class GameContext Parent = parent, Period = period, Phase = storedPhase, - Zone = parentOrbit.Zone + Zone = zone }; Cache.Add(orbit); + _orbits.Add(orbit.ID); return orbit; } @@ -735,6 +745,7 @@ public class GameContext Zone = zone }; Cache.Add(orbit); + _orbits.Add(orbit.ID); var entity = new OrbitalEntity(this, hull.ID, gear.Select(g => g.ID), cargo.Select(c => c.ID).Concat(simpleCargo.Select(c => c.ID)), orbit.ID, zone, corporation) @@ -876,15 +887,29 @@ public class GameContext var asteroidTransform = GetAsteroidTransform(asteroidBelt, asteroid); var hpLerp = unlerp(GlobalData.AsteroidSizeMin, GlobalData.AsteroidSizeMax, asteroidTransform.w); var asteroidHitpoints = lerp(GlobalData.AsteroidHitpointsMin, GlobalData.AsteroidHitpointsMax, pow(hpLerp, GlobalData.AsteroidHitpointsPower)); + if (!_asteroidDamage.ContainsKey((asteroidBelt, asteroid))) _asteroidDamage[(asteroidBelt, asteroid)] = 0; _asteroidDamage[(asteroidBelt, asteroid)] = _asteroidDamage[(asteroidBelt, asteroid)] + damage; + + if (!_asteroidMiningAccumulator.ContainsKey((asteroidBelt, miner.ID, asteroid))) + _asteroidMiningAccumulator[(asteroidBelt, miner.ID, asteroid)] = 0; + _asteroidMiningAccumulator[(asteroidBelt, miner.ID, asteroid)] = _asteroidMiningAccumulator[(asteroidBelt, miner.ID, asteroid)] + damage; + if (_asteroidDamage[(asteroidBelt, asteroid)] > asteroidHitpoints) + { _asteroidRespawnTimers[(asteroidBelt, asteroid)] = lerp(GlobalData.AsteroidRespawnMin, GlobalData.AsteroidRespawnMax, hpLerp); + _asteroidDamage.Remove((asteroidBelt, asteroid)); + _asteroidMiningAccumulator.Remove((asteroidBelt, miner.ID, asteroid)); + return; + } + + var resourceCount = planetData.Resources.Sum(x => x.Value); var resource = planetData.Resources.MaxBy(x => pow(x.Value, 1f / penetration) * Random.NextFloat()); - if (resource.Value * efficiency * Random.NextFloat() > 1 && miner.OccupiedCapacity < miner.Capacity - 1) + if (efficiency * Random.NextFloat() * _asteroidMiningAccumulator[(asteroidBelt, miner.ID, asteroid)] * resourceCount / GlobalData.MiningDifficulty > 1 && miner.OccupiedCapacity < miner.Capacity - 1) { + _asteroidMiningAccumulator.Remove((asteroidBelt, miner.ID, asteroid)); var simpleCommodityTarget = miner.Cargo .Select(i => Cache.Get(i)) .FirstOrDefault(i => i.Data == resource.Key) as SimpleCommodity; diff --git a/Assets/Scripts/ServerShared/GlobalData.cs b/Assets/Scripts/ServerShared/GlobalData.cs index 257e31be9..22fa0576b 100644 --- a/Assets/Scripts/ServerShared/GlobalData.cs +++ b/Assets/Scripts/ServerShared/GlobalData.cs @@ -154,6 +154,12 @@ public class GlobalData : DatabaseEntry [InspectableField, JsonProperty("asteroidRespawnMax"), Key(48)] public float AsteroidRespawnMax = 100f; + + [InspectableField, JsonProperty("miningDifficulty"), Key(49)] + public float MiningDifficulty = 500f; + + [InspectableField, JsonProperty("messageDuration"), Key(50)] + public float MessageDuration = 4f; public float PlanetRadius(float mass) { diff --git a/Assets/Scripts/ServerShared/OrbitalEntity.cs b/Assets/Scripts/ServerShared/OrbitalEntity.cs index 01558c485..63ce26a82 100644 --- a/Assets/Scripts/ServerShared/OrbitalEntity.cs +++ b/Assets/Scripts/ServerShared/OrbitalEntity.cs @@ -18,8 +18,8 @@ public class OrbitalEntity : Entity { if (OrbitData != Guid.Empty) { - Velocity = Context.GetOrbitVelocity(OrbitData); Position = Context.GetOrbitPosition(OrbitData); + Velocity = Context.GetOrbitVelocity(OrbitData); } base.Update(delta); diff --git a/Assets/Scripts/StrategyGameManager.cs b/Assets/Scripts/StrategyGameManager.cs index f3af07be1..ae76fdd45 100644 --- a/Assets/Scripts/StrategyGameManager.cs +++ b/Assets/Scripts/StrategyGameManager.cs @@ -308,8 +308,6 @@ public class StrategyGameManager : MonoBehaviour Context = _context, OrbitDistance = _orbitRadius, OrbitParent = _selectedOrbit, - Priority = 0, - Reserved = false, Station = _selectedTowingTarget, Zone = _populatedZone }; @@ -367,6 +365,7 @@ public class StrategyGameManager : MonoBehaviour foreach (var planet in _zoneGravityObjects) { planet.Value.transform.position = float3(_context.GetOrbitPosition(planet.Key) * ZoneSizeScale, .1f); + planet.Value.Message.text = ""; } foreach (var belt in _zoneBelts) @@ -439,6 +438,8 @@ public class StrategyGameManager : MonoBehaviour var thrusterScale = _zoneShips[ship].Thruster.localScale; thrusterScale.x = ship.Axes[ship.GetAxis()].Value; _zoneShips[ship].Thruster.localScale = thrusterScale; + _zoneShips[ship].Message.text = !ship.Messages.Any() ? "" : + string.Join("\n", ship.Messages.OrderByDescending(x=>x.Value).Take(2).Select(x=>x.Key)); PopulateChildObjects(_zoneShips[ship], ship); @@ -472,6 +473,8 @@ public class StrategyGameManager : MonoBehaviour _zoneOrbitals[orbital].transform.position = float3(orbital.Position * ZoneSizeScale, .05f); _zoneOrbitals[orbital].Icon.transform.up = (Vector2) orbital.Direction; + _zoneOrbitals[orbital].Message.text = !orbital.Messages.Any() ? "" : + string.Join("\n", orbital.Messages.OrderByDescending(x=>x.Value).Take(2).Select(x=>x.Key)); PopulateChildObjects(_zoneOrbitals[orbital], orbital); @@ -551,14 +554,23 @@ public class StrategyGameManager : MonoBehaviour { Asteroids = clickTarget, Context = _context, - Priority = 0, - Reserved = false, Zone = _populatedZone }; _cache.Add(task); _cache.Get(_playerCorporation).Tasks.Add(task.ID); }); } + ContextMenu.AddOption("Create Survey Task", () => + { + var task = new Survey + { + Planets = new List(new []{clickTarget}), + Context = _context, + Zone = _populatedZone + }; + _cache.Add(task); + _cache.Get(_playerCorporation).Tasks.Add(task.ID); + }); // ContextMenu.AddOption("Test Option 1", () => Debug.Log("Test Option 1 Selected")); // ContextMenu.AddOption("Test Option 2", () => Debug.Log("Test Option 2 Selected")); // ContextMenu.AddDropdown("Test Dropdown", new [] @@ -571,7 +583,10 @@ public class StrategyGameManager : MonoBehaviour } else if (targetObject is Ship ship) { - + var controller = ship.GetBehaviors().FirstOrDefault(); + if (controller != null) + ContextMenu.AddOption("Finish Task", () => controller.FinishTask()); + } else if (targetObject is OrbitalEntity orbital) { @@ -583,6 +598,46 @@ public class StrategyGameManager : MonoBehaviour OrbitLineRenderer.gameObject.SetActive(true); }); } + else if (targetObject is ZoneData zone) + { + ContextMenu.AddOption("Survey All", () => + { + var planets = zone.Planets.ToList(); + var task = new Survey + { + Planets = planets, + Context = _context, + Zone = _populatedZone + }; + _cache.Add(task); + _cache.Get(_playerCorporation).Tasks.Add(task.ID); + }); + ContextMenu.AddOption("Survey Planets", () => + { + var planets = zone.Planets.Where(id => !_cache.Get(id).Belt).ToList(); + var task = new Survey + { + Planets = planets, + Context = _context, + Zone = _populatedZone + }; + _cache.Add(task); + _cache.Get(_playerCorporation).Tasks.Add(task.ID); + }); + ContextMenu.AddOption("Survey Asteroids", () => + { + var planets = zone.Planets.Where(id => _cache.Get(id).Belt).ToList(); + var task = new Survey + { + Planets = planets, + Context = _context, + Zone = _populatedZone + }; + _cache.Add(task); + _cache.Get(_playerCorporation).Tasks.Add(task.ID); + }); + + } else { ContextMenu.gameObject.SetActive(false); @@ -614,11 +669,24 @@ public class StrategyGameManager : MonoBehaviour planet.Mass > _context.GlobalData.PlanetMass ? "Planet" : "Planetoid"); PropertiesPanel.AddProperty("Mass", () => $"{planet.Mass}"); - PropertiesPanel.AddList("Resources", planet.Resources.Select(resource => + var playerCorp = _cache.Get(_playerCorporation); + if (!playerCorp.PlanetSurveyFloor.ContainsKey(clickTarget)) { - var itemData = _context.Cache.Get(resource.Key); - return new Tuple(itemData.Name, $"{resource.Value:0}"); - })); + PropertiesPanel.AddProperty("Not surveyed for resources", () => ""); + } + else + { + var detectionFloor = playerCorp.PlanetSurveyFloor[clickTarget]; + var detectedResources = planet.Resources.Where(x => x.Value > detectionFloor); + if(!detectedResources.Any()) + PropertiesPanel.AddProperty("No resources detected", () => ""); + else + PropertiesPanel.AddList("Resources", detectedResources.Select, (string, Func)>(resource => + { + var itemData = _context.Cache.Get(resource.Key); + return (itemData.Name, () => $"{resource.Value:0}"); + })); + } } } @@ -637,6 +705,13 @@ public class StrategyGameManager : MonoBehaviour PropertiesPanel.AddProperty("Mass", () => $"{entity.Mass}"); PropertiesPanel.AddProperty("Temperature", () => $"{entity.Temperature:0}°K"); PropertiesPanel.AddProperty("Energy", () => $"{entity.Energy:0}/{entity.GetBehaviors().First().Capacitance:0}"); + PropertiesPanel.AddList("Gear", entity.EquippedItems.Select(g=>_context.Cache.Get(g).ItemData.Name)); + PropertiesPanel.AddList("Cargo", entity.Cargo.Select)>(ii=> + { + var itemInstance = _context.Cache.Get(ii); + var data = _context.Cache.Get(itemInstance.Data); + return (data.Name, () => itemInstance is SimpleCommodity simpleCommodity ? simpleCommodity.Quantity.ToString() : ""); + })); } if (targetObject is ZoneData zone) @@ -825,6 +900,7 @@ public class StrategyGameManager : MonoBehaviour wormholeObject.GravityMesh.gameObject.SetActive(false); wormholeObject.Icon.material.SetTexture("_MainTex", WormholeSprite); wormholeObject.Label.text = otherZone.Name; + wormholeObject.Message.text = ""; wormholeObject.Icon.GetComponent().OnClick += (_, pointer) => { // If the user double clicks on a wormhole, switch to that zone diff --git a/Assets/Scripts/UI/ReadOnlyPropertiesPanel.cs b/Assets/Scripts/UI/ReadOnlyPropertiesPanel.cs index 64458168e..b3baf0496 100644 --- a/Assets/Scripts/UI/ReadOnlyPropertiesPanel.cs +++ b/Assets/Scripts/UI/ReadOnlyPropertiesPanel.cs @@ -50,7 +50,7 @@ public class ReadOnlyPropertiesPanel : MonoBehaviour _properties.Add(list.gameObject); } - public void AddList(string name, IEnumerable> elements) + public void AddList(string name, IEnumerable<(string, Func)> elements) { var list = Instantiate(ListPrefab, transform); list.GetComponentInChildren().text = name; @@ -58,7 +58,8 @@ public class ReadOnlyPropertiesPanel : MonoBehaviour { var item = Instantiate(ListPropertyPrefab, list); item.Name.text = element.Item1; - item.Value.text = element.Item2; + item.Value.text = element.Item2(); + item.ValueFunction = element.Item2; _properties.Add(item.gameObject); } _properties.Add(list.gameObject); diff --git a/Assets/Scripts/UI/ZoneObject.cs b/Assets/Scripts/UI/ZoneObject.cs index 65d4b2d80..ee25ac521 100644 --- a/Assets/Scripts/UI/ZoneObject.cs +++ b/Assets/Scripts/UI/ZoneObject.cs @@ -8,6 +8,8 @@ public class ZoneObject : MonoBehaviour public MeshRenderer Icon; public TextMeshPro Label; + + public TextMeshPro Message; [HideInInspector] public List Children = new List(); diff --git a/Economy.Shared.Unity.csproj b/Economy.Shared.Unity.csproj index b5f806f24..c9992bebd 100644 --- a/Economy.Shared.Unity.csproj +++ b/Economy.Shared.Unity.csproj @@ -63,9 +63,11 @@ + + @@ -90,6 +92,7 @@ +