diff --git a/Cyan-Stars/Assets/Scenes/MarkdownTest.unity b/Cyan-Stars/Assets/Scenes/MarkdownTest.unity new file mode 100644 index 000000000..31b74dd0e --- /dev/null +++ b/Cyan-Stars/Assets/Scenes/MarkdownTest.unity @@ -0,0 +1,673 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &576191394 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 576191395} + - component: {fileID: 576191398} + - component: {fileID: 576191397} + - component: {fileID: 576191396} + - component: {fileID: 576191401} + - component: {fileID: 576191400} + - component: {fileID: 576191399} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &576191395 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576191394} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2116993320} + 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: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &576191396 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576191394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cb6290c451a5b3a4b956eebaeba56c51, type: 3} + m_Name: + m_EditorClassIdentifier: CyanStars.MarkdownRenderer::CyanStars.MarkdownRenderer.TextMeshProMarkdown + text: "# Title\n\np1\np2\n\np3 for newline\n- \u97F3\u4E50\u4F5C\u8005:\n - + \u8C03\u6821\uFF1A[@\u5929\u5929\u51C9\u51C9\u8C46]\n - \u6DF7\u97F3\uFF1A[@\u9038\u606C\u6E05]\n + - \u4F5C\u66F2\u3001\u7F16\u66F2\uFF1A[@\u795E\u5154\u5C0FP]\n - \u4F5C\u8BCD\uFF1A[@Jackdaw\u7941\u6E90]\n + - \u66F2\u7ED8\uFF1A[@\u6DF1\u8C37-shintani]\n - \u89C6\u9891\uFF1A[@\u89C2\u6708\u666F]\n + - \u7B56\u5212\uFF1A[@\u65F6\u5C1A]\n- \u76F8\u5173\u94FE\u63A5\uFF1A\n - + [\u54D4\u54E9\u54D4\u54E9](https://www.bilibili.com/video/BV1qX4y1w7k3)\n + - [\u7F51\u6613\u4E91\u97F3\u4E50](https://music.163.com/#/song?id=1867992176)\n- + \u6E38\u620F\u66F2\u7ED8\uFF1A[@\u80D6\u5934\u9C7C]\n- \u8C31\u9762\u8BBE\u8BA1\uFF1A[@\u6668\u5CE6]\n- + \u6F14\u5531\uFF1A[@\u6D1B\u5929\u4F9D]" + configProvider: + value: {fileID: 576191399} + onDocumentParsed: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 576191401} + m_TargetAssemblyTypeName: CyanStars.MarkdownRenderer.TextMeshProMarkdownAtInfoCollector, + CyanStars.MarkdownRenderer + m_MethodName: CollectAtInfo + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 1 +--- !u!114 &576191397 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576191394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "Title\np1 p2\np3 for newline\n\\u2011\u97F3\u4E50\u4F5C\u8005:\n\\u2011\u8C03\u6821\uFF1A@\u5929\u5929\u51C9\u51C9\u8C46\n\\u2011\u6DF7\u97F3\uFF1A@\u9038\u606C\u6E05\n\\u2011\u4F5C\u66F2\u3001\u7F16\u66F2\uFF1A@\u795E\u5154\u5C0FP\n\\u2011\u4F5C\u8BCD\uFF1A@Jackdaw\u7941\u6E90\n\\u2011\u66F2\u7ED8\uFF1A@\u6DF1\u8C37-shintani\n\\u2011\u89C6\u9891\uFF1A@\u89C2\u6708\u666F\n\\u2011\u7B56\u5212\uFF1A@\u65F6\u5C1A\n\\u2011\u76F8\u5173\u94FE\u63A5\uFF1A\n\\u2011\u54D4\u54E9\u54D4\u54E9\n\\u2011\u7F51\u6613\u4E91\u97F3\u4E50\n\\u2011\u6E38\u620F\u66F2\u7ED8\uFF1A@\u80D6\u5934\u9C7C\n\\u2011\u8C31\u9762\u8BBE\u8BA1\uFF1A@\u6668\u5CE6\n\\u2011\u6F14\u5531\uFF1A@\u6D1B\u5929\u4F9D\n" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: d17f214eb2e14e74c95fdc4e99b0187d, type: 2} + m_sharedMaterial: {fileID: -7204877318828142287, guid: d17f214eb2e14e74c95fdc4e99b0187d, 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_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_characterHorizontalScale: 1 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &576191398 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576191394} + m_CullTransparentMesh: 1 +--- !u!114 &576191399 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576191394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 113584774ebb6f27aa836f931023d9cf, type: 3} + m_Name: + m_EditorClassIdentifier: CyanStars.MarkdownRenderer::CyanStars.MarkdownRenderer.TextMeshProMarkdownConfigBehaviour + config: + CodeBlockBackgroundColor: {r: 0.533, g: 0.533, b: 0.533, a: 1} + AtColor: {r: 1, g: 0.8392157, b: 0.078431375, a: 0.87} + LinkColor: {r: 1, g: 0.841, b: 0.078, a: 0.87} + LinkPrefix: __md_link__ + UnorderedListMarker: \u2011 +--- !u!114 &576191400 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576191394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 01edf5553eb2657468374e38f3c06a3b, type: 3} + m_Name: + m_EditorClassIdentifier: CyanStars.MarkdownRenderer.Tests::CyanStars.MarkdownRenderer.Tests.LogCollectedAtInfo +--- !u!114 &576191401 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 576191394} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ccec54e473dc4d13afb07d1e9aea6ed6, type: 3} + m_Name: + m_EditorClassIdentifier: CyanStars.MarkdownRenderer::CyanStars.MarkdownRenderer.TextMeshProMarkdownAtInfoCollector + onAtInfoCollected: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 576191400} + m_TargetAssemblyTypeName: CyanStars.MarkdownRenderer.Tests.LogCollectedAtInfo, + CyanStars.MarkdownRenderer.Tests + m_MethodName: Print + m_Mode: 0 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 1 +--- !u!1 &817239468 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 817239471} + - component: {fileID: 817239470} + - component: {fileID: 817239469} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &817239469 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 817239468} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.EventSystems.StandaloneInputModule + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &817239470 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 817239468} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.EventSystems.EventSystem + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &817239471 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 817239468} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1999387934 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1999387937} + - component: {fileID: 1999387936} + - component: {fileID: 1999387935} + - component: {fileID: 1999387938} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1999387935 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1999387934} + m_Enabled: 1 +--- !u!20 &1999387936 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1999387934} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1999387937 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1999387934} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1999387938 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1999387934} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalAdditionalCameraData + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 + m_Version: 2 +--- !u!1 &2116993316 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2116993320} + - component: {fileID: 2116993319} + - component: {fileID: 2116993318} + - component: {fileID: 2116993317} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2116993317 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116993316} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.GraphicRaycaster + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &2116993318 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116993316} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.CanvasScaler + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &2116993319 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116993316} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 25 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &2116993320 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2116993316} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 576191395} + m_Father: {fileID: 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_Pivot: {x: 0, y: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1999387937} + - {fileID: 2116993320} + - {fileID: 817239471} diff --git a/Cyan-Stars/Assets/Scenes/MarkdownTest.unity.meta b/Cyan-Stars/Assets/Scenes/MarkdownTest.unity.meta new file mode 100644 index 000000000..f73e8a5cf --- /dev/null +++ b/Cyan-Stars/Assets/Scenes/MarkdownTest.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cda9d079fafedc2d7a4d4359803e5964 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx.meta new file mode 100644 index 000000000..7f31ab9b1 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e908e15d58b0e83d8100c3db5b6e227 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor.meta new file mode 100644 index 000000000..4dd79004e --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 87355c240274de66498a1fa1cd709234 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/IPOL.UnityEx.Editor.asmdef b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/IPOL.UnityEx.Editor.asmdef new file mode 100644 index 000000000..aaa6cd769 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/IPOL.UnityEx.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "IPOL.UnityEx.Editor", + "rootNamespace": "IPOL.UnityEx.Editor", + "references": [ + "GUID:4988cf9794f41d64c884876ab6574b89", + "GUID:d1aaf193c9c425bf18d52ed9d5dbd031" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/IPOL.UnityEx.Editor.asmdef.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/IPOL.UnityEx.Editor.asmdef.meta new file mode 100644 index 000000000..e992e4d60 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/IPOL.UnityEx.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0eacb1753cfaea294adf1e4afdedc7ed +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/ObjectRefEditor.cs b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/ObjectRefEditor.cs new file mode 100644 index 000000000..256cb141b --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/ObjectRefEditor.cs @@ -0,0 +1,90 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; +using UnityObject = UnityEngine.Object; + +namespace Ipol.UnityEx.Editor +{ + [CustomPropertyDrawer(typeof(ObjectRef<>))] + public class ObjectRefEditor : PropertyDrawer + { + private const string ValueName = ObjectRef.ValueFieldName; + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var value = property.FindPropertyRelative(ValueName); + var foldout = new Foldout { value = property.isExpanded }; + var objectField = new ObjectField(property.displayName) + { + objectType = GetObjectType(), + allowSceneObjects = true + }; + ModifyObjectFieldStyle(objectField); + var content = new VisualElement(); + + objectField.BindProperty(value); + AddObjectFieldToFoldoutHeader(foldout, objectField); + foldout.Add(content); + + foldout.RegisterValueChangedCallback(change => property.isExpanded = change.newValue); + objectField.RegisterValueChangedCallback(change => PopulateProperties(content, change.newValue)); + PopulateProperties(content, value.objectReferenceValue); + + return foldout; + } + + private static void ModifyObjectFieldStyle(ObjectField objectField) + { + objectField.AddToClassList("unity-base-field__aligned"); + objectField.style.flexGrow = 1; + objectField.style.marginLeft = 1; + objectField.style.marginRight = 1; + + var label = objectField.labelElement; + label.style.marginLeft = 0; + } + + private static void AddObjectFieldToFoldoutHeader(Foldout foldout, ObjectField objectField) + { + var toggle = foldout.Q(className: Foldout.toggleUssClassName); + toggle.Children().First().style.flexGrow = 0; + toggle.Add(objectField); + + objectField.RegisterCallback(change => change.StopPropagation()); + } + + private static void PopulateProperties(VisualElement content, UnityObject referencedObject) + { + content.Unbind(); + content.Clear(); + + if (referencedObject == null) + return; + + var serializedObject = new SerializedObject(referencedObject); + var iterator = serializedObject.GetIterator(); + var enterChildren = true; + + while (iterator.NextVisible(enterChildren)) + { + enterChildren = false; + + if (iterator.propertyPath != "m_Script") + content.Add(new PropertyField { bindingPath = iterator.propertyPath }); + } + + content.Bind(serializedObject); + } + + private Type GetObjectType() + { + return fieldInfo.FieldType.IsGenericType + ? fieldInfo.FieldType.GetGenericArguments()[0] + : typeof(UnityObject); + } + + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/ObjectRefEditor.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/ObjectRefEditor.cs.meta new file mode 100644 index 000000000..9799a35b3 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Editor/ObjectRefEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: be270f99145511f86967ff0b673153d6 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime.meta new file mode 100644 index 000000000..a71da28dd --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 98e6d958feffd37789fe4472053be74f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/AssemblyInfo.cs b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/AssemblyInfo.cs new file mode 100644 index 000000000..6f41312b4 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/AssemblyInfo.cs @@ -0,0 +1 @@ +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Ipol.UnityEx.Editor")] \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/AssemblyInfo.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/AssemblyInfo.cs.meta new file mode 100644 index 000000000..6c72fc922 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/AssemblyInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 41a666497eadab06a9f70ee49e216fc8 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/IPOL.UnityEx.Runtime.asmdef b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/IPOL.UnityEx.Runtime.asmdef new file mode 100644 index 000000000..5992f0475 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/IPOL.UnityEx.Runtime.asmdef @@ -0,0 +1,14 @@ +{ + "name": "IPOL.UnityEx.Runtime", + "rootNamespace": "IPOL.UnityEx", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/IPOL.UnityEx.Runtime.asmdef.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/IPOL.UnityEx.Runtime.asmdef.meta new file mode 100644 index 000000000..fad6bc553 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/IPOL.UnityEx.Runtime.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d1aaf193c9c425bf18d52ed9d5dbd031 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/ObjectRef.cs b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/ObjectRef.cs new file mode 100644 index 000000000..6c88e6481 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/ObjectRef.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +namespace Ipol.UnityEx +{ + [System.Serializable] + public class ObjectRef where T : class + { + internal const string ValueFieldName = nameof(value); + + [SerializeField] private Object value; + + public T Value => value as T; + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/ObjectRef.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/ObjectRef.cs.meta new file mode 100644 index 000000000..26cef75c1 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/IpolUnityEx/Runtime/ObjectRef.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 893ddcd141224e7aea4c20607601b7f6 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer.meta new file mode 100644 index 000000000..29db90d48 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a503dce2d66569a049b897878a7a58f3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor.meta new file mode 100644 index 000000000..aae990c37 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 055d588beb17842419943044e69e97fb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/CyanStars.MarkdownRenderer.Editor.asmdef b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/CyanStars.MarkdownRenderer.Editor.asmdef new file mode 100644 index 000000000..e2122725d --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/CyanStars.MarkdownRenderer.Editor.asmdef @@ -0,0 +1,19 @@ +{ + "name": "CyanStars.MarkdownRenderer.Editor", + "rootNamespace": "CyanStars.MarkdownRenderer.Editor", + "references": [ + "GUID:4988cf9794f41d64c884876ab6574b89", + "GUID:f86fff73e27070d2b9a01de1a73ed02f" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/CyanStars.MarkdownRenderer.Editor.asmdef.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/CyanStars.MarkdownRenderer.Editor.asmdef.meta new file mode 100644 index 000000000..9a4bd32f0 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/CyanStars.MarkdownRenderer.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 654ab16b094d978eea7208c1b798602a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/TextMeshProMarkdownConfigDrawer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/TextMeshProMarkdownConfigDrawer.cs new file mode 100644 index 000000000..2373a6bed --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/TextMeshProMarkdownConfigDrawer.cs @@ -0,0 +1,29 @@ +using UnityEditor; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace CyanStars.MarkdownRenderer.Editor +{ + [CustomPropertyDrawer(typeof(TextMeshProMarkdownConfig))] + public class TextMeshProMarkdownConfigDrawer : PropertyDrawer + { + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + var content = new VisualElement(); + var endProperty = property.GetEndProperty(); + + if (!property.NextVisible(true)) + { + return content; + } + + do + { + content.Add(new PropertyField(property)); + } + while (property.NextVisible(false) && !SerializedProperty.EqualContents(property, endProperty)); + + return content; + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/TextMeshProMarkdownConfigDrawer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/TextMeshProMarkdownConfigDrawer.cs.meta new file mode 100644 index 000000000..5a6e1fec1 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Editor/TextMeshProMarkdownConfigDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b443430b513bc4da0a73c1c4e8118d33 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime.meta new file mode 100644 index 000000000..e8a3989e7 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa63f730bf0736d15981a3ec161aa177 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/CyanStars.MarkdownRenderer.asmdef b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/CyanStars.MarkdownRenderer.asmdef new file mode 100644 index 000000000..58aa169dd --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/CyanStars.MarkdownRenderer.asmdef @@ -0,0 +1,19 @@ +{ + "name": "CyanStars.MarkdownRenderer", + "rootNamespace": "", + "references": [ + "GUID:6055be8ebefd69e48b49212b09b47b2f", + "GUID:d1aaf193c9c425bf18d52ed9d5dbd031" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "Markdig.dll" + ], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/CyanStars.MarkdownRenderer.asmdef.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/CyanStars.MarkdownRenderer.asmdef.meta new file mode 100644 index 000000000..48e1708a0 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/CyanStars.MarkdownRenderer.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f86fff73e27070d2b9a01de1a73ed02f +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions.meta new file mode 100644 index 000000000..4c0297404 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4c62c35e916c4e629bb257f440c12b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions/InlineEnumeratorExtensions.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions/InlineEnumeratorExtensions.cs new file mode 100644 index 000000000..341525da2 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions/InlineEnumeratorExtensions.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer +{ + public static class ContainerInlineExtensions + { + public static IEnumerable FindDescendants(this ContainerInline container) + where T1 : Inline + where T2 : Inline + { + Stack stack = new Stack(); + for (Inline child = container.LastChild; child != null; child = child.PreviousSibling) + { + stack.Push(child); + } + + while (stack.Count > 0) + { + Inline child = stack.Pop(); + if (child is T1 val1) + { + yield return val1; + } + else if (child is T2 val2) + { + yield return val2; + } + + if (child is ContainerInline containerInline) + { + for (child = containerInline.LastChild; child != null; child = child.PreviousSibling) + { + stack.Push(child); + } + } + } + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions/InlineEnumeratorExtensions.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions/InlineEnumeratorExtensions.cs.meta new file mode 100644 index 000000000..920f43cb1 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Extensions/InlineEnumeratorExtensions.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7e818299da3838b71bf5fd6a1c107558 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers.meta new file mode 100644 index 000000000..11fe5e948 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17089e9f3ab8830f99c6f06a9fdf32f0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers/AtParagraphInlineParser.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers/AtParagraphInlineParser.cs new file mode 100644 index 000000000..6e690ecfc --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers/AtParagraphInlineParser.cs @@ -0,0 +1,94 @@ +using CyanStars.MarkdownRenderer.Renderers; +using CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines; +using Markdig; +using Markdig.Helpers; +using Markdig.Parsers; +using Markdig.Parsers.Inlines; +using Markdig.Renderers; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer.Parsers +{ + public sealed class AtParagraphInline : LinkInline + { + public AtParagraphInline(string paragraph) + { + Paragraph = paragraph; + Label = "@" + paragraph; + Url = string.Empty; + } + + public string Paragraph { get; } + } + + public sealed class AtParagraphInlineParser : InlineParser + { + public AtParagraphInlineParser() + { + OpeningCharacters = new[] { '[' }; + } + + public override bool Match(InlineProcessor processor, ref StringSlice slice) + { + var start = slice.Start; + if (slice.CurrentChar != '[' || slice.PeekChar() != '@') + { + return false; + } + + var closingBracketIndex = slice.Text.IndexOf(']', start + 2, slice.End - start - 1); + if (closingBracketIndex < 0 || closingBracketIndex == start + 2 || + (closingBracketIndex < slice.End && (slice.Text[closingBracketIndex + 1] == '(' || slice.Text[closingBracketIndex + 1] == '['))) + { + return false; + } + + var paragraph = slice.Text.Substring(start + 2, closingBracketIndex - start - 2); + var sourceStart = processor.GetSourcePosition(start, out var line, out var column); + var sourceEnd = processor.GetSourcePosition(closingBracketIndex); + var labelStart = processor.GetSourcePosition(start + 1); + + var inline = new AtParagraphInline(paragraph) + { + IsClosed = true, + Span = new SourceSpan(sourceStart, sourceEnd), + Line = line, + Column = column, + }; + inline.AppendChild(new LiteralInline + { + Content = new StringSlice(slice.Text, start + 1, closingBracketIndex - 1), + IsClosed = true, + Span = new SourceSpan(labelStart, sourceEnd - 1), + Line = line, + Column = column + 1, + }); + + slice.Start = closingBracketIndex + 1; + processor.Inline = inline; + return true; + } + } + + public sealed class AtParagraphExtension : IMarkdownExtension + { + public void Setup(MarkdownPipelineBuilder pipeline) + { + if (pipeline.InlineParsers.FindExact() == null) + { + pipeline.InlineParsers.InsertBefore(new AtParagraphInlineParser()); + } + } + + public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) + { + if (renderer is TextMeshProRenderer textMeshProRenderer && + textMeshProRenderer.ObjectRenderers.FindExact() == null && + !textMeshProRenderer.ObjectRenderers.InsertBefore(new AtParagraphInlineRenderer())) + { + textMeshProRenderer.ObjectRenderers.Add(new AtParagraphInlineRenderer()); + } + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers/AtParagraphInlineParser.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers/AtParagraphInlineParser.cs.meta new file mode 100644 index 000000000..35e1f101c --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Parsers/AtParagraphInlineParser.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 062d3302c2e64566a0f6e38e33c9d50c \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers.meta new file mode 100644 index 000000000..fde4491cf --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 884ab26450b799842b240b2a92db5db3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro.meta new file mode 100644 index 000000000..3e919e603 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f3151c021774303a1b220838d1bfa251 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HeadingRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HeadingRenderer.cs new file mode 100644 index 000000000..0c4ee3ec4 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HeadingRenderer.cs @@ -0,0 +1,57 @@ +// Copyright (c) Alexandre Mutel. All rights reserved. +// This file is licensed under the BSD-Clause 2 license. +// See the license.txt file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Markdig; +using Markdig.Parsers; +using Markdig.Renderers; +using Markdig.Syntax; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro +{ + public class HeadingRenderer : MarkdownObjectRenderer + { + private static readonly string[] HeadingTextSizes = new string[] + { + "200%", + "150%", + "117%", + "100%", + "83%", + "67%", + }; + + protected override void Write(TextMeshProRenderer renderer, HeadingBlock obj) + { + int index = obj.Level - 1; + + if ((uint)index >= (uint)HeadingTextSizes.Length) + { + renderer.WriteLeafInline(obj); + } + else + { + renderer.PushTag("size", HeadingTextSizes[index]) + .WriteLeafInline(obj) + .TryPopTag(out _); + } + + renderer.FinishBlock(true); + } + } + + // public class ThematicBreakRenderer : MarkdownObjectRenderer + // { + // protected override void Write(TextMeshProRenderer renderer, ThematicBreakBlock obj) + // { + // renderer.EnsureLine(); + // renderer.WriteLine("
"); + // renderer.EnsureLine(); + // } + // } + +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HeadingRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HeadingRenderer.cs.meta new file mode 100644 index 000000000..5f90988f8 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HeadingRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e28184f3978e9c68bb7ced40e262e664 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HtmlBlockRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HtmlBlockRenderer.cs new file mode 100644 index 000000000..d5cf4e6a6 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HtmlBlockRenderer.cs @@ -0,0 +1,42 @@ +// Copyright (c) Alexandre Mutel. All rights reserved. +// This file is licensed under the BSD-Clause 2 license. +// See the license.txt file in the project root for more information. + +using Markdig.Renderers; +using Markdig.Syntax; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro +{ + public class HtmlBlockRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, HtmlBlock obj) + { + var slices = obj.Lines.Lines; + if (!(slices is null)) + { + for (int i = 0; i < slices.Length; i++) + { + ref var slice = ref slices[i].Slice; + if (slice.Text is null) + { + break; + } + + renderer.Write(slice.AsSpan()); + renderer.WriteLine(); + } + } + } + } + + // public class ThematicBreakRenderer : MarkdownObjectRenderer + // { + // protected override void Write(TextMeshProRenderer renderer, ThematicBreakBlock obj) + // { + // renderer.EnsureLine(); + // renderer.WriteLine("
"); + // renderer.EnsureLine(); + // } + // } + +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HtmlBlockRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HtmlBlockRenderer.cs.meta new file mode 100644 index 000000000..d36815f97 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/HtmlBlockRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 129c43ea607c444059ba9cd215513f04 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines.meta new file mode 100644 index 000000000..5ead59e78 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5afc8993fc26bd0f0b08ac2015982a53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/AtParagraphInlineRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/AtParagraphInlineRenderer.cs new file mode 100644 index 000000000..aba561eb4 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/AtParagraphInlineRenderer.cs @@ -0,0 +1,15 @@ +using CyanStars.MarkdownRenderer.Parsers; +using Markdig.Renderers; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines +{ + public sealed class AtParagraphInlineRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, AtParagraphInline obj) + { + renderer.PushTag("link", obj.Url, valuePrefix: renderer.Config.AtColorHex); + renderer.WriteChildren(obj); + renderer.TryPopTag(out _); + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/AtParagraphInlineRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/AtParagraphInlineRenderer.cs.meta new file mode 100644 index 000000000..0325131ac --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/AtParagraphInlineRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d9e704fd2d88e1ec397f34bc85d2df9e \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/CodeInlineRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/CodeInlineRenderer.cs new file mode 100644 index 000000000..be8e44cb2 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/CodeInlineRenderer.cs @@ -0,0 +1,42 @@ +using System; +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines +{ + public class CodeInlineRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, CodeInline obj) + { + renderer.PushTag("mark", renderer.Config.CodeBlockBackgroundColorHex, valuePrefix: "#") + .PushTag("noparse"); + WriteContent(renderer, obj.Content.AsSpan()); + renderer.TryPopTag(out _); + renderer.TryPopTag(out _); + } + + private void WriteContent(TextMeshProRenderer renderer, ReadOnlySpan content) + { + if (content.IsEmpty) + { + return; + } + + foreach (var c in content) + { + if (c == '\\') + { + renderer.WriteRaw(@"\\"); + } + else if (c == '\n') + { + renderer.Write(c); + } + else + { + renderer.WriteRaw(c); + } + } + } + } +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/CodeInlineRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/CodeInlineRenderer.cs.meta new file mode 100644 index 000000000..02dec49be --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/CodeInlineRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 331bd3107bc1a17d289a5457107a655f \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/EmphasisInlineRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/EmphasisInlineRenderer.cs new file mode 100644 index 000000000..e657d14b5 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/EmphasisInlineRenderer.cs @@ -0,0 +1,16 @@ +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines +{ + public class EmphasisInlineRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, EmphasisInline obj) + { + string tag = obj.DelimiterCount == 2 ? "b" : "i"; + renderer.PushTag(tag); + renderer.WriteChildren(obj); + renderer.TryPopTag(out _); + } + } +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/EmphasisInlineRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/EmphasisInlineRenderer.cs.meta new file mode 100644 index 000000000..d9c7bfae7 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/EmphasisInlineRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ee04adfd3316413a3872a76941e11c74 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LineBreakInlineRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LineBreakInlineRenderer.cs new file mode 100644 index 000000000..d204e0537 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LineBreakInlineRenderer.cs @@ -0,0 +1,25 @@ +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines +{ + public class LineBreakInlineRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, LineBreakInline obj) + { + if (renderer.IsLastInContainer) + { + return; + } + + if (obj.IsHard) + { + renderer.WriteRaw("
"); + } + else + { + renderer.WriteRaw(' '); + } + } + } +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LineBreakInlineRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LineBreakInlineRenderer.cs.meta new file mode 100644 index 000000000..516c90340 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LineBreakInlineRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6f2c9a14b7d84e3a9c01d5f2e8b347a6 diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LinkInlineRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LinkInlineRenderer.cs new file mode 100644 index 000000000..2c2efe652 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LinkInlineRenderer.cs @@ -0,0 +1,29 @@ +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines +{ + public class LinkInlineRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, LinkInline obj) + { + renderer.PushTag("color", renderer.Config.LinkColorHex, valuePrefix: "#") + .PushTag("u"); + + renderer.WriteRaw(""); + renderer.WriteChildren(obj); + renderer.WriteRaw(""); + + renderer.TryPopTag(out _); + renderer.TryPopTag(out _); + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LinkInlineRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LinkInlineRenderer.cs.meta new file mode 100644 index 000000000..a8f3b4229 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LinkInlineRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c621595341457ff0697cedbd896a94bd \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LiteralInlineRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LiteralInlineRenderer.cs new file mode 100644 index 000000000..bc26fe8b7 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LiteralInlineRenderer.cs @@ -0,0 +1,27 @@ +using System; +using Markdig.Renderers; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines +{ + public class LiteralInlineRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, LiteralInline obj) + { + var span = obj.Content.AsSpan(); + if (span.Length == 1 && span[0] == '\\') + { + renderer.Write(@"\\"); + } + else if (span.Length == 2 && span[0] == '\\' && span[1] == '\\') + { + renderer.Write(@"\\\\"); + } + else + { + renderer.Write(ref obj.Content); + } + + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LiteralInlineRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LiteralInlineRenderer.cs.meta new file mode 100644 index 000000000..a47505d53 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/Inlines/LiteralInlineRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7ad88bac5234e51eeb691c7b6d968069 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ListRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ListRenderer.cs new file mode 100644 index 000000000..f0708970c --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ListRenderer.cs @@ -0,0 +1,108 @@ +using Markdig.Renderers; +using Markdig.Syntax; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro +{ + public class ListRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, ListBlock obj) + { + renderer.EnsureLine(); + renderer.PushNestingLevel(); + + var compact = renderer.IsCompactParagraph; + renderer.IsCompactParagraph = !obj.IsLoose; + + try + { + if (obj.IsOrdered) + { + WriteOrderedList(renderer, obj); + } + else + { + WriteUnorderedList(renderer, obj); + } + + if (renderer.NestingLevel == 1) + { + renderer.FinishBlock(true); + } + } + finally + { + renderer.IsCompactParagraph = compact; + renderer.PopNestingLevel(); + } + } + + private void WriteOrderedList(TextMeshProRenderer renderer, ListBlock obj) + { + int start = 1; + if (!(obj.OrderedStart is null)) + { + int.TryParse(obj.OrderedStart, out start); + } + + int index = start; + foreach (ListItemBlock item in obj) + { + renderer.EnsureLine(); + WriteListItem(renderer, item, $"{index++}.", 0); + } + } + + private void WriteUnorderedList(TextMeshProRenderer renderer, ListBlock obj) + { + var unorderedListMarker = renderer.Config.UnorderedListMarker; + foreach (ListItemBlock item in obj) + { + renderer.EnsureLine(); + WriteListItem(renderer, item, unorderedListMarker, -0.5); + } + } + + private void WriteListItem(TextMeshProRenderer renderer, ListItemBlock item, string marker, double contentIndentOffset) + { + int depth = renderer.NestingLevel; + renderer.PushTag("indent", (depth - 1).ToString(), valueSuffix: "em") + .Write(marker) + .TryPopTag(out _); + renderer.PushTag("indent", (depth + contentIndentOffset).ToString(), valueSuffix: "em"); + + bool isClosed = false; + + foreach (var block in item) + { + if (block is ListBlock or QuoteBlock) + { + if (!isClosed) + { + renderer.TryPopTag(out _); + isClosed = true; + } + + renderer.EnsureLine(); + renderer.Write(block); + continue; + } + + renderer.Write(block); + renderer.TryPopTag(out _); + isClosed = true; + } + + } + } + + // public class ThematicBreakRenderer : MarkdownObjectRenderer + // { + // protected override void Write(TextMeshProRenderer renderer, ThematicBreakBlock obj) + // { + // renderer.EnsureLine(); + // renderer.WriteLine("
"); + // renderer.EnsureLine(); + // } + // } + +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ListRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ListRenderer.cs.meta new file mode 100644 index 000000000..08a553526 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ListRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fa1a6884e4328da6388bd2a0a0d7ca2d \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ParagraphRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ParagraphRenderer.cs new file mode 100644 index 000000000..a0aeee71d --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ParagraphRenderer.cs @@ -0,0 +1,25 @@ +using Markdig.Renderers; +using Markdig.Syntax; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro +{ + public class ParagraphRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, ParagraphBlock obj) + { + renderer.WriteLeafInline(obj); + renderer.FinishBlock(!renderer.IsCompactParagraph); + } + } + + // public class ThematicBreakRenderer : MarkdownObjectRenderer + // { + // protected override void Write(TextMeshProRenderer renderer, ThematicBreakBlock obj) + // { + // renderer.EnsureLine(); + // renderer.WriteLine("
"); + // renderer.EnsureLine(); + // } + // } + +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ParagraphRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ParagraphRenderer.cs.meta new file mode 100644 index 000000000..8aa1d16b8 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/ParagraphRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9253a5fafd1b3340ab8fdb36a2d9842d \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/QuoteBlockRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/QuoteBlockRenderer.cs new file mode 100644 index 000000000..8aaf4196f --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/QuoteBlockRenderer.cs @@ -0,0 +1,209 @@ +using Markdig.Renderers; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; + +namespace CyanStars.MarkdownRenderer.Renderers.TextMeshPro +{ + public class QuoteBlockRenderer : MarkdownObjectRenderer + { + protected override void Write(TextMeshProRenderer renderer, QuoteBlock obj) + { + renderer.EnsureLine(); + + renderer.QuoteLevel++; + + try + { + int contentNestingLevel = renderer.NestingLevel + renderer.QuoteLevel; + bool isFirstQuote = renderer.QuoteLevel == 1; + + if (isFirstQuote) + { + if (renderer.NestingLevel > 0) + { + // note: 当前只有 list 会修改全局 markdown 嵌套层级 + // 可以认定当前 quote block 是 list 的子项 + // 直接先给一点 Spacing 防止两个块元素靠得太近 + renderer.EnsureSpacing("6"); + } + + renderer.PushTag("color", renderer.Config.QuoteColorHex, valuePrefix: "#"); + } + + var contentNestingLevelString = contentNestingLevel.ToString(); + + for (int i = 0; i < obj.Count; i++) + { + if (i > 0) + { + renderer.EnsureLine(); + } + + Block block = obj[i]; + + if (block is QuoteBlock innerQuoteBlock) + { + Write(renderer, innerQuoteBlock); + } + else + { + WriteQuoteMarker(renderer, renderer.QuoteLevel, renderer.NestingLevel, false); + + if (block is ParagraphBlock paragraph) + { + // 引用块内的段落:内部换行时在新的一行重复输出 mark + // 基本上复制了 paragraph block inlines 的处理逻辑 + // 如果 paragraph renderer 有更改,记得检查这里 + WriteParagraphInlines(renderer, paragraph, renderer.NestingLevel, contentNestingLevelString); + } + else + { + renderer.PushTag("indent", contentNestingLevelString, valueSuffix: "em") + .Write(block); + renderer.TryPopTag(out _); + } + } + + TryEnsureQuoteEmptyLine(renderer, obj, renderer.NestingLevel, i); + } + + if (isFirstQuote) + { + renderer.TryPopTag(out _); + } + + if (contentNestingLevel == 1) + { + renderer.FinishBlock(true); + } + } + finally + { + renderer.QuoteLevel--; + } + } + + private void TryEnsureQuoteEmptyLine(TextMeshProRenderer renderer, QuoteBlock obj, + int lineNestingLevel, int i) + { + if (renderer.Config.QuoteSpacing <= 0) + { + return; + } + + var block = obj[i]; + if (i >= obj.Count - 1 || block is not ParagraphBlock) + { + return; + } + + Block nextBlock = obj[i + 1]; + if (nextBlock is not ParagraphBlock && nextBlock is not QuoteBlock) + { + return; + } + + renderer.PushTag("line-height", renderer.QuoteSpacing, valueSuffix: "em"); + renderer.EnsureLine(); + + // 如果渲染空白的引用块(相邻引用块的间距部分) + // 就往空引用块的同一行输出一个透明字符 + // 确保 TMP 不会丢弃通过空格渲染的引用块 mark 部分 + if (renderer.Config.QuoteWidth > 0) + { + WriteQuoteMarker(renderer, renderer.QuoteLevel, lineNestingLevel, true); + renderer.PushTag("color", "#00000000"); + renderer.Write('*'); + renderer.PopTag(1); + } + + renderer.PopTag(1); + renderer.WriteLine(); + } + + private void WriteQuoteMarker(TextMeshProRenderer renderer, int count, int lineNestingLevel, bool isBlankLine) + { +// + + if (renderer.Config.QuoteWidth <= 0) + { + return; + } + + bool isOverrideSize = isBlankLine && renderer.Config.QuoteSpacing > 1; + + for (int i = 0; i < count; i++) + { + //renderer.Write(renderer.Config.QuoteMarker); + + var indent = (i - renderer.HalfQuoteMarkerWidth + lineNestingLevel).ToString("0.###", System.Globalization.CultureInfo.InvariantCulture); + renderer.PushTag("indent", indent, valueSuffix: "em") + .PushTag("mspace", renderer.QuoteMarkerWidth, valueSuffix: "em"); + + if (isOverrideSize) + { + renderer.PushTag("size", renderer.QuoteSpacing, valueSuffix: "em"); + } + + renderer.PushTag("mark", renderer.Config.QuoteColorHex, valuePrefix: "#") + .WriteRaw(' '); + renderer.PopTag(isOverrideSize ? 4 : 3); + + if (i < count - 1) + { + renderer.WriteRaw(' '); + } + } + } + + private void WriteParagraphInlines(TextMeshProRenderer renderer, ParagraphBlock paragraph, + int lineNestingLevel, string contentNestingLevelString) + { + renderer.PushTag("indent", contentNestingLevelString, valueSuffix: "em"); + + var root = paragraph.Inline; + if (root != null) + { + for (Inline child = root.FirstChild; child != null; child = child.NextSibling) + { + if (child is LineBreakInline lineBreak) + { + if (child.NextSibling == null) + { + continue; + } + + if (!lineBreak.IsHard) + { + renderer.WriteRaw(' '); + continue; + } + + // 硬换行:新的一行重复输出 mark + renderer.TryPopTag(out _); + renderer.WriteLine(); + WriteQuoteMarker(renderer, renderer.QuoteLevel, lineNestingLevel, false); + renderer.PushTag("indent", contentNestingLevelString, valueSuffix: "em"); + } + else + { + renderer.Write(child); + } + } + } + + renderer.TryPopTag(out _); + } + } + + // public class ThematicBreakRenderer : MarkdownObjectRenderer + // { + // protected override void Write(TextMeshProRenderer renderer, ThematicBreakBlock obj) + // { + // renderer.EnsureLine(); + // renderer.WriteLine("
"); + // renderer.EnsureLine(); + // } + // } + +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/QuoteBlockRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/QuoteBlockRenderer.cs.meta new file mode 100644 index 000000000..70371044a --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshPro/QuoteBlockRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1c5e3b9e08a31520e9ab7e476e9cf280 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshProRenderer.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshProRenderer.cs new file mode 100644 index 000000000..32dfc9599 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshProRenderer.cs @@ -0,0 +1,220 @@ +#nullable enable + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using Markdig.Renderers; +using CyanStars.MarkdownRenderer.Renderers.TextMeshPro; +using CyanStars.MarkdownRenderer.Renderers.TextMeshPro.Inlines; +using System.Collections.Generic; + +namespace CyanStars.MarkdownRenderer.Renderers +{ + public class TextMeshProRenderer : TextRendererBase + { + public TextMeshProMarkdownConfig Config { get; set; } = TextMeshProMarkdownConfig.DefaultConfig; + + public int NestingLevel { get; private set; } + public int QuoteLevel { get; set; } + public bool IsCompactParagraph { get; set; } + + + // computed properties form config + public string? BlockFakeMarginBottom { get; private set; } + public string? QuoteSpacing { get; private set; } + public string? QuoteMarkerWidth { get; private set; } + public double HalfQuoteMarkerWidth { get; private set; } + + public readonly struct TmpTagItem + { + public readonly string TagName; + public readonly string? Value; + public readonly bool IsWrited; + + public TmpTagItem(string tagName, string? value, bool isWrited) + { + TagName = tagName; + Value = value; + IsWrited = isWrited; + } + } + + private Stack tags; + + public TextMeshProRenderer(TextWriter writer) : base(writer) + { + // Block renderers + AddRenderers( + new ListRenderer(), + new HeadingRenderer(), + new HtmlBlockRenderer(), + new ParagraphRenderer(), + new QuoteBlockRenderer() + ); + + // Inline renderers + AddRenderers( + new CodeInlineRenderer(), + new EmphasisInlineRenderer(), + new LineBreakInlineRenderer(), + new LinkInlineRenderer(), + new LiteralInlineRenderer() + ); + + tags = new Stack(32); + ComputeConfig(); + } + + private void AddRenderers(params IMarkdownObjectRenderer[] renderers) + { + ObjectRenderers.AddRange(renderers); + } + + public void FinishBlock(bool appendFakeMarginBottom) + { + if (IsLastInContainer || tags.Count > 0) + return; + + EnsureLine(); + + if (!appendFakeMarginBottom) + { + return; + } + + if (Config.FinishBlockBehavior == FinishBlockBehavior.FakeMargin && + !string.IsNullOrEmpty(BlockFakeMarginBottom)) + { + WriteFakeMarginBottom(); + } + else if (Config.FinishBlockBehavior == FinishBlockBehavior.EmptyLine) + { + WriteLine(); + } + } + + private void WriteFakeMarginBottom() + { + WriteRaw(""); + WriteLine(); + WriteRaw(""); + } + + internal TextMeshProRenderer EnsureSpacing(string size) + { + if (!base.previousWasLine) + return this; + + WriteRaw(""); + WriteLine(); + WriteRaw(""); + return this; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteRaw(string? content) => Writer.Write(content); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteRaw(char content) => Writer.Write(content); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteRaw(ReadOnlySpan content) => Writer.Write(content); + + public void PushNestingLevel() => NestingLevel++; + + public void PopNestingLevel() + { + if (NestingLevel < 0) + { + throw new InvalidOperationException("Nesting level cannot be negative."); + } + NestingLevel--; + } + + public void ResetRecordedProps() + { + NestingLevel = 0; + QuoteLevel = 0; + IsCompactParagraph = false; + tags.Clear(); + base.Reset(); + } + + public TextMeshProRenderer PushTag(string tagName, string? value = null, + string? valuePrefix = null, string? valueSuffix = null, + bool isWrite = true) + { + tags.Push(new TmpTagItem(tagName, value, isWrite)); + + if (!isWrite) + { + return this; + } + + WriteRaw('<'); + WriteRaw(tagName); + if (value != null) + { + WriteRaw('='); + if (valuePrefix != null) + { + WriteRaw(valuePrefix); + } + WriteRaw(value); + if (valueSuffix != null) + { + WriteRaw(valueSuffix); + } + } + WriteRaw('>'); + return this; + } + + public bool TryPopTag(out TmpTagItem tag) + { + bool success = tags.TryPop(out tag); + if (tag.IsWrited) + { + WriteRaw("'); + } + return success; + } + + public bool PopTag(int count) + { + for (int i = 0; i < count; i++) + { + if (!TryPopTag(out _)) + { + return false; + } + } + return true; + } + + public void ComputeConfig() + { + BlockFakeMarginBottom = Config.BlockFakeMarginBottom <= 0 + ? string.Empty + : Config.BlockFakeMarginBottom.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture); + + QuoteSpacing = Config.QuoteSpacing <= 0 + ? string.Empty + : Config.QuoteSpacing.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture); + + QuoteMarkerWidth = Config.QuoteWidth <= 0 + ? string.Empty + : Config.QuoteWidth.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture); + + HalfQuoteMarkerWidth = Config.QuoteWidth <= 0 ? 0 : Config.QuoteWidth / 2.0; + + //: (Math.Round(Config.BlockFakeMarginBottom * 1000) / 1000.0).ToString(); + } + } +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshProRenderer.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshProRenderer.cs.meta new file mode 100644 index 000000000..07c653cdc --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/Renderers/TextMeshProRenderer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 50b13d89154278b89b12e403f38bdd5e \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdown.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdown.cs new file mode 100644 index 000000000..b6e9a698c --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdown.cs @@ -0,0 +1,157 @@ +using CyanStars.MarkdownRenderer.Parsers; +using CyanStars.MarkdownRenderer.Renderers; +using System.Text; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using TMPro; +using Markdig; +using Markdig.Syntax; +using UnityEngine.Assertions; +using System.IO; +using Ipol.UnityEx; + +namespace CyanStars.MarkdownRenderer +{ + [RequireComponent(typeof(TextMeshProUGUI))] + [ExecuteAlways] + public class TextMeshProMarkdown : UIBehaviour + { + private TextMeshProUGUI renderTarget; + private TextMeshProRenderer toTextMeshProRenderer; + + private MarkdownPipeline pipeline; + + [SerializeField, TextArea(5, 10)] private string text; + [SerializeField] private ObjectRef configProvider; + + private ITextMeshProMarkdownConfigProvider observedConfigProvider; + private TextMeshProMarkdownConfig observedConfig; + + public string Text + { + get => text; + set + { + text = value; + isDirty = true; + } + } + + private bool isDirty; + + + [Space(5)] + [SerializeField] + private UnityEvent onDocumentParsed = new UnityEvent(); + public UnityEvent OnDocumentParsed => onDocumentParsed; + + protected override void Awake() + { + renderTarget = GetComponent(); + renderTarget.richText = true; + + CreateRequires(); + } + + protected override void OnEnable() + { + base.OnEnable(); + isDirty = true; + } + + protected override void OnDisable() + { + base.OnDisable(); + } + +#if UNITY_EDITOR + protected override void OnValidate() + { + base.OnValidate(); + CreateRequires(); + SetDirty(); + } +#endif + + private void CreateRequires() + { + var writer = new StringWriter(new StringBuilder(512)); + toTextMeshProRenderer ??= new TextMeshProRenderer(writer); + if (pipeline == null) + { + var pipelineBuilder = new MarkdownPipelineBuilder().UseCjkFriendlyEmphasis(); + pipelineBuilder.Extensions.Add(new AtParagraphExtension()); + pipeline = pipelineBuilder.Build(); + } + } + + private void Update() + { +#if UNITY_EDITOR + DetectConfigChanges(); +#endif + + if (isDirty) + { + BuildTextMeshProRichText(); + } + } + + public void SetDirty() => isDirty = true; + +#if UNITY_EDITOR + private void DetectConfigChanges() + { + var currentProvider = configProvider?.Value; + var currentConfig = currentProvider?.Config ?? TextMeshProMarkdownConfig.DefaultConfig; + if (currentConfig.Equals(observedConfig)) + { + return; + } + + observedConfigProvider = currentProvider; + observedConfig = new TextMeshProMarkdownConfig(currentConfig); + SetDirty(); + } +#endif + + private void BuildTextMeshProRichText() + { + isDirty = false; + Assert.IsNotNull(renderTarget, "Render target is not assigned."); + Assert.IsNotNull(toTextMeshProRenderer, "TextMeshPro text renderer is not assigned."); + Assert.IsNotNull(pipeline, "Markdown pipeline is not assigned."); + + if (string.IsNullOrEmpty(text)) + { + onDocumentParsed.Invoke(null); + if (!string.IsNullOrEmpty(renderTarget.text)) + { + renderTarget.text = string.Empty; + } + return; + } + + var document = Markdown.Parse(text, pipeline); + onDocumentParsed.Invoke(document); + + var renderer = toTextMeshProRenderer; + pipeline.Setup(renderer); + + var writer = (StringWriter)toTextMeshProRenderer.Writer; + writer.GetStringBuilder().Clear(); + renderer.ResetRecordedProps(); + + renderer.Config = configProvider?.Value?.Config ?? TextMeshProMarkdownConfig.DefaultConfig; + renderer.ComputeConfig(); + renderer.Render(document); + writer.Flush(); + + var result = writer.ToString() ?? string.Empty; + + renderTarget.text = result; + } + } + +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdown.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdown.cs.meta new file mode 100644 index 000000000..e0c26dccb --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdown.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cb6290c451a5b3a4b956eebaeba56c51 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownAtInfoCollector.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownAtInfoCollector.cs new file mode 100644 index 000000000..88d07830d --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownAtInfoCollector.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using CyanStars.MarkdownRenderer.Parsers; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; +using UnityEngine; +using UnityEngine.Events; + +namespace CyanStars.MarkdownRenderer +{ + public class TextMeshProMarkdownAtInfoCollector : MonoBehaviour + { + #nullable enable + public readonly struct AtInfo + { + public readonly string Content; + public readonly string? Link; + + public AtInfo(string content, string? link) + { + Content = content; + Link = link; + } + } + #nullable disable + + [SerializeField] private UnityEvent> onAtInfoCollected = new UnityEvent>(); + + public UnityEvent> OnAtInfoCollected => onAtInfoCollected; + + public void CollectAtInfo(MarkdownDocument document) + { + if (onAtInfoCollected == null || onAtInfoCollected.GetPersistentEventCount() == 0) + { + return; + } + + if (document is null) + { + onAtInfoCollected.Invoke(Array.Empty()); + return; + } + + var atInfo = new List(); + CollectAtInfo(document, atInfo); + onAtInfoCollected.Invoke(atInfo); + } + + private static void CollectAtInfo(ContainerBlock block, List atInfo) + { + foreach (var child in block) + { + if (child is ContainerBlock containerBlock) + { + CollectAtInfo(containerBlock, atInfo); + } + else if (child is LeafBlock leafBlock && leafBlock.Inline != null) + { + CollectAtInfo(leafBlock.Inline, atInfo); + } + } + } + + private static void CollectAtInfo(ContainerInline container, List atInfo) + { + foreach (var inline in container.FindDescendants()) + { + if (inline is AtParagraphInline atParagraphInline) + { + atInfo.Add(new AtInfo(atParagraphInline.Paragraph, atParagraphInline.Url)); + continue; + } + + if (TryGetAtInfo((LinkInline)inline, out var info)) + { + atInfo.Add(info); + continue; + } + } + } + + private static bool TryGetAtInfo(LinkInline inline, out AtInfo info) + { + if (!inline.IsShortcut && inline.LocalLabel == LocalLabel.None && + inline.FirstChild is LiteralInline literalInline && literalInline.NextSibling == null) + { + var content = literalInline.Content.ToString(); + if (content.StartsWith('@') && content.Length > 1) + { + info = new AtInfo(content.Substring(1), inline.Url); + return true; + } + } + + info = default; + return false; + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownAtInfoCollector.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownAtInfoCollector.cs.meta new file mode 100644 index 000000000..292620e70 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownAtInfoCollector.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ccec54e473dc4d13afb07d1e9aea6ed6 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfig.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfig.cs new file mode 100644 index 000000000..4b3365b7d --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfig.cs @@ -0,0 +1,89 @@ +using System; +using UnityEngine; + +namespace CyanStars.MarkdownRenderer +{ + public interface ITextMeshProMarkdownConfigProvider + { + TextMeshProMarkdownConfig Config { get; } + } + + [Serializable] + public class TextMeshProMarkdownConfig : IEquatable + { + private static TextMeshProMarkdownConfig defaultConfig; + public static TextMeshProMarkdownConfig DefaultConfig => defaultConfig ??= CreateDefault(); + + public Color CodeBlockBackgroundColor; + public Color AtColor; + public Color LinkColor; + public Color QuoteColor; + public string LinkPrefix; + public string UnorderedListMarker; + [Range(0, 2)] public double QuoteWidth; + [Range(0, 10)] public double QuoteSpacing; + [Range(0, 10)] public double BlockFakeMarginBottom; + public FinishBlockBehavior FinishBlockBehavior; + + public string CodeBlockBackgroundColorHex => ColorUtility.ToHtmlStringRGBA(CodeBlockBackgroundColor); + public string AtColorHex => ColorUtility.ToHtmlStringRGBA(AtColor); + public string LinkColorHex => ColorUtility.ToHtmlStringRGBA(LinkColor); + public string QuoteColorHex => ColorUtility.ToHtmlStringRGBA(QuoteColor); + + public TextMeshProMarkdownConfig() + { + } + + public TextMeshProMarkdownConfig(TextMeshProMarkdownConfig other) + { + this.CodeBlockBackgroundColor = other.CodeBlockBackgroundColor; + this.AtColor = other.AtColor; + this.LinkColor = other.LinkColor; + this.QuoteColor = other.QuoteColor; + this.LinkPrefix = other.LinkPrefix; + this.UnorderedListMarker = other.UnorderedListMarker; + this.QuoteWidth = other.QuoteWidth; + this.QuoteSpacing = other.QuoteSpacing; + this.BlockFakeMarginBottom = other.BlockFakeMarginBottom; + this.FinishBlockBehavior = other.FinishBlockBehavior; + } + + private static TextMeshProMarkdownConfig CreateDefault() => new() + { + CodeBlockBackgroundColor = new(0.533f, 0.533f, 0.533f, 0.5f), + AtColor = new(1, 0.841f, 0.078f, 0.87f), + LinkColor = new(1, 0.841f, 0.078f, 0.87f), + QuoteColor = new(0.6f, 0.6f, 0.6f), + LinkPrefix = "__md_link__", + UnorderedListMarker = "\u2011", + QuoteWidth = 1, + QuoteSpacing = 0.5, + BlockFakeMarginBottom = 0.5, + FinishBlockBehavior = FinishBlockBehavior.FakeMargin + }; + + public bool Equals(TextMeshProMarkdownConfig other) + { + if (other == null) return false; + if (ReferenceEquals(this, other)) return true; + + return CodeBlockBackgroundColor == other.CodeBlockBackgroundColor + && AtColor == other.AtColor + && LinkColor == other.LinkColor + && QuoteColor == other.QuoteColor + && LinkPrefix == other.LinkPrefix + && UnorderedListMarker == other.UnorderedListMarker + && QuoteWidth == other.QuoteWidth + && QuoteSpacing == other.QuoteSpacing + && BlockFakeMarginBottom == other.BlockFakeMarginBottom + && FinishBlockBehavior == other.FinishBlockBehavior; + } + } + + public enum FinishBlockBehavior + { + None, + FakeMargin, + EmptyLine + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfig.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfig.cs.meta new file mode 100644 index 000000000..03289d253 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 87325468ad42b4a52b2d61b8cbb8af22 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigBehaviour.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigBehaviour.cs new file mode 100644 index 000000000..18dd5466d --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigBehaviour.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +namespace CyanStars.MarkdownRenderer +{ + public class TextMeshProMarkdownConfigBehaviour : MonoBehaviour, ITextMeshProMarkdownConfigProvider + { + [SerializeField] private TextMeshProMarkdownConfig config = new(TextMeshProMarkdownConfig.DefaultConfig); + + public TextMeshProMarkdownConfig Config => config; + + private void Reset() + { + config = new(TextMeshProMarkdownConfig.DefaultConfig); + } + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigBehaviour.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigBehaviour.cs.meta new file mode 100644 index 000000000..739a16ed6 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigBehaviour.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 113584774ebb6f27aa836f931023d9cf \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigSO.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigSO.cs new file mode 100644 index 000000000..ab64be8e4 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigSO.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace CyanStars.MarkdownRenderer +{ + [CreateAssetMenu(menuName = "Cyan Stars/Markdown/TextMeshPro Markdown Config")] + public class TextMeshProMarkdownConfigSO : ScriptableObject, ITextMeshProMarkdownConfigProvider + { + [SerializeField] private TextMeshProMarkdownConfig config = new(TextMeshProMarkdownConfig.DefaultConfig); + public TextMeshProMarkdownConfig Config => config; + } +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigSO.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigSO.cs.meta new file mode 100644 index 000000000..a0ebf953a --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Runtime/TextMeshProMarkdownConfigSO.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8723b0d87fab56e8b8e6fd3b7e4be854 \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests.meta new file mode 100644 index 000000000..faff01b74 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 941517668b0c2986d9839df7b9500968 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/CyanStars.MarkdownRenderer.Tests.asmdef b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/CyanStars.MarkdownRenderer.Tests.asmdef new file mode 100644 index 000000000..3c6f234b7 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/CyanStars.MarkdownRenderer.Tests.asmdef @@ -0,0 +1,16 @@ +{ + "name": "CyanStars.MarkdownRenderer.Tests", + "rootNamespace": "CyanStars.MarkdownRenderer.Tests", + "references": [ + "CyanStars.MarkdownRenderer" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/CyanStars.MarkdownRenderer.Tests.asmdef.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/CyanStars.MarkdownRenderer.Tests.asmdef.meta new file mode 100644 index 000000000..a51c28ac0 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/CyanStars.MarkdownRenderer.Tests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 13b5844322ea2768b92d269aa439af96 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/LogCollectedAtInfo.cs b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/LogCollectedAtInfo.cs new file mode 100644 index 000000000..64d620880 --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/LogCollectedAtInfo.cs @@ -0,0 +1,13 @@ +using UnityEngine; +using System.Collections.Generic; +using System.Linq; +namespace CyanStars.MarkdownRenderer.Tests +{ + public class LogCollectedAtInfo : MonoBehaviour + { + public void Print(IReadOnlyList atInfos) + { + Debug.Log(string.Join("\n", atInfos.Select(info => $"{info.Content} : {info.Link}"))); + } + } +} diff --git a/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/LogCollectedAtInfo.cs.meta b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/LogCollectedAtInfo.cs.meta new file mode 100644 index 000000000..3ebc34e2b --- /dev/null +++ b/Cyan-Stars/Assets/Scripts/Libraries/MarkdownRenderer/Tests/LogCollectedAtInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 01edf5553eb2657468374e38f3c06a3b \ No newline at end of file diff --git a/Cyan-Stars/Packages/nuget-packages/packages.config b/Cyan-Stars/Packages/nuget-packages/packages.config index c7d803fa8..341a585fa 100644 --- a/Cyan-Stars/Packages/nuget-packages/packages.config +++ b/Cyan-Stars/Packages/nuget-packages/packages.config @@ -1,5 +1,6 @@  +