开始开发

This commit is contained in:
2026-05-12 17:45:40 +08:00
parent cbb94162e0
commit bde7494997
1217 changed files with 253889 additions and 210 deletions

View File

@@ -0,0 +1,952 @@
%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: 9
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: 705507994}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GIWorkflowMode: 1
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_FinalGather: 0
m_FinalGatherFiltering: 1
m_FinalGatherRayCount: 256
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 500
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 500
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 2
m_PVRDenoiserTypeDirect: 0
m_PVRDenoiserTypeIndirect: 0
m_PVRDenoiserTypeAO: 0
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 0
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 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 &112901350
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 112901355}
- component: {fileID: 112901354}
- component: {fileID: 112901353}
- component: {fileID: 112901352}
- component: {fileID: 112901351}
- component: {fileID: 112901356}
m_Layer: 5
m_Name: Canvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &112901351
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 112901350}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7951c64acb0fa62458bf30a60089fe2d, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 0
m_CheckFor2DOcclusion: 0
m_CheckFor3DOcclusion: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RaycastTriggerInteraction: 1
--- !u!114 &112901352
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 112901350}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreReversedGraphics: 1
m_BlockingObjects: 0
m_BlockingMask:
serializedVersion: 2
m_Bits: 4294967295
--- !u!114 &112901353
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 112901350}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
m_Name:
m_EditorClassIdentifier:
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: 1
--- !u!223 &112901354
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 112901350}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 2
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 &112901355
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 112901350}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 1}
m_LocalScale: {x: 0.001, y: 0.001, z: 0.001}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1328319263}
- {fileID: 708670888}
m_Father: {fileID: 1090032660}
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: 1.4}
m_SizeDelta: {x: 300, y: 150}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &112901356
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 112901350}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1a2d7d89889b4d94fa1f8d6fe49788e8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Target: {fileID: 0}
m_TargetOffset: {x: 0, y: 0, z: 0.5}
m_FollowInLocalSpace: 0
m_ApplyTargetInLocalSpace: 0
m_MovementSpeed: 6
m_MovementSpeedVariancePercentage: 0.25
m_SnapOnEnable: 1
m_PositionFollowMode: 1
m_MinDistanceAllowed: 0.01
m_MaxDistanceAllowed: 0.3
m_TimeUntilThresholdReachesMaxDistance: 3
m_RotationFollowMode: 1
m_MinAngleAllowed: 0.1
m_MaxAngleAllowed: 5
m_TimeUntilThresholdReachesMaxAngle: 3
--- !u!1 &378127772
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 378127773}
- component: {fileID: 378127775}
- component: {fileID: 378127774}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &378127773
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 378127772}
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: 1328319263}
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}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &378127774
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 378127772}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
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_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: Record
--- !u!222 &378127775
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 378127772}
m_CullTransparentMesh: 1
--- !u!1 &532986410
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 532986411}
- component: {fileID: 532986413}
- component: {fileID: 532986412}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &532986411
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 532986410}
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: 708670888}
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}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &532986412
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 532986410}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
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_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 1
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: Stream
--- !u!222 &532986413
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 532986410}
m_CullTransparentMesh: 1
--- !u!1 &705507993
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 705507995}
- component: {fileID: 705507994}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &705507994
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 705507993}
m_Enabled: 1
serializedVersion: 10
m_Type: 1
m_Shape: 0
m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
m_Intensity: 1
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 1
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 6570
m_UseColorTemperature: 0
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &705507995
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 705507993}
serializedVersion: 2
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!1 &708670887
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 708670888}
- component: {fileID: 708670891}
- component: {fileID: 708670890}
- component: {fileID: 708670889}
m_Layer: 5
m_Name: Stream
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &708670888
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 708670887}
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:
- {fileID: 532986411}
m_Father: {fileID: 112901355}
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: 70, y: 0}
m_SizeDelta: {x: 100.00001, y: 45}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &708670889
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 708670887}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 0.40392157, g: 0.40392157, b: 0.40392157, a: 1}
m_HighlightedColor: {r: 0.40392157, g: 0.40392157, b: 0.40392157, a: 1}
m_PressedColor: {r: 0.4117647, g: 0.3137255, b: 0.9411765, a: 1}
m_SelectedColor: {r: 0.40392157, g: 0.40392157, b: 0.40392157, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 708670890}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &708670890
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 708670887}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
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_Sprite: {fileID: 21300000, guid: 379e221c1f1f81848b02916cf820aee2, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &708670891
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 708670887}
m_CullTransparentMesh: 1
--- !u!1 &1090032659
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1090032660}
- component: {fileID: 1090032661}
m_Layer: 0
m_Name: FirstPersonViewStreamingCast
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1090032660
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1090032659}
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:
- {fileID: 112901355}
- {fileID: 1666460195}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1090032661
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1090032659}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8bf566b5d7062da48bd2a6b677c9b9a6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_RecordBtn: {fileID: 1328319264}
m_RecordText: {fileID: 378127774}
m_StreamBtn: {fileID: 708670889}
m_StreamText: {fileID: 532986412}
m_BlendMode: 0
m_ResolutionLevel: 1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_AudioState: 2
useGreenBackGround: 0
--- !u!1 &1328319262
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1328319263}
- component: {fileID: 1328319266}
- component: {fileID: 1328319265}
- component: {fileID: 1328319264}
m_Layer: 5
m_Name: Record
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1328319263
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1328319262}
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:
- {fileID: 378127773}
m_Father: {fileID: 112901355}
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: -70, y: 0}
m_SizeDelta: {x: 100.00001, y: 45}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1328319264
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1328319262}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 0.40392157, g: 0.40392157, b: 0.40392157, a: 1}
m_HighlightedColor: {r: 0.40392157, g: 0.40392157, b: 0.40392157, a: 1}
m_PressedColor: {r: 0.4117647, g: 0.3137255, b: 0.9411765, a: 1}
m_SelectedColor: {r: 0.40392157, g: 0.40392157, b: 0.40392157, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 1328319265}
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!114 &1328319265
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1328319262}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
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_Sprite: {fileID: 21300000, guid: 379e221c1f1f81848b02916cf820aee2, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!222 &1328319266
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1328319262}
m_CullTransparentMesh: 1
--- !u!1001 &1511841562
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3282163454440828667, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4199889769274821528, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
propertyPath: m_Name
value: XR Interaction Setup
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 779fa6087d61b4c4abc175a2d5d948f5, type: 3}
--- !u!4 &1666460195 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
m_PrefabInstance: {fileID: 1761147325}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &1761147325
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 1090032660}
m_Modifications:
- target: {fileID: 5239455315974444336, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_Name
value: XREALLogo
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalRotation.x
value: -0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalRotation.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalRotation.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 5849225329768979463, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 7dcbaf9fa19b16f43b40f9dd5a94ef70, type: 3}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 705507995}
- {fileID: 1511841562}
- {fileID: 1090032660}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7d540e896be756e4c9c44271661ff99a
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a538ab8a177eb1c4383f0bea91849c4e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,60 @@
#region Header
/**
* IJsonWrapper.cs
* Interface that represents a type capable of handling all kinds of JSON
* data. This is mainly used when mapping objects through JsonMapper, and
* it's implemented by JsonData.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System.Collections;
using System.Collections.Specialized;
namespace LitJson
{
public enum JsonType
{
None,
Object,
Array,
String,
Int,
Long,
Double,
Boolean
}
public interface IJsonWrapper : IList, IOrderedDictionary
{
bool IsArray { get; }
bool IsBoolean { get; }
bool IsDouble { get; }
bool IsInt { get; }
bool IsLong { get; }
bool IsObject { get; }
bool IsString { get; }
bool GetBoolean ();
double GetDouble ();
int GetInt ();
JsonType GetJsonType ();
long GetLong ();
string GetString ();
void SetBoolean (bool val);
void SetDouble (double val);
void SetInt (int val);
void SetJsonType (JsonType type);
void SetLong (long val);
void SetString (string val);
string ToJson ();
void ToJson (JsonWriter writer);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 21904ce73f7ce384f8a41f1dd541c8ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38a9bd66235df964a8bf046f62fdf635
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,65 @@
#region Header
/**
* JsonException.cs
* Base class throwed by LitJSON when a parsing error occurs.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
namespace LitJson
{
public class JsonException :
#if NETSTANDARD1_5
Exception
#else
ApplicationException
#endif
{
public JsonException () : base ()
{
}
internal JsonException (ParserToken token) :
base (String.Format (
"Invalid token '{0}' in input string", token))
{
}
internal JsonException (ParserToken token,
Exception inner_exception) :
base (String.Format (
"Invalid token '{0}' in input string", token),
inner_exception)
{
}
internal JsonException (int c) :
base (String.Format (
"Invalid character '{0}' in input string", (char) c))
{
}
internal JsonException (int c, Exception inner_exception) :
base (String.Format (
"Invalid character '{0}' in input string", (char) c),
inner_exception)
{
}
public JsonException (string message) : base (message)
{
}
public JsonException (string message, Exception inner_exception) :
base (message, inner_exception)
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bff7b6ddfdba8024d901862cc2ca22e1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,994 @@
#region Header
/**
* JsonMapper.cs
* JSON to .Net object and object to JSON conversions.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
namespace LitJson
{
internal struct PropertyMetadata
{
public MemberInfo Info;
public bool IsField;
public Type Type;
}
internal struct ArrayMetadata
{
private Type element_type;
private bool is_array;
private bool is_list;
public Type ElementType {
get {
if (element_type == null)
return typeof (JsonData);
return element_type;
}
set { element_type = value; }
}
public bool IsArray {
get { return is_array; }
set { is_array = value; }
}
public bool IsList {
get { return is_list; }
set { is_list = value; }
}
}
internal struct ObjectMetadata
{
private Type element_type;
private bool is_dictionary;
private IDictionary<string, PropertyMetadata> properties;
public Type ElementType {
get {
if (element_type == null)
return typeof (JsonData);
return element_type;
}
set { element_type = value; }
}
public bool IsDictionary {
get { return is_dictionary; }
set { is_dictionary = value; }
}
public IDictionary<string, PropertyMetadata> Properties {
get { return properties; }
set { properties = value; }
}
}
internal delegate void ExporterFunc (object obj, JsonWriter writer);
public delegate void ExporterFunc<T> (T obj, JsonWriter writer);
internal delegate object ImporterFunc (object input);
public delegate TValue ImporterFunc<TJson, TValue> (TJson input);
public delegate IJsonWrapper WrapperFactory ();
public class JsonMapper
{
#region Fields
private static readonly int max_nesting_depth;
private static readonly IFormatProvider datetime_format;
private static readonly IDictionary<Type, ExporterFunc> base_exporters_table;
private static readonly IDictionary<Type, ExporterFunc> custom_exporters_table;
private static readonly IDictionary<Type,
IDictionary<Type, ImporterFunc>> base_importers_table;
private static readonly IDictionary<Type,
IDictionary<Type, ImporterFunc>> custom_importers_table;
private static readonly IDictionary<Type, ArrayMetadata> array_metadata;
private static readonly object array_metadata_lock = new Object ();
private static readonly IDictionary<Type,
IDictionary<Type, MethodInfo>> conv_ops;
private static readonly object conv_ops_lock = new Object ();
private static readonly IDictionary<Type, ObjectMetadata> object_metadata;
private static readonly object object_metadata_lock = new Object ();
private static readonly IDictionary<Type,
IList<PropertyMetadata>> type_properties;
private static readonly object type_properties_lock = new Object ();
private static readonly JsonWriter static_writer;
private static readonly object static_writer_lock = new Object ();
#endregion
#region Constructors
static JsonMapper ()
{
max_nesting_depth = 100;
array_metadata = new Dictionary<Type, ArrayMetadata> ();
conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>> ();
object_metadata = new Dictionary<Type, ObjectMetadata> ();
type_properties = new Dictionary<Type,
IList<PropertyMetadata>> ();
static_writer = new JsonWriter ();
datetime_format = DateTimeFormatInfo.InvariantInfo;
base_exporters_table = new Dictionary<Type, ExporterFunc> ();
custom_exporters_table = new Dictionary<Type, ExporterFunc> ();
base_importers_table = new Dictionary<Type,
IDictionary<Type, ImporterFunc>> ();
custom_importers_table = new Dictionary<Type,
IDictionary<Type, ImporterFunc>> ();
RegisterBaseExporters ();
RegisterBaseImporters ();
}
#endregion
#region Private Methods
private static void AddArrayMetadata (Type type)
{
if (array_metadata.ContainsKey (type))
return;
ArrayMetadata data = new ArrayMetadata ();
data.IsArray = type.IsArray;
if (type.GetInterface ("System.Collections.IList") != null)
data.IsList = true;
foreach (PropertyInfo p_info in type.GetProperties ()) {
if (p_info.Name != "Item")
continue;
ParameterInfo[] parameters = p_info.GetIndexParameters ();
if (parameters.Length != 1)
continue;
if (parameters[0].ParameterType == typeof (int))
data.ElementType = p_info.PropertyType;
}
lock (array_metadata_lock) {
try {
array_metadata.Add (type, data);
} catch (ArgumentException) {
return;
}
}
}
private static void AddObjectMetadata (Type type)
{
if (object_metadata.ContainsKey (type))
return;
ObjectMetadata data = new ObjectMetadata ();
if (type.GetInterface ("System.Collections.IDictionary") != null)
data.IsDictionary = true;
data.Properties = new Dictionary<string, PropertyMetadata> ();
foreach (PropertyInfo p_info in type.GetProperties ()) {
if (p_info.Name == "Item") {
ParameterInfo[] parameters = p_info.GetIndexParameters ();
if (parameters.Length != 1)
continue;
if (parameters[0].ParameterType == typeof (string))
data.ElementType = p_info.PropertyType;
continue;
}
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = p_info;
p_data.Type = p_info.PropertyType;
data.Properties.Add (p_info.Name, p_data);
}
foreach (FieldInfo f_info in type.GetFields ()) {
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = f_info;
p_data.IsField = true;
p_data.Type = f_info.FieldType;
data.Properties.Add (f_info.Name, p_data);
}
lock (object_metadata_lock) {
try {
object_metadata.Add (type, data);
} catch (ArgumentException) {
return;
}
}
}
private static void AddTypeProperties (Type type)
{
if (type_properties.ContainsKey (type))
return;
IList<PropertyMetadata> props = new List<PropertyMetadata> ();
foreach (PropertyInfo p_info in type.GetProperties ()) {
if (p_info.Name == "Item")
continue;
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = p_info;
p_data.IsField = false;
props.Add (p_data);
}
foreach (FieldInfo f_info in type.GetFields ()) {
PropertyMetadata p_data = new PropertyMetadata ();
p_data.Info = f_info;
p_data.IsField = true;
props.Add (p_data);
}
lock (type_properties_lock) {
try {
type_properties.Add (type, props);
} catch (ArgumentException) {
return;
}
}
}
private static MethodInfo GetConvOp (Type t1, Type t2)
{
lock (conv_ops_lock) {
if (! conv_ops.ContainsKey (t1))
conv_ops.Add (t1, new Dictionary<Type, MethodInfo> ());
}
if (conv_ops[t1].ContainsKey (t2))
return conv_ops[t1][t2];
MethodInfo op = t1.GetMethod (
"op_Implicit", new Type[] { t2 });
lock (conv_ops_lock) {
try {
conv_ops[t1].Add (t2, op);
} catch (ArgumentException) {
return conv_ops[t1][t2];
}
}
return op;
}
private static object ReadValue (Type inst_type, JsonReader reader)
{
reader.Read ();
if (reader.Token == JsonToken.ArrayEnd)
return null;
Type underlying_type = Nullable.GetUnderlyingType(inst_type);
Type value_type = underlying_type ?? inst_type;
if (reader.Token == JsonToken.Null) {
#if NETSTANDARD1_5
if (inst_type.IsClass() || underlying_type != null) {
return null;
}
#else
if (inst_type.IsClass || underlying_type != null) {
return null;
}
#endif
throw new JsonException (String.Format (
"Can't assign null to an instance of type {0}",
inst_type));
}
if (reader.Token == JsonToken.Double ||
reader.Token == JsonToken.Int ||
reader.Token == JsonToken.Long ||
reader.Token == JsonToken.String ||
reader.Token == JsonToken.Boolean) {
Type json_type = reader.Value.GetType ();
if (value_type.IsAssignableFrom (json_type))
return reader.Value;
// If there's a custom importer that fits, use it
if (custom_importers_table.ContainsKey (json_type) &&
custom_importers_table[json_type].ContainsKey (
value_type)) {
ImporterFunc importer =
custom_importers_table[json_type][value_type];
return importer (reader.Value);
}
// Maybe there's a base importer that works
if (base_importers_table.ContainsKey (json_type) &&
base_importers_table[json_type].ContainsKey (
value_type)) {
ImporterFunc importer =
base_importers_table[json_type][value_type];
return importer (reader.Value);
}
// Maybe it's an enum
#if NETSTANDARD1_5
if (value_type.IsEnum())
return Enum.ToObject (value_type, reader.Value);
#else
if (value_type.IsEnum)
return Enum.ToObject (value_type, reader.Value);
#endif
// Try using an implicit conversion operator
MethodInfo conv_op = GetConvOp (value_type, json_type);
if (conv_op != null)
return conv_op.Invoke (null,
new object[] { reader.Value });
// No luck
throw new JsonException (String.Format (
"Can't assign value '{0}' (type {1}) to type {2}",
reader.Value, json_type, inst_type));
}
object instance = null;
if (reader.Token == JsonToken.ArrayStart) {
AddArrayMetadata (inst_type);
ArrayMetadata t_data = array_metadata[inst_type];
if (! t_data.IsArray && ! t_data.IsList)
throw new JsonException (String.Format (
"Type {0} can't act as an array",
inst_type));
IList list;
Type elem_type;
if (! t_data.IsArray) {
list = (IList) Activator.CreateInstance (inst_type);
elem_type = t_data.ElementType;
} else {
list = new ArrayList ();
elem_type = inst_type.GetElementType ();
}
list.Clear();
while (true) {
object item = ReadValue (elem_type, reader);
if (item == null && reader.Token == JsonToken.ArrayEnd)
break;
list.Add (item);
}
if (t_data.IsArray) {
int n = list.Count;
instance = Array.CreateInstance (elem_type, n);
for (int i = 0; i < n; i++)
((Array) instance).SetValue (list[i], i);
} else
instance = list;
} else if (reader.Token == JsonToken.ObjectStart) {
AddObjectMetadata (value_type);
ObjectMetadata t_data = object_metadata[value_type];
instance = Activator.CreateInstance (value_type);
while (true) {
reader.Read ();
if (reader.Token == JsonToken.ObjectEnd)
break;
string property = (string) reader.Value;
if (t_data.Properties.ContainsKey (property)) {
PropertyMetadata prop_data =
t_data.Properties[property];
if (prop_data.IsField) {
((FieldInfo) prop_data.Info).SetValue (
instance, ReadValue (prop_data.Type, reader));
} else {
PropertyInfo p_info =
(PropertyInfo) prop_data.Info;
if (p_info.CanWrite)
p_info.SetValue (
instance,
ReadValue (prop_data.Type, reader),
null);
else
ReadValue (prop_data.Type, reader);
}
} else {
if (! t_data.IsDictionary) {
if (! reader.SkipNonMembers) {
throw new JsonException (String.Format (
"The type {0} doesn't have the " +
"property '{1}'",
inst_type, property));
} else {
ReadSkip (reader);
continue;
}
}
((IDictionary) instance).Add (
property, ReadValue (
t_data.ElementType, reader));
}
}
}
return instance;
}
private static IJsonWrapper ReadValue (WrapperFactory factory,
JsonReader reader)
{
reader.Read ();
if (reader.Token == JsonToken.ArrayEnd ||
reader.Token == JsonToken.Null)
return null;
IJsonWrapper instance = factory ();
if (reader.Token == JsonToken.String) {
instance.SetString ((string) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Double) {
instance.SetDouble ((double) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Int) {
instance.SetInt ((int) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Long) {
instance.SetLong ((long) reader.Value);
return instance;
}
if (reader.Token == JsonToken.Boolean) {
instance.SetBoolean ((bool) reader.Value);
return instance;
}
if (reader.Token == JsonToken.ArrayStart) {
instance.SetJsonType (JsonType.Array);
while (true) {
IJsonWrapper item = ReadValue (factory, reader);
if (item == null && reader.Token == JsonToken.ArrayEnd)
break;
((IList) instance).Add (item);
}
}
else if (reader.Token == JsonToken.ObjectStart) {
instance.SetJsonType (JsonType.Object);
while (true) {
reader.Read ();
if (reader.Token == JsonToken.ObjectEnd)
break;
string property = (string) reader.Value;
((IDictionary) instance)[property] = ReadValue (
factory, reader);
}
}
return instance;
}
private static void ReadSkip (JsonReader reader)
{
ToWrapper (
delegate { return new JsonMockWrapper (); }, reader);
}
private static void RegisterBaseExporters ()
{
base_exporters_table[typeof (byte)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((byte) obj));
};
base_exporters_table[typeof (char)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToString ((char) obj));
};
base_exporters_table[typeof (DateTime)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToString ((DateTime) obj,
datetime_format));
};
base_exporters_table[typeof (decimal)] =
delegate (object obj, JsonWriter writer) {
writer.Write ((decimal) obj);
};
base_exporters_table[typeof (sbyte)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((sbyte) obj));
};
base_exporters_table[typeof (short)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((short) obj));
};
base_exporters_table[typeof (ushort)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToInt32 ((ushort) obj));
};
base_exporters_table[typeof (uint)] =
delegate (object obj, JsonWriter writer) {
writer.Write (Convert.ToUInt64 ((uint) obj));
};
base_exporters_table[typeof (ulong)] =
delegate (object obj, JsonWriter writer) {
writer.Write ((ulong) obj);
};
base_exporters_table[typeof(DateTimeOffset)] =
delegate (object obj, JsonWriter writer) {
writer.Write(((DateTimeOffset)obj).ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", datetime_format));
};
}
private static void RegisterBaseImporters ()
{
ImporterFunc importer;
importer = delegate (object input) {
return Convert.ToByte ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (byte), importer);
importer = delegate (object input) {
return Convert.ToUInt64 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (ulong), importer);
importer = delegate (object input) {
return Convert.ToInt64((int)input);
};
RegisterImporter(base_importers_table, typeof(int),
typeof(long), importer);
importer = delegate (object input) {
return Convert.ToSByte ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (sbyte), importer);
importer = delegate (object input) {
return Convert.ToInt16 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (short), importer);
importer = delegate (object input) {
return Convert.ToUInt16 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (ushort), importer);
importer = delegate (object input) {
return Convert.ToUInt32 ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (uint), importer);
importer = delegate (object input) {
return Convert.ToSingle ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (float), importer);
importer = delegate (object input) {
return Convert.ToDouble ((int) input);
};
RegisterImporter (base_importers_table, typeof (int),
typeof (double), importer);
importer = delegate (object input) {
return Convert.ToDecimal ((double) input);
};
RegisterImporter (base_importers_table, typeof (double),
typeof (decimal), importer);
importer = delegate (object input) {
return Convert.ToSingle((double)input);
};
RegisterImporter(base_importers_table, typeof(double),
typeof(float), importer);
importer = delegate (object input) {
return Convert.ToUInt32 ((long) input);
};
RegisterImporter (base_importers_table, typeof (long),
typeof (uint), importer);
importer = delegate (object input) {
return Convert.ToChar ((string) input);
};
RegisterImporter (base_importers_table, typeof (string),
typeof (char), importer);
importer = delegate (object input) {
return Convert.ToDateTime ((string) input, datetime_format);
};
RegisterImporter (base_importers_table, typeof (string),
typeof (DateTime), importer);
importer = delegate (object input) {
return DateTimeOffset.Parse((string)input, datetime_format);
};
RegisterImporter(base_importers_table, typeof(string),
typeof(DateTimeOffset), importer);
}
private static void RegisterImporter (
IDictionary<Type, IDictionary<Type, ImporterFunc>> table,
Type json_type, Type value_type, ImporterFunc importer)
{
if (! table.ContainsKey (json_type))
table.Add (json_type, new Dictionary<Type, ImporterFunc> ());
table[json_type][value_type] = importer;
}
private static void WriteValue (object obj, JsonWriter writer,
bool writer_is_private,
int depth)
{
if (depth > max_nesting_depth)
throw new JsonException (
String.Format ("Max allowed object depth reached while " +
"trying to export from type {0}",
obj.GetType ()));
if (obj == null) {
writer.Write (null);
return;
}
if (obj is IJsonWrapper) {
if (writer_is_private)
writer.TextWriter.Write (((IJsonWrapper) obj).ToJson ());
else
((IJsonWrapper) obj).ToJson (writer);
return;
}
if (obj is String) {
writer.Write ((string) obj);
return;
}
if (obj is Double) {
writer.Write ((double) obj);
return;
}
if (obj is Single)
{
var fv = (float)obj;
if (float.IsNaN(fv))
{
UnityEngine.Debug.LogWarning("JsonMapper write NaN Value.");
writer.Write(0.0f);
}
else
writer.Write(fv);
return;
}
if (obj is Int32) {
writer.Write ((int) obj);
return;
}
if (obj is Boolean) {
writer.Write ((bool) obj);
return;
}
if (obj is Int64) {
writer.Write ((long) obj);
return;
}
if (obj is Array) {
writer.WriteArrayStart ();
foreach (object elem in (Array) obj)
WriteValue (elem, writer, writer_is_private, depth + 1);
writer.WriteArrayEnd ();
return;
}
if (obj is IList) {
writer.WriteArrayStart ();
foreach (object elem in (IList) obj)
WriteValue (elem, writer, writer_is_private, depth + 1);
writer.WriteArrayEnd ();
return;
}
if (obj is IDictionary dictionary) {
writer.WriteObjectStart ();
foreach (DictionaryEntry entry in dictionary) {
var propertyName = entry.Key is string key ?
key
: Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
writer.WritePropertyName (propertyName);
WriteValue (entry.Value, writer, writer_is_private,
depth + 1);
}
writer.WriteObjectEnd ();
return;
}
Type obj_type = obj.GetType ();
// See if there's a custom exporter for the object
if (custom_exporters_table.ContainsKey (obj_type)) {
ExporterFunc exporter = custom_exporters_table[obj_type];
exporter (obj, writer);
return;
}
// If not, maybe there's a base exporter
if (base_exporters_table.ContainsKey (obj_type)) {
ExporterFunc exporter = base_exporters_table[obj_type];
exporter (obj, writer);
return;
}
// Last option, let's see if it's an enum
if (obj is Enum) {
Type e_type = Enum.GetUnderlyingType (obj_type);
if (e_type == typeof (long))
writer.Write ((long) obj);
else if (e_type == typeof (uint))
writer.Write ((uint) obj);
else if (e_type == typeof (ulong))
writer.Write ((ulong) obj);
else if (e_type == typeof(ushort))
writer.Write ((ushort)obj);
else if (e_type == typeof(short))
writer.Write ((short)obj);
else if (e_type == typeof(byte))
writer.Write ((byte)obj);
else if (e_type == typeof(sbyte))
writer.Write ((sbyte)obj);
else
writer.Write ((int) obj);
return;
}
// Okay, so it looks like the input should be exported as an
// object
AddTypeProperties (obj_type);
IList<PropertyMetadata> props = type_properties[obj_type];
writer.WriteObjectStart ();
foreach (PropertyMetadata p_data in props) {
if (p_data.IsField) {
writer.WritePropertyName (p_data.Info.Name);
WriteValue (((FieldInfo) p_data.Info).GetValue (obj),
writer, writer_is_private, depth + 1);
}
else {
PropertyInfo p_info = (PropertyInfo) p_data.Info;
if (p_info.CanRead) {
writer.WritePropertyName (p_data.Info.Name);
WriteValue (p_info.GetValue (obj, null),
writer, writer_is_private, depth + 1);
}
}
}
writer.WriteObjectEnd ();
}
#endregion
public static string ToJson (object obj)
{
lock (static_writer_lock) {
static_writer.Reset ();
WriteValue (obj, static_writer, true, 0);
return static_writer.ToString ();
}
}
public static void ToJson (object obj, JsonWriter writer)
{
WriteValue (obj, writer, false, 0);
}
public static JsonData ToObject (JsonReader reader)
{
return (JsonData) ToWrapper (
delegate { return new JsonData (); }, reader);
}
public static JsonData ToObject (TextReader reader)
{
JsonReader json_reader = new JsonReader (reader);
return (JsonData) ToWrapper (
delegate { return new JsonData (); }, json_reader);
}
public static JsonData ToObject (string json)
{
return (JsonData) ToWrapper (
delegate { return new JsonData (); }, json);
}
public static T ToObject<T> (JsonReader reader)
{
return (T) ReadValue (typeof (T), reader);
}
public static T ToObject<T> (TextReader reader)
{
JsonReader json_reader = new JsonReader (reader);
return (T) ReadValue (typeof (T), json_reader);
}
public static T ToObject<T> (string json)
{
JsonReader reader = new JsonReader (json);
return (T) ReadValue (typeof (T), reader);
}
public static object ToObject(string json, Type ConvertType )
{
JsonReader reader = new JsonReader(json);
return ReadValue(ConvertType, reader);
}
public static IJsonWrapper ToWrapper (WrapperFactory factory,
JsonReader reader)
{
return ReadValue (factory, reader);
}
public static IJsonWrapper ToWrapper (WrapperFactory factory,
string json)
{
JsonReader reader = new JsonReader (json);
return ReadValue (factory, reader);
}
public static void RegisterExporter<T> (ExporterFunc<T> exporter)
{
ExporterFunc exporter_wrapper =
delegate (object obj, JsonWriter writer) {
exporter ((T) obj, writer);
};
custom_exporters_table[typeof (T)] = exporter_wrapper;
}
public static void RegisterImporter<TJson, TValue> (
ImporterFunc<TJson, TValue> importer)
{
ImporterFunc importer_wrapper =
delegate (object input) {
return importer ((TJson) input);
};
RegisterImporter (custom_importers_table, typeof (TJson),
typeof (TValue), importer_wrapper);
}
public static void UnregisterExporters ()
{
custom_exporters_table.Clear ();
}
public static void UnregisterImporters ()
{
custom_importers_table.Clear ();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e6ed9cc50af3ff74eb306b3a6646d172
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,105 @@
#region Header
/**
* JsonMockWrapper.cs
* Mock object implementing IJsonWrapper, to facilitate actions like
* skipping data more efficiently.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
namespace LitJson
{
public class JsonMockWrapper : IJsonWrapper
{
public bool IsArray { get { return false; } }
public bool IsBoolean { get { return false; } }
public bool IsDouble { get { return false; } }
public bool IsInt { get { return false; } }
public bool IsLong { get { return false; } }
public bool IsObject { get { return false; } }
public bool IsString { get { return false; } }
public bool GetBoolean () { return false; }
public double GetDouble () { return 0.0; }
public int GetInt () { return 0; }
public JsonType GetJsonType () { return JsonType.None; }
public long GetLong () { return 0L; }
public string GetString () { return ""; }
public void SetBoolean (bool val) {}
public void SetDouble (double val) {}
public void SetInt (int val) {}
public void SetJsonType (JsonType type) {}
public void SetLong (long val) {}
public void SetString (string val) {}
public string ToJson () { return ""; }
public void ToJson (JsonWriter writer) {}
bool IList.IsFixedSize { get { return true; } }
bool IList.IsReadOnly { get { return true; } }
object IList.this[int index] {
get { return null; }
set {}
}
int IList.Add (object value) { return 0; }
void IList.Clear () {}
bool IList.Contains (object value) { return false; }
int IList.IndexOf (object value) { return -1; }
void IList.Insert (int i, object v) {}
void IList.Remove (object value) {}
void IList.RemoveAt (int index) {}
int ICollection.Count { get { return 0; } }
bool ICollection.IsSynchronized { get { return false; } }
object ICollection.SyncRoot { get { return null; } }
void ICollection.CopyTo (Array array, int index) {}
IEnumerator IEnumerable.GetEnumerator () { return null; }
bool IDictionary.IsFixedSize { get { return true; } }
bool IDictionary.IsReadOnly { get { return true; } }
ICollection IDictionary.Keys { get { return null; } }
ICollection IDictionary.Values { get { return null; } }
object IDictionary.this[object key] {
get { return null; }
set {}
}
void IDictionary.Add (object k, object v) {}
void IDictionary.Clear () {}
bool IDictionary.Contains (object key) { return false; }
void IDictionary.Remove (object key) {}
IDictionaryEnumerator IDictionary.GetEnumerator () { return null; }
object IOrderedDictionary.this[int idx] {
get { return null; }
set {}
}
IDictionaryEnumerator IOrderedDictionary.GetEnumerator () {
return null;
}
void IOrderedDictionary.Insert (int i, object k, object v) {}
void IOrderedDictionary.RemoveAt (int i) {}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15328b784a96a4a42a85ba2527624cd5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,478 @@
#region Header
/**
* JsonReader.cs
* Stream-like access to JSON text.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace LitJson
{
public enum JsonToken
{
None,
ObjectStart,
PropertyName,
ObjectEnd,
ArrayStart,
ArrayEnd,
Int,
Long,
Double,
String,
Boolean,
Null
}
public class JsonReader
{
#region Fields
private static readonly IDictionary<int, IDictionary<int, int[]>> parse_table;
private Stack<int> automaton_stack;
private int current_input;
private int current_symbol;
private bool end_of_json;
private bool end_of_input;
private Lexer lexer;
private bool parser_in_string;
private bool parser_return;
private bool read_started;
private TextReader reader;
private bool reader_is_owned;
private bool skip_non_members;
private object token_value;
private JsonToken token;
#endregion
#region Public Properties
public bool AllowComments {
get { return lexer.AllowComments; }
set { lexer.AllowComments = value; }
}
public bool AllowSingleQuotedStrings {
get { return lexer.AllowSingleQuotedStrings; }
set { lexer.AllowSingleQuotedStrings = value; }
}
public bool SkipNonMembers {
get { return skip_non_members; }
set { skip_non_members = value; }
}
public bool EndOfInput {
get { return end_of_input; }
}
public bool EndOfJson {
get { return end_of_json; }
}
public JsonToken Token {
get { return token; }
}
public object Value {
get { return token_value; }
}
#endregion
#region Constructors
static JsonReader ()
{
parse_table = PopulateParseTable ();
}
public JsonReader (string json_text) :
this (new StringReader (json_text), true)
{
}
public JsonReader (TextReader reader) :
this (reader, false)
{
}
private JsonReader (TextReader reader, bool owned)
{
if (reader == null)
throw new ArgumentNullException ("reader");
parser_in_string = false;
parser_return = false;
read_started = false;
automaton_stack = new Stack<int> ();
automaton_stack.Push ((int) ParserToken.End);
automaton_stack.Push ((int) ParserToken.Text);
lexer = new Lexer (reader);
end_of_input = false;
end_of_json = false;
skip_non_members = true;
this.reader = reader;
reader_is_owned = owned;
}
#endregion
#region Static Methods
private static IDictionary<int, IDictionary<int, int[]>> PopulateParseTable ()
{
// See section A.2. of the manual for details
IDictionary<int, IDictionary<int, int[]>> parse_table = new Dictionary<int, IDictionary<int, int[]>> ();
TableAddRow (parse_table, ParserToken.Array);
TableAddCol (parse_table, ParserToken.Array, '[',
'[',
(int) ParserToken.ArrayPrime);
TableAddRow (parse_table, ParserToken.ArrayPrime);
TableAddCol (parse_table, ParserToken.ArrayPrime, '"',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, '[',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, ']',
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, '{',
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Number,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.True,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.False,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddCol (parse_table, ParserToken.ArrayPrime, (int) ParserToken.Null,
(int) ParserToken.Value,
(int) ParserToken.ValueRest,
']');
TableAddRow (parse_table, ParserToken.Object);
TableAddCol (parse_table, ParserToken.Object, '{',
'{',
(int) ParserToken.ObjectPrime);
TableAddRow (parse_table, ParserToken.ObjectPrime);
TableAddCol (parse_table, ParserToken.ObjectPrime, '"',
(int) ParserToken.Pair,
(int) ParserToken.PairRest,
'}');
TableAddCol (parse_table, ParserToken.ObjectPrime, '}',
'}');
TableAddRow (parse_table, ParserToken.Pair);
TableAddCol (parse_table, ParserToken.Pair, '"',
(int) ParserToken.String,
':',
(int) ParserToken.Value);
TableAddRow (parse_table, ParserToken.PairRest);
TableAddCol (parse_table, ParserToken.PairRest, ',',
',',
(int) ParserToken.Pair,
(int) ParserToken.PairRest);
TableAddCol (parse_table, ParserToken.PairRest, '}',
(int) ParserToken.Epsilon);
TableAddRow (parse_table, ParserToken.String);
TableAddCol (parse_table, ParserToken.String, '"',
'"',
(int) ParserToken.CharSeq,
'"');
TableAddRow (parse_table, ParserToken.Text);
TableAddCol (parse_table, ParserToken.Text, '[',
(int) ParserToken.Array);
TableAddCol (parse_table, ParserToken.Text, '{',
(int) ParserToken.Object);
TableAddRow (parse_table, ParserToken.Value);
TableAddCol (parse_table, ParserToken.Value, '"',
(int) ParserToken.String);
TableAddCol (parse_table, ParserToken.Value, '[',
(int) ParserToken.Array);
TableAddCol (parse_table, ParserToken.Value, '{',
(int) ParserToken.Object);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Number,
(int) ParserToken.Number);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.True,
(int) ParserToken.True);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.False,
(int) ParserToken.False);
TableAddCol (parse_table, ParserToken.Value, (int) ParserToken.Null,
(int) ParserToken.Null);
TableAddRow (parse_table, ParserToken.ValueRest);
TableAddCol (parse_table, ParserToken.ValueRest, ',',
',',
(int) ParserToken.Value,
(int) ParserToken.ValueRest);
TableAddCol (parse_table, ParserToken.ValueRest, ']',
(int) ParserToken.Epsilon);
return parse_table;
}
private static void TableAddCol (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken row, int col,
params int[] symbols)
{
parse_table[(int) row].Add (col, symbols);
}
private static void TableAddRow (IDictionary<int, IDictionary<int, int[]>> parse_table, ParserToken rule)
{
parse_table.Add ((int) rule, new Dictionary<int, int[]> ());
}
#endregion
#region Private Methods
private void ProcessNumber (string number)
{
if (number.IndexOf ('.') != -1 ||
number.IndexOf ('e') != -1 ||
number.IndexOf ('E') != -1) {
double n_double;
if (double.TryParse (number, NumberStyles.Any, CultureInfo.InvariantCulture, out n_double)) {
token = JsonToken.Double;
token_value = n_double;
return;
}
}
int n_int32;
if (int.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int32)) {
token = JsonToken.Int;
token_value = n_int32;
return;
}
long n_int64;
if (long.TryParse (number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_int64)) {
token = JsonToken.Long;
token_value = n_int64;
return;
}
ulong n_uint64;
if (ulong.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out n_uint64))
{
token = JsonToken.Long;
token_value = n_uint64;
return;
}
// Shouldn't happen, but just in case, return something
token = JsonToken.Int;
token_value = 0;
}
private void ProcessSymbol ()
{
if (current_symbol == '[') {
token = JsonToken.ArrayStart;
parser_return = true;
} else if (current_symbol == ']') {
token = JsonToken.ArrayEnd;
parser_return = true;
} else if (current_symbol == '{') {
token = JsonToken.ObjectStart;
parser_return = true;
} else if (current_symbol == '}') {
token = JsonToken.ObjectEnd;
parser_return = true;
} else if (current_symbol == '"') {
if (parser_in_string) {
parser_in_string = false;
parser_return = true;
} else {
if (token == JsonToken.None)
token = JsonToken.String;
parser_in_string = true;
}
} else if (current_symbol == (int) ParserToken.CharSeq) {
token_value = lexer.StringValue;
} else if (current_symbol == (int) ParserToken.False) {
token = JsonToken.Boolean;
token_value = false;
parser_return = true;
} else if (current_symbol == (int) ParserToken.Null) {
token = JsonToken.Null;
parser_return = true;
} else if (current_symbol == (int) ParserToken.Number) {
ProcessNumber (lexer.StringValue);
parser_return = true;
} else if (current_symbol == (int) ParserToken.Pair) {
token = JsonToken.PropertyName;
} else if (current_symbol == (int) ParserToken.True) {
token = JsonToken.Boolean;
token_value = true;
parser_return = true;
}
}
private bool ReadToken ()
{
if (end_of_input)
return false;
lexer.NextToken ();
if (lexer.EndOfInput) {
Close ();
return false;
}
current_input = lexer.Token;
return true;
}
#endregion
public void Close ()
{
if (end_of_input)
return;
end_of_input = true;
end_of_json = true;
if (reader_is_owned)
{
using(reader){}
}
reader = null;
}
public bool Read ()
{
if (end_of_input)
return false;
if (end_of_json) {
end_of_json = false;
automaton_stack.Clear ();
automaton_stack.Push ((int) ParserToken.End);
automaton_stack.Push ((int) ParserToken.Text);
}
parser_in_string = false;
parser_return = false;
token = JsonToken.None;
token_value = null;
if (! read_started) {
read_started = true;
if (! ReadToken ())
return false;
}
int[] entry_symbols;
while (true) {
if (parser_return) {
if (automaton_stack.Peek () == (int) ParserToken.End)
end_of_json = true;
return true;
}
current_symbol = automaton_stack.Pop ();
ProcessSymbol ();
if (current_symbol == current_input) {
if (! ReadToken ()) {
if (automaton_stack.Peek () != (int) ParserToken.End)
throw new JsonException (
"Input doesn't evaluate to proper JSON text");
if (parser_return)
return true;
return false;
}
continue;
}
try {
entry_symbols =
parse_table[current_symbol][current_input];
} catch (KeyNotFoundException e) {
throw new JsonException ((ParserToken) current_input, e);
}
if (entry_symbols[0] == (int) ParserToken.Epsilon)
continue;
for (int i = entry_symbols.Length - 1; i >= 0; i--)
automaton_stack.Push (entry_symbols[i]);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7778b8c42260e4445bbb0fc7f8277fc2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,483 @@
#region Header
/**
* JsonWriter.cs
* Stream-like facility to output JSON text.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
namespace LitJson
{
internal enum Condition
{
InArray,
InObject,
NotAProperty,
Property,
Value
}
internal class WriterContext
{
public int Count;
public bool InArray;
public bool InObject;
public bool ExpectingValue;
public int Padding;
}
public class JsonWriter
{
#region Fields
private static readonly NumberFormatInfo number_format;
private WriterContext context;
private Stack<WriterContext> ctx_stack;
private bool has_reached_end;
private char[] hex_seq;
private int indentation;
private int indent_value;
private StringBuilder inst_string_builder;
private bool pretty_print;
private bool validate;
private bool lower_case_properties;
private TextWriter writer;
#endregion
#region Properties
public int IndentValue {
get { return indent_value; }
set {
indentation = (indentation / indent_value) * value;
indent_value = value;
}
}
public bool PrettyPrint {
get { return pretty_print; }
set { pretty_print = value; }
}
public TextWriter TextWriter {
get { return writer; }
}
public bool Validate {
get { return validate; }
set { validate = value; }
}
public bool LowerCaseProperties {
get { return lower_case_properties; }
set { lower_case_properties = value; }
}
#endregion
#region Constructors
static JsonWriter ()
{
number_format = NumberFormatInfo.InvariantInfo;
}
public JsonWriter ()
{
inst_string_builder = new StringBuilder ();
writer = new StringWriter (inst_string_builder);
Init ();
}
public JsonWriter (StringBuilder sb) :
this (new StringWriter (sb))
{
}
public JsonWriter (TextWriter writer)
{
if (writer == null)
throw new ArgumentNullException ("writer");
this.writer = writer;
Init ();
}
#endregion
#region Private Methods
private void DoValidation (Condition cond)
{
if (! context.ExpectingValue)
context.Count++;
if (! validate)
return;
if (has_reached_end)
throw new JsonException (
"A complete JSON symbol has already been written");
switch (cond) {
case Condition.InArray:
if (! context.InArray)
throw new JsonException (
"Can't close an array here");
break;
case Condition.InObject:
if (! context.InObject || context.ExpectingValue)
throw new JsonException (
"Can't close an object here");
break;
case Condition.NotAProperty:
if (context.InObject && ! context.ExpectingValue)
throw new JsonException (
"Expected a property");
break;
case Condition.Property:
if (! context.InObject || context.ExpectingValue)
throw new JsonException (
"Can't add a property here");
break;
case Condition.Value:
if (! context.InArray &&
(! context.InObject || ! context.ExpectingValue))
throw new JsonException (
"Can't add a value here");
break;
}
}
private void Init ()
{
has_reached_end = false;
hex_seq = new char[4];
indentation = 0;
indent_value = 4;
pretty_print = false;
validate = true;
lower_case_properties = false;
ctx_stack = new Stack<WriterContext> ();
context = new WriterContext ();
ctx_stack.Push (context);
}
private static void IntToHex (int n, char[] hex)
{
int num;
for (int i = 0; i < 4; i++) {
num = n % 16;
if (num < 10)
hex[3 - i] = (char) ('0' + num);
else
hex[3 - i] = (char) ('A' + (num - 10));
n >>= 4;
}
}
private void Indent ()
{
if (pretty_print)
indentation += indent_value;
}
private void Put (string str)
{
if (pretty_print && ! context.ExpectingValue)
for (int i = 0; i < indentation; i++)
writer.Write (' ');
writer.Write (str);
}
private void PutNewline ()
{
PutNewline (true);
}
private void PutNewline (bool add_comma)
{
if (add_comma && ! context.ExpectingValue &&
context.Count > 1)
writer.Write (',');
if (pretty_print && ! context.ExpectingValue)
writer.Write (Environment.NewLine);
}
private void PutString (string str)
{
Put (String.Empty);
writer.Write ('"');
int n = str.Length;
for (int i = 0; i < n; i++) {
switch (str[i]) {
case '\n':
writer.Write ("\\n");
continue;
case '\r':
writer.Write ("\\r");
continue;
case '\t':
writer.Write ("\\t");
continue;
case '"':
case '\\':
writer.Write ('\\');
writer.Write (str[i]);
continue;
case '\f':
writer.Write ("\\f");
continue;
case '\b':
writer.Write ("\\b");
continue;
}
if ((int) str[i] >= 32 && (int) str[i] <= 126) {
writer.Write (str[i]);
continue;
}
// Default, turn into a \uXXXX sequence
IntToHex ((int) str[i], hex_seq);
writer.Write ("\\u");
writer.Write (hex_seq);
}
writer.Write ('"');
}
private void Unindent ()
{
if (pretty_print)
indentation -= indent_value;
}
#endregion
public override string ToString ()
{
if (inst_string_builder == null)
return String.Empty;
return inst_string_builder.ToString ();
}
public void Reset ()
{
has_reached_end = false;
ctx_stack.Clear ();
context = new WriterContext ();
ctx_stack.Push (context);
if (inst_string_builder != null)
inst_string_builder.Remove (0, inst_string_builder.Length);
}
public void Write (bool boolean)
{
DoValidation (Condition.Value);
PutNewline ();
Put (boolean ? "true" : "false");
context.ExpectingValue = false;
}
public void Write (decimal number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (double number)
{
DoValidation (Condition.Value);
PutNewline ();
string str = Convert.ToString (number, number_format);
Put (str);
if (str.IndexOf ('.') == -1 &&
str.IndexOf ('E') == -1)
writer.Write (".0");
context.ExpectingValue = false;
}
public void Write(float number)
{
DoValidation(Condition.Value);
PutNewline();
string str = Convert.ToString(number, number_format);
Put(str);
context.ExpectingValue = false;
}
public void Write (int number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (long number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void Write (string str)
{
DoValidation (Condition.Value);
PutNewline ();
if (str == null)
Put ("null");
else
PutString (str);
context.ExpectingValue = false;
}
public void Write (ulong number)
{
DoValidation (Condition.Value);
PutNewline ();
Put (Convert.ToString (number, number_format));
context.ExpectingValue = false;
}
public void WriteArrayEnd ()
{
DoValidation (Condition.InArray);
PutNewline (false);
ctx_stack.Pop ();
if (ctx_stack.Count == 1)
has_reached_end = true;
else {
context = ctx_stack.Peek ();
context.ExpectingValue = false;
}
Unindent ();
Put ("]");
}
public void WriteArrayStart ()
{
DoValidation (Condition.NotAProperty);
PutNewline ();
Put ("[");
context = new WriterContext ();
context.InArray = true;
ctx_stack.Push (context);
Indent ();
}
public void WriteObjectEnd ()
{
DoValidation (Condition.InObject);
PutNewline (false);
ctx_stack.Pop ();
if (ctx_stack.Count == 1)
has_reached_end = true;
else {
context = ctx_stack.Peek ();
context.ExpectingValue = false;
}
Unindent ();
Put ("}");
}
public void WriteObjectStart ()
{
DoValidation (Condition.NotAProperty);
PutNewline ();
Put ("{");
context = new WriterContext ();
context.InObject = true;
ctx_stack.Push (context);
Indent ();
}
public void WritePropertyName (string property_name)
{
DoValidation (Condition.Property);
PutNewline ();
string propertyName = (property_name == null || !lower_case_properties)
? property_name
: property_name.ToLowerInvariant();
PutString (propertyName);
if (pretty_print) {
if (propertyName.Length > context.Padding)
context.Padding = propertyName.Length;
for (int i = context.Padding - propertyName.Length;
i >= 0; i--)
writer.Write (' ');
writer.Write (": ");
} else
writer.Write (':');
context.ExpectingValue = true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6160566037632bb43b0cd6d238abc261
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,912 @@
#region Header
/**
* Lexer.cs
* JSON lexer implementation based on a finite state machine.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace LitJson
{
internal class FsmContext
{
public bool Return;
public int NextState;
public Lexer L;
public int StateStack;
}
internal class Lexer
{
#region Fields
private delegate bool StateHandler (FsmContext ctx);
private static readonly int[] fsm_return_table;
private static readonly StateHandler[] fsm_handler_table;
private bool allow_comments;
private bool allow_single_quoted_strings;
private bool end_of_input;
private FsmContext fsm_context;
private int input_buffer;
private int input_char;
private TextReader reader;
private int state;
private StringBuilder string_buffer;
private string string_value;
private int token;
private int unichar;
#endregion
#region Properties
public bool AllowComments {
get { return allow_comments; }
set { allow_comments = value; }
}
public bool AllowSingleQuotedStrings {
get { return allow_single_quoted_strings; }
set { allow_single_quoted_strings = value; }
}
public bool EndOfInput {
get { return end_of_input; }
}
public int Token {
get { return token; }
}
public string StringValue {
get { return string_value; }
}
#endregion
#region Constructors
static Lexer ()
{
PopulateFsmTables (out fsm_handler_table, out fsm_return_table);
}
public Lexer (TextReader reader)
{
allow_comments = true;
allow_single_quoted_strings = true;
input_buffer = 0;
string_buffer = new StringBuilder (128);
state = 1;
end_of_input = false;
this.reader = reader;
fsm_context = new FsmContext ();
fsm_context.L = this;
}
#endregion
#region Static Methods
private static int HexValue (int digit)
{
switch (digit) {
case 'a':
case 'A':
return 10;
case 'b':
case 'B':
return 11;
case 'c':
case 'C':
return 12;
case 'd':
case 'D':
return 13;
case 'e':
case 'E':
return 14;
case 'f':
case 'F':
return 15;
default:
return digit - '0';
}
}
private static void PopulateFsmTables (out StateHandler[] fsm_handler_table, out int[] fsm_return_table)
{
// See section A.1. of the manual for details of the finite
// state machine.
fsm_handler_table = new StateHandler[28] {
State1,
State2,
State3,
State4,
State5,
State6,
State7,
State8,
State9,
State10,
State11,
State12,
State13,
State14,
State15,
State16,
State17,
State18,
State19,
State20,
State21,
State22,
State23,
State24,
State25,
State26,
State27,
State28
};
fsm_return_table = new int[28] {
(int) ParserToken.Char,
0,
(int) ParserToken.Number,
(int) ParserToken.Number,
0,
(int) ParserToken.Number,
0,
(int) ParserToken.Number,
0,
0,
(int) ParserToken.True,
0,
0,
0,
(int) ParserToken.False,
0,
0,
(int) ParserToken.Null,
(int) ParserToken.CharSeq,
(int) ParserToken.Char,
0,
0,
(int) ParserToken.CharSeq,
(int) ParserToken.Char,
0,
0,
0,
0
};
}
private static char ProcessEscChar (int esc_char)
{
switch (esc_char) {
case '"':
case '\'':
case '\\':
case '/':
return Convert.ToChar (esc_char);
case 'n':
return '\n';
case 't':
return '\t';
case 'r':
return '\r';
case 'b':
return '\b';
case 'f':
return '\f';
default:
// Unreachable
return '?';
}
}
private static bool State1 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r')
continue;
if (ctx.L.input_char >= '1' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 3;
return true;
}
switch (ctx.L.input_char) {
case '"':
ctx.NextState = 19;
ctx.Return = true;
return true;
case ',':
case ':':
case '[':
case ']':
case '{':
case '}':
ctx.NextState = 1;
ctx.Return = true;
return true;
case '-':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 2;
return true;
case '0':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 4;
return true;
case 'f':
ctx.NextState = 12;
return true;
case 'n':
ctx.NextState = 16;
return true;
case 't':
ctx.NextState = 9;
return true;
case '\'':
if (! ctx.L.allow_single_quoted_strings)
return false;
ctx.L.input_char = '"';
ctx.NextState = 23;
ctx.Return = true;
return true;
case '/':
if (! ctx.L.allow_comments)
return false;
ctx.NextState = 25;
return true;
default:
return false;
}
}
return true;
}
private static bool State2 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '1' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 3;
return true;
}
switch (ctx.L.input_char) {
case '0':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 4;
return true;
default:
return false;
}
}
private static bool State3 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case '.':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 5;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
return true;
}
private static bool State4 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case '.':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 5;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
private static bool State5 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 6;
return true;
}
return false;
}
private static bool State6 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char <= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
case 'e':
case 'E':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 7;
return true;
default:
return false;
}
}
return true;
}
private static bool State7 (FsmContext ctx)
{
ctx.L.GetChar ();
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 8;
return true;
}
switch (ctx.L.input_char) {
case '+':
case '-':
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
ctx.NextState = 8;
return true;
default:
return false;
}
}
private static bool State8 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char<= '9') {
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
if (ctx.L.input_char == ' ' ||
ctx.L.input_char >= '\t' && ctx.L.input_char<= '\r') {
ctx.Return = true;
ctx.NextState = 1;
return true;
}
switch (ctx.L.input_char) {
case ',':
case ']':
case '}':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
return true;
}
private static bool State9 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'r':
ctx.NextState = 10;
return true;
default:
return false;
}
}
private static bool State10 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 11;
return true;
default:
return false;
}
}
private static bool State11 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'e':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State12 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'a':
ctx.NextState = 13;
return true;
default:
return false;
}
}
private static bool State13 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.NextState = 14;
return true;
default:
return false;
}
}
private static bool State14 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 's':
ctx.NextState = 15;
return true;
default:
return false;
}
}
private static bool State15 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'e':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State16 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 17;
return true;
default:
return false;
}
}
private static bool State17 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.NextState = 18;
return true;
default:
return false;
}
}
private static bool State18 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'l':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State19 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
switch (ctx.L.input_char) {
case '"':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 20;
return true;
case '\\':
ctx.StateStack = 19;
ctx.NextState = 21;
return true;
default:
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
}
return true;
}
private static bool State20 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '"':
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State21 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case 'u':
ctx.NextState = 22;
return true;
case '"':
case '\'':
case '/':
case '\\':
case 'b':
case 'f':
case 'n':
case 'r':
case 't':
ctx.L.string_buffer.Append (
ProcessEscChar (ctx.L.input_char));
ctx.NextState = ctx.StateStack;
return true;
default:
return false;
}
}
private static bool State22 (FsmContext ctx)
{
int counter = 0;
int mult = 4096;
ctx.L.unichar = 0;
while (ctx.L.GetChar ()) {
if (ctx.L.input_char >= '0' && ctx.L.input_char <= '9' ||
ctx.L.input_char >= 'A' && ctx.L.input_char <= 'F' ||
ctx.L.input_char >= 'a' && ctx.L.input_char <= 'f') {
ctx.L.unichar += HexValue (ctx.L.input_char) * mult;
counter++;
mult /= 16;
if (counter == 4) {
ctx.L.string_buffer.Append (
Convert.ToChar (ctx.L.unichar));
ctx.NextState = ctx.StateStack;
return true;
}
continue;
}
return false;
}
return true;
}
private static bool State23 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
switch (ctx.L.input_char) {
case '\'':
ctx.L.UngetChar ();
ctx.Return = true;
ctx.NextState = 24;
return true;
case '\\':
ctx.StateStack = 23;
ctx.NextState = 21;
return true;
default:
ctx.L.string_buffer.Append ((char) ctx.L.input_char);
continue;
}
}
return true;
}
private static bool State24 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '\'':
ctx.L.input_char = '"';
ctx.Return = true;
ctx.NextState = 1;
return true;
default:
return false;
}
}
private static bool State25 (FsmContext ctx)
{
ctx.L.GetChar ();
switch (ctx.L.input_char) {
case '*':
ctx.NextState = 27;
return true;
case '/':
ctx.NextState = 26;
return true;
default:
return false;
}
}
private static bool State26 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '\n') {
ctx.NextState = 1;
return true;
}
}
return true;
}
private static bool State27 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '*') {
ctx.NextState = 28;
return true;
}
}
return true;
}
private static bool State28 (FsmContext ctx)
{
while (ctx.L.GetChar ()) {
if (ctx.L.input_char == '*')
continue;
if (ctx.L.input_char == '/') {
ctx.NextState = 1;
return true;
}
ctx.NextState = 27;
return true;
}
return true;
}
#endregion
private bool GetChar ()
{
if ((input_char = NextChar ()) != -1)
return true;
end_of_input = true;
return false;
}
private int NextChar ()
{
if (input_buffer != 0) {
int tmp = input_buffer;
input_buffer = 0;
return tmp;
}
return reader.Read ();
}
public bool NextToken ()
{
StateHandler handler;
fsm_context.Return = false;
while (true) {
handler = fsm_handler_table[state - 1];
if (! handler (fsm_context))
throw new JsonException (input_char);
if (end_of_input)
return false;
if (fsm_context.Return) {
string_value = string_buffer.ToString ();
string_buffer.Remove (0, string_buffer.Length);
token = fsm_return_table[state - 1];
if (token == (int) ParserToken.Char)
token = input_char;
state = fsm_context.NextState;
return true;
}
state = fsm_context.NextState;
}
}
private void UngetChar ()
{
input_buffer = input_char;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8e230f1808e11ba46aaf2ed818c3bb3b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
#if NETSTANDARD1_5
using System;
using System.Reflection;
namespace LitJson
{
internal static class Netstandard15Polyfill
{
internal static Type GetInterface(this Type type, string name)
{
return type.GetTypeInfo().GetInterface(name);
}
internal static bool IsClass(this Type type)
{
return type.GetTypeInfo().IsClass;
}
internal static bool IsEnum(this Type type)
{
return type.GetTypeInfo().IsEnum;
}
}
}
#endif

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1f14b5f652a240d49afb61f7eeb51bf1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
#region Header
/**
* ParserToken.cs
* Internal representation of the tokens used by the lexer and the parser.
*
* The authors disclaim copyright to this source code. For more details, see
* the COPYING file included with this distribution.
**/
#endregion
namespace LitJson
{
internal enum ParserToken
{
// Lexer tokens (see section A.1.1. of the manual)
None = System.Char.MaxValue + 1,
Number,
True,
False,
Null,
CharSeq,
// Single char
Char,
// Parser Rules (see section A.2.1 of the manual)
Text,
Object,
ObjectPrime,
Pair,
PairRest,
Array,
ArrayPrime,
Value,
ValueRest,
String,
// End of input
End,
// The empty rule
Epsilon
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 96d5025c0642e094c828bd45f22255c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f57b24297b333ce49a6ea2a6aaed1e99
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,156 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
namespace Unity.XR.XREAL.Samples.NetWork
{
public class LocalServerSearcher : SingletonMonoBehaviour<LocalServerSearcher>
{
public struct ServerInfoResult
{
public bool isSuccess;
public IPEndPoint endPoint;
}
public delegate void OnGetSearchResult(ServerInfoResult result);
private UdpClient client;
private IPEndPoint endpoint;
private Thread m_ReceiveThread = null;
private const string SEARCHSERVERIP = "FIND-SERVER";
private const int BroadCastPort = 6001;
private static float TimeoutWaittingTime = 3f;
private IPEndPoint m_LocalServer;
private Queue<OnGetSearchResult> m_Tasks = new Queue<OnGetSearchResult>();
private Coroutine m_TimeOutCoroutine = null;
public LocalServerSearcher()
{
client = new UdpClient(new IPEndPoint(IPAddress.Any, 0));
endpoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), BroadCastPort);
}
public void Search(OnGetSearchResult callback)
{
lock (m_Tasks)
{
m_Tasks.Enqueue(callback);
}
if (m_ReceiveThread == null)
{
m_ReceiveThread = new Thread(new ThreadStart(RecvThread));
m_ReceiveThread.IsBackground = true;
m_ReceiveThread.Start();
}
RequestForServerIP();
TryStopTimeOutCoroutine();
m_TimeOutCoroutine = StartCoroutine(TimeOut());
}
private void TryStopTimeOutCoroutine()
{
if (m_TimeOutCoroutine != null)
{
Debug.Log("[LocalServerSearcher] StopTimeOutCoroutine");
StopCoroutine(m_TimeOutCoroutine);
m_TimeOutCoroutine = null;
}
}
private void RequestForServerIP()
{
Debug.Log("[LocalServerSearcher] RequestForServerIP");
byte[] buf = Encoding.Default.GetBytes(SEARCHSERVERIP);
client.Send(buf, buf.Length, endpoint);
}
private void RecvThread()
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, BroadCastPort);
while (true)
{
try
{
byte[] buf = client.Receive(ref endpoint);
string data = Encoding.Default.GetString(buf);
Debug.Log("[LocalServerSearcher] Get the server info:" + data);
if (!string.IsNullOrEmpty(data))
{
string[] param = data.Split(':');
if (param != null && param.Length == 2)
{
m_LocalServer = new IPEndPoint(IPAddress.Parse(param[0]), int.Parse(param[1]));
Response(m_LocalServer);
TryStopTimeOutCoroutine();
}
}
}
catch (Exception e)
{
throw e;
}
}
}
private IEnumerator TimeOut()
{
float time_last = 0f;
while (true)
{
yield return new WaitForEndOfFrame();
time_last += Time.deltaTime;
if (time_last > TimeoutWaittingTime)
{
Debug.Log("[LocalServerSearcher] Get the server TimeOut");
Response(null);
TryStopTimeOutCoroutine();
}
}
}
private void Response(IPEndPoint endpoint)
{
if (m_Tasks.Count == 0)
{
return;
}
XREALMainThreadDispatcher.Singleton.QueueOnMainThread(() =>
{
ServerInfoResult result = new ServerInfoResult();
result.endPoint = endpoint;
result.isSuccess = endpoint != null;
lock (m_Tasks)
{
if (m_Tasks.Count == 0)
{
return;
}
var callback = m_Tasks.Dequeue();
while (callback != null)
{
try
{
callback?.Invoke(result);
}
catch (Exception e)
{
throw e;
}
if (m_Tasks.Count == 0)
{
return;
}
callback = m_Tasks.Dequeue();
}
}
});
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1361081bc4466d94796ef0d593a960d4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,91 @@
using System;
namespace Unity.XR.XREAL.Samples.NetWork
{
/// <summary> Net msg type. </summary>
public enum MessageType
{
/// <summary> Empty type. </summary>
None = 0,
/// <summary> Connect server. </summary>
Connected = 1,
/// <summary> Disconnect from server. </summary>
Disconnect = 2,
/// <summary> Heart beat. </summary>
HeartBeat = 3,
/// <summary> Enter room. </summary>
EnterRoom = 4,
/// <summary> Enter room. </summary>
ExitRoom = 5,
/// <summary> An enum constant representing the update camera Parameter option. </summary>
UpdateCameraParam = 6,
/// <summary> Used to synchronization message with the server. </summary>
MessageSynchronization = 7,
}
/// <summary> (Serializable) an enter room data. </summary>
[Serializable]
public class EnterRoomData
{
/// <summary> Enter room result. </summary>
public bool result;
}
/// <summary> (Serializable) an exit room data. </summary>
[Serializable]
public class ExitRoomData
{
/// <summary> Exit room result. </summary>
public bool Suc;
}
/// <summary> (Serializable) a camera parameter. </summary>
[Serializable]
public class CameraParam
{
/// <summary> Camera fov. </summary>
public Fov4f fov;
}
/// <summary> (Serializable) a fov 4f. </summary>
[Serializable]
public class Fov4f
{
/// <summary> The left. </summary>
public double left;
/// <summary> The right. </summary>
public double right;
/// <summary> The top. </summary>
public double top;
/// <summary> The bottom. </summary>
public double bottom;
/// <summary> Default constructor. </summary>
public Fov4f() { }
/// <summary> Constructor. </summary>
/// <param name="l"> A double to process.</param>
/// <param name="r"> A double to process.</param>
/// <param name="t"> A double to process.</param>
/// <param name="b"> A double to process.</param>
public Fov4f(double l, double r, double t, double b)
{
this.left = l;
this.right = r;
this.top = t;
this.bottom = b;
}
/// <summary> Convert this object into a string representation. </summary>
/// <returns> A string that represents this object. </returns>
public override string ToString()
{
return string.Format("{0} {1} {2} {3}", left, right, top, bottom);
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a310a14a9e3851f47a5041b928fdf819
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,211 @@
using LitJson;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
namespace Unity.XR.XREAL.Samples.NetWork
{
/// <summary> An observer view net worker. </summary>
public class NetWorkBehaviour
{
/// <summary> The net work client. </summary>
protected NetWorkClient m_NetWorkClient;
/// <summary> The limit waitting time. </summary>
private const float limitWaittingTime = 5f;
/// <summary> True if is connected, false if not. </summary>
private bool m_IsConnected = false;
/// <summary> True if is jonin success, false if not. </summary>
private bool m_IsJoninSuccess = false;
/// <summary> True if is closed, false if not. </summary>
private bool m_IsClosed = false;
private Coroutine checkServerAvailableCoroutine = null;
private Dictionary<ulong, Action<JsonData>> _ResponseEvents = new Dictionary<ulong, Action<JsonData>>();
public virtual void Listen()
{
if (m_NetWorkClient == null)
{
m_NetWorkClient = new NetWorkClient();
m_NetWorkClient.OnDisconnect += OnDisconnect;
m_NetWorkClient.OnConnect += OnConnected;
m_NetWorkClient.OnJoinRoomResult += OnJoinRoomResult;
m_NetWorkClient.OnMessageResponse += OnMessageResponse;
}
}
private void OnMessageResponse(byte[] data)
{
ulong msgid = BitConverter.ToUInt64(data, 0);
Action<JsonData> callback;
if (!_ResponseEvents.TryGetValue(msgid, out callback))
{
Debug.LogWarning("[NetWorkBehaviour] can not find the msgid bind event:" + msgid);
return;
}
// Remove the header to get the msg.
byte[] result = new byte[data.Length - sizeof(ulong)];
Array.Copy(data, sizeof(ulong), result, 0, result.Length);
string json = Encoding.UTF8.GetString(result);
callback?.Invoke(JsonMapper.ToObject(json));
Debug.Log("[NetWorkBehaviour] OnMessageResponse hit...");
_ResponseEvents.Remove(msgid);
}
/// <summary> Check server available. </summary>
/// <param name="ip"> The IP.</param>
/// <param name="callback"> The callback.</param>
public void CheckServerAvailable(string ip, int port, Action<bool> callback)
{
if (string.IsNullOrEmpty(ip))
{
callback?.Invoke(false);
}
else
{
if (checkServerAvailableCoroutine != null)
{
XREALMainThreadDispatcher.Singleton.StopCoroutine(checkServerAvailableCoroutine);
}
checkServerAvailableCoroutine = XREALMainThreadDispatcher.Singleton.StartCoroutine(CheckServerAvailableCoroutine(ip, port, callback));
}
}
/// <summary> Check server available coroutine. </summary>
/// <param name="ip"> The IP.</param>
/// <param name="callback"> The callback.</param>
/// <returns> An IEnumerator. </returns>
private IEnumerator CheckServerAvailableCoroutine(string ip, int port, Action<bool> callback)
{
Debug.Log($"[ObserverView] CheckServerAvailableCoroutine: {ip}:{port}");
// Start to connect the server.
m_NetWorkClient.Connect(ip, port);
float timeLast = 0;
while (!m_IsConnected)
{
if (timeLast > limitWaittingTime || m_IsClosed)
{
Debug.Log("[ObserverView] Connect the server TimeOut!");
callback?.Invoke(false);
yield break;
}
timeLast += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
// Start to enter the room.
m_NetWorkClient.EnterRoomRequest();
timeLast = 0;
while (!m_IsJoninSuccess)
{
if (timeLast > limitWaittingTime || m_IsClosed)
{
Debug.Log("[ObserverView] Join the server TimeOut!");
callback?.Invoke(false);
yield break;
}
timeLast += Time.deltaTime;
yield return new WaitForEndOfFrame();
}
callback?.Invoke(true);
}
public void SendMsg(JsonData data, Action<JsonData> onResponse, float timeout = 3)
{
XREALMainThreadDispatcher.Singleton.StartCoroutine(SendMessage(data, onResponse, timeout));
}
private IEnumerator SendMessage(JsonData data, Action<JsonData> onResponse, float timeout)
{
if (data == null)
{
Debug.LogError("[NetWorkBehaviour] data is null!");
yield break;
}
// Add msgid(current timestamp) as the header.
ulong msgid = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
byte[] json_data = Encoding.UTF8.GetBytes(data.ToJson());
byte[] total_data = new byte[json_data.Length + sizeof(ulong)];
Array.Copy(BitConverter.GetBytes(msgid), 0, total_data, 0, sizeof(ulong));
Array.Copy(json_data, 0, total_data, sizeof(ulong), json_data.Length);
if (onResponse != null)
{
Action<JsonData> onResult;
AsyncTask<JsonData> asyncTask = new AsyncTask<JsonData>(out onResult);
_ResponseEvents[msgid] = onResult;
m_NetWorkClient.SendMessage(total_data);
XREALMainThreadDispatcher.Singleton.StartCoroutine(SendMsgTimeOut(msgid, timeout));
yield return asyncTask.WaitForCompletion();
onResponse?.Invoke(asyncTask.Result);
}
else
{
m_NetWorkClient.SendMessage(total_data);
}
}
private IEnumerator SendMsgTimeOut(UInt64 id, float timeout)
{
yield return new WaitForSeconds(timeout);
Action<JsonData> callback;
if (_ResponseEvents.TryGetValue(id, out callback))
{
Debug.LogWarningFormat("[NetWorkBehaviour] Send msg timeout, id:{0}", id);
JsonData json = new JsonData();
json["success"] = false;
callback?.Invoke(json);
}
}
#region Net msg
/// <summary> Executes the 'connected' action. </summary>
private void OnConnected()
{
Debug.Log("[NetWorkBehaviour] OnConnected...");
m_IsConnected = true;
}
/// <summary> Executes the 'disconnect' action. </summary>
private void OnDisconnect()
{
Debug.Log("[NetWorkBehaviour] OnDisconnect...");
this.Close();
}
/// <summary> Executes the 'join room result' action. </summary>
/// <param name="result"> True to result.</param>
private void OnJoinRoomResult(bool result)
{
Debug.Log("[NetWorkBehaviour] OnJoinRoomResult :" + result);
m_IsJoninSuccess = result;
if (!result)
{
this.Close();
}
}
#endregion
/// <summary> Closes this object. </summary>
public virtual void Close()
{
if (checkServerAvailableCoroutine != null)
{
XREALMainThreadDispatcher.Singleton.StopCoroutine(checkServerAvailableCoroutine);
}
m_NetWorkClient.ExitRoomRequest();
m_NetWorkClient?.Dispose();
m_NetWorkClient = null;
checkServerAvailableCoroutine = null;
m_IsClosed = true;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20c6ebff010f798409adcf0cfa4b57fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,151 @@
using System;
using UnityEngine;
namespace Unity.XR.XREAL.Samples.NetWork
{
/// <summary> A net work client. </summary>
public class NetWorkClient : IDisposable
{
/// <summary> Event queue for all listeners interested in OnJoinRoomResult events. </summary>
public event Action<bool> OnJoinRoomResult;
/// <summary> Event queue for all listeners interested in OnCameraParamUpdate events. </summary>
public event Action<CameraParam> OnCameraParamUpdate;
/// <summary> Event queue for all listeners interested in OnMessageResponse events. </summary>
public event Action<byte[]> OnMessageResponse;
/// <summary> Event queue for all listeners interested in OnDisconnect events. </summary>
public event Action OnDisconnect;
/// <summary> Event queue for all listeners interested in OnConnect events. </summary>
public event Action OnConnect;
/// <summary> Default constructor. </summary>
public NetWorkClient()
{
NetworkSession.Register(MessageType.Connected, OnConnected);
NetworkSession.Register(MessageType.Disconnect, OnDisConnected);
NetworkSession.Register(MessageType.HeartBeat, HeartbeatResponse);
NetworkSession.Register(MessageType.EnterRoom, EnterRoomResponse);
NetworkSession.Register(MessageType.ExitRoom, ExitRoomResponse);
NetworkSession.Register(MessageType.UpdateCameraParam, UpdateCameraParamResponse);
NetworkSession.Register(MessageType.MessageSynchronization, MessageSynchronizationResponse);
}
/// <summary> Join the server's room. </summary>
public void EnterRoomRequest()
{
NetworkSession.Enqueue(MessageType.EnterRoom);
}
/// <summary> Exit room request. </summary>
public void ExitRoomRequest()
{
NetworkSession.Enqueue(MessageType.ExitRoom);
}
/// <summary> Updates the camera parameter request. </summary>
public void UpdateCameraParamRequest()
{
NetworkSession.Enqueue(MessageType.UpdateCameraParam);
}
/// <summary> Join the server's room. </summary>
public void SendMessage(byte[] data)
{
NetworkSession.Enqueue(MessageType.MessageSynchronization, data);
}
/// <summary> Connects. </summary>
/// <param name="ip"> The IP.</param>
/// <param name="port"> The port.</param>
public void Connect(string ip, int port)
{
NetworkSession.Connect(ip, port);
}
/// <summary> Executes the 'connected' action. </summary>
/// <param name="data"> The data.</param>
private void OnConnected(byte[] data)
{
OnConnect?.Invoke();
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged
/// resources. </summary>
public void Dispose()
{
NetworkSession.UnRegister(MessageType.Connected, OnConnected);
NetworkSession.UnRegister(MessageType.Disconnect, OnDisConnected);
NetworkSession.UnRegister(MessageType.HeartBeat, HeartbeatResponse);
NetworkSession.UnRegister(MessageType.EnterRoom, EnterRoomResponse);
NetworkSession.UnRegister(MessageType.ExitRoom, ExitRoomResponse);
NetworkSession.UnRegister(MessageType.UpdateCameraParam, UpdateCameraParamResponse);
NetworkSession.UnRegister(MessageType.MessageSynchronization, MessageSynchronizationResponse);
NetworkSession.Close();
}
/// <summary> Executes the 'dis connected' action. </summary>
/// <param name="data"> The data.</param>
private void OnDisConnected(byte[] data)
{
OnDisconnect?.Invoke();
}
#region Net msg response
/// <summary> Heartbeat response. </summary>
/// <param name="data"> The data.</param>
private void HeartbeatResponse(byte[] data)
{
NetworkSession.Received = true;
Debug.Log("Receive a heart beat package.");
}
/// <summary> Enter room response. </summary>
/// <param name="data"> The data.</param>
private void EnterRoomResponse(byte[] data)
{
EnterRoomData result = SerializerFactory.Create().Deserialize<EnterRoomData>(data);
if (result.result)
{
Debug.Log("Join the room success.");
OnJoinRoomResult?.Invoke(true);
}
else
{
Debug.LogWarning("Join the room faild.");
OnJoinRoomResult?.Invoke(false);
}
}
/// <summary> Exit room response. </summary>
/// <param name="data"> The data.</param>
private void ExitRoomResponse(byte[] data)
{
ExitRoomData result = SerializerFactory.Create().Deserialize<ExitRoomData>(data);
if (result.Suc)
{
Debug.Log("Exit the room success.");
}
else
{
Debug.LogWarning("Exit the room faild.");
}
}
/// <summary> Updates the camera parameter response described by data. </summary>
/// <param name="data"> The data.</param>
private void UpdateCameraParamResponse(byte[] data)
{
CameraParam result = SerializerFactory.Create().Deserialize<CameraParam>(data);
OnCameraParamUpdate?.Invoke(result);
Debug.Log(result.fov.ToString());
}
private void MessageSynchronizationResponse(byte[] data)
{
OnMessageResponse?.Invoke(data);
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 64d6788171afdaf4ea7aa77cd447bdf7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,379 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
namespace Unity.XR.XREAL.Samples.NetWork
{
/// <summary> Call back. </summary>
/// <param name="data"> The data.</param>
public delegate void CallBack(byte[] data);
/// <summary> A network session. </summary>
public static class NetworkSession
{
/// <summary> Clent connect state. </summary>
private enum ClientState
{
/// <summary> Disconnect. </summary>
None,
/// <summary> Connect server success. </summary>
Connected,
}
/// <summary> Message type dictionary. </summary>
private static Dictionary<MessageType, CallBack> m_CallBacks = new Dictionary<MessageType, CallBack>();
/// <summary> Message queue. </summary>
private static Queue<byte[]> m_Messages;
/// <summary> Client current state. </summary>
private static ClientState m_CurState;
/// <summary> Gets or sets the current state. </summary>
/// <value> The current state. </value>
private static ClientState CurState
{
get
{
return m_CurState;
}
set
{
m_CurState = value;
if (m_CurState == ClientState.Connected)
{
CallBack callback;
if (m_CallBacks.TryGetValue(MessageType.Connected, out callback))
{
callback?.Invoke(null);
}
}
else
{
CallBack callback;
if (m_CallBacks.TryGetValue(MessageType.Disconnect, out callback))
{
callback?.Invoke(null);
}
}
}
}
/// <summary> The client. </summary>
private static TcpClient m_Client;
/// <summary> The stream. </summary>
private static NetworkStream m_Stream;
/// <summary> Target address. </summary>
private static IPAddress m_Address;
/// <summary> The port. </summary>
private static int m_Port;
/// <summary> Heart beat time stamp. </summary>
private const float HEARTBEAT_TIME = 1;
/// <summary> Time from last heart beat package. </summary>
private static float m_Timer = HEARTBEAT_TIME;
/// <summary> Get heart beat msg from server. </summary>
public static bool Received = true;
#region coroutines
/// <summary> Connects the coroutine. </summary>
/// <returns> An IEnumerator. </returns>
private static IEnumerator ConnectCoroutine()
{
m_Client = new TcpClient();
IAsyncResult async = m_Client.BeginConnect(m_Address, m_Port, null, null);
while (!async.IsCompleted)
{
Debug.Log("Contecting server...");
yield return null;
}
try
{
m_Client.EndConnect(async);
}
catch (Exception ex)
{
Debug.LogWarning("Conncet server faild :" + ex.Message);
yield break;
}
// Get data stream
try
{
m_Stream = m_Client.GetStream();
}
catch (Exception ex)
{
Debug.LogWarning("Connect server faild:" + ex.Message);
yield break;
}
if (m_Stream == null)
{
Debug.LogWarning("Connect server faild: data stream is empty");
yield break;
}
CurState = ClientState.Connected;
m_Messages = new Queue<byte[]>();
Debug.Log("Connect server success.");
// Set asyn msg send
NetworkCoroutine.Instance.StartCoroutine(HeartBeat());
// Set asyn msg receive
NetworkCoroutine.Instance.StartCoroutine(ReceiveCoroutine());
// Set quit event
NetworkCoroutine.Instance.SetQuitEvent(() => { m_Client.Close(); CurState = ClientState.None; });
}
/// <summary> Heart beat. </summary>
/// <returns> An IEnumerator. </returns>
private static IEnumerator HeartBeat()
{
while (CurState == ClientState.Connected)
{
m_Timer += Time.deltaTime;
if (m_Messages.Count > 0)
{
byte[] data = m_Messages.Dequeue();
yield return WriteCoroutine(data);
}
// Heart beat strategy
if (m_Timer >= HEARTBEAT_TIME)
{
// if dont receive last heart beat package.
if (!Received)
{
CurState = ClientState.None;
Debug.LogWarning("Heart beat error. disconnect server.");
yield break;
}
m_Timer = 0;
byte[] data = Pack(MessageType.HeartBeat);
yield return WriteCoroutine(data);
Debug.Log("Send a heart beat package.");
}
yield return null;
}
}
/// <summary> Receive coroutine. </summary>
/// <returns> An IEnumerator. </returns>
private static IEnumerator ReceiveCoroutine()
{
while (CurState == ClientState.Connected)
{
byte[] data = new byte[4];
int length; // msg len
MessageType type; // msg type
int receive = 0; // receive len
IAsyncResult async = m_Stream.BeginRead(data, 0, data.Length, null, null);
while (!async.IsCompleted)
{
yield return null;
}
try
{
receive = m_Stream.EndRead(async);
}
catch (Exception ex)
{
CurState = ClientState.None;
Debug.LogWarning("Receive msg package head erro:" + ex.Message);
yield break;
}
if (receive < data.Length)
{
CurState = ClientState.None;
Debug.LogWarning("Receive msg package head erro");
yield break;
}
using (MemoryStream stream = new MemoryStream(data))
{
BinaryReader binary = new BinaryReader(stream, Encoding.UTF8); // parase data using UTF-8
try
{
length = binary.ReadUInt16();
type = (MessageType)binary.ReadUInt16();
}
catch (Exception)
{
CurState = ClientState.None;
Debug.LogWarning("Receive msg package head erro");
yield break;
}
}
if (length - 4 > 0)
{
data = new byte[length - 4];
async = m_Stream.BeginRead(data, 0, data.Length, null, null);
while (!async.IsCompleted)
{
yield return null;
}
try
{
receive = m_Stream.EndRead(async);
}
catch (Exception ex)
{
CurState = ClientState.None;
Debug.LogWarning("Receive msg package head erro:" + ex.Message);
yield break;
}
if (receive < data.Length)
{
CurState = ClientState.None;
Debug.LogWarning("Receive msg package head erro");
yield break;
}
}
else
{
data = new byte[0];
receive = 0;
}
if (m_CallBacks.ContainsKey(type))
{
CallBack method = m_CallBacks[type];
method(data);
}
else
{
Debug.LogWarning("Did not regist the msg callback : " + type);
}
}
}
/// <summary> Writes a coroutine. </summary>
/// <param name="data"> The data.</param>
/// <returns> An IEnumerator. </returns>
private static IEnumerator WriteCoroutine(byte[] data)
{
if (CurState != ClientState.Connected || m_Stream == null)
{
Debug.LogWarning("Connect error, can not receive msg");
yield break;
}
IAsyncResult async = m_Stream.BeginWrite(data, 0, data.Length, null, null);
while (!async.IsCompleted)
{
yield return null;
}
try
{
m_Stream.EndWrite(async);
}
catch (Exception ex)
{
CurState = ClientState.None;
Debug.LogWarning("Send msg erro:" + ex.Message);
}
}
#endregion
/// <summary> Connect server. </summary>
/// <param name="address"> (Optional) The address.</param>
/// <param name="port"> (Optional) The port.</param>
public static void Connect(string address = null, int port = 8848)
{
// Can not connect again after connected.
if (CurState == ClientState.Connected)
{
Debug.Log("Has connected server.");
return;
}
if (address == null)
address = NetworkUtils.GetLocalIPv4();
// Cancle when get the ipaddress failed.
if (!IPAddress.TryParse(address, out m_Address))
{
Debug.LogWarning("IP erro, try again.");
return;
}
m_Port = port;
// Connect service.
NetworkCoroutine.Instance.StartCoroutine(ConnectCoroutine());
}
/// <summary> Closes this object. </summary>
public static void Close()
{
if (CurState == ClientState.Connected)
{
m_Client.Close();
m_CurState = ClientState.None;
}
NetworkCoroutine.Instance.StopAllCoroutines();
}
/// <summary> Regist callback event. </summary>
/// <param name="type"> The type.</param>
/// <param name="method"> The method.</param>
public static void Register(MessageType type, CallBack method)
{
if (!m_CallBacks.ContainsKey(type))
m_CallBacks.Add(type, method);
else
Debug.LogWarning("Regist the same msg type.");
}
/// <summary> Un register. </summary>
/// <param name="type"> The type.</param>
/// <param name="method"> The method.</param>
public static void UnRegister(MessageType type, CallBack method)
{
if (m_CallBacks.ContainsKey(type))
{
m_CallBacks.Remove(type);
}
}
/// <summary> Join the msg queue. </summary>
/// <param name="type"> The type.</param>
/// <param name="data"> (Optional) The data.</param>
public static void Enqueue(MessageType type, byte[] data = null)
{
// Pack the data
byte[] bytes = Pack(type, data);
if (CurState == ClientState.Connected)
{
m_Messages.Enqueue(bytes);
}
}
/// <summary> Pack the byte data. </summary>
/// <param name="type"> The type.</param>
/// <param name="data"> (Optional) The data.</param>
/// <returns> A byte[]. </returns>
private static byte[] Pack(MessageType type, byte[] data = null)
{
MessagePacker packer = new MessagePacker();
if (data != null)
{
packer.Add((ushort)(4 + data.Length)); // msg length
packer.Add((ushort)type); // msg type
packer.Add(data); // msg content
}
else
{
packer.Add(4);
packer.Add((ushort)type);
}
return packer.Package;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 81d4af6fac544cc498693b34606a6330
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e157ed67b5af0f74ba3dcbc64fce2cee
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
namespace Unity.XR.XREAL.Samples.NetWork
{
/// <summary> A message packer. </summary>
public class MessagePacker
{
/// <summary> The bytes. </summary>
private List<byte> bytes = new List<byte>();
/// <summary> Gets the package. </summary>
/// <value> The package. </value>
public byte[] Package
{
get { return bytes.ToArray(); }
}
/// <summary> Adds value. </summary>
/// <param name="data"> The data to add.</param>
/// <returns> A MessagePacker. </returns>
public MessagePacker Add(byte[] data)
{
bytes.AddRange(data);
return this;
}
/// <summary> Adds value. </summary>
/// <param name="value"> The value to add.</param>
/// <returns> A MessagePacker. </returns>
public MessagePacker Add(ushort value)
{
byte[] data = BitConverter.GetBytes(value);
bytes.AddRange(data);
return this;
}
/// <summary> Adds value. </summary>
/// <param name="value"> The value to add.</param>
/// <returns> A MessagePacker. </returns>
public MessagePacker Add(uint value)
{
byte[] data = BitConverter.GetBytes(value);
bytes.AddRange(data);
return this;
}
/// <summary> Adds value. </summary>
/// <param name="value"> The value to add.</param>
/// <returns> A MessagePacker. </returns>
public MessagePacker Add(ulong value)
{
byte[] data = BitConverter.GetBytes(value);
bytes.AddRange(data);
return this;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a3ad4b2ef850781438a4531d3c8843d3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,45 @@
using System;
using UnityEngine;
namespace Unity.XR.XREAL.Samples.NetWork
{
/// <summary> A network coroutine. </summary>
internal class NetworkCoroutine : MonoBehaviour
{
/// <summary> Event queue for all listeners interested in applicationQuit events. </summary>
private event Action ApplicationQuitEvent;
/// <summary> The instance. </summary>
private static NetworkCoroutine _instance;
/// <summary> Gets the instance. </summary>
/// <value> The instance. </value>
public static NetworkCoroutine Instance
{
get
{
if (!_instance)
{
GameObject socketClientObj = new GameObject("NetworkCoroutine");
_instance = socketClientObj.AddComponent<NetworkCoroutine>();
DontDestroyOnLoad(socketClientObj);
}
return _instance;
}
}
/// <summary> Sets quit event. </summary>
/// <param name="func"> The function.</param>
public void SetQuitEvent(Action func)
{
if (ApplicationQuitEvent != null) return;
ApplicationQuitEvent += func;
}
/// <summary> Executes the 'application quit' action. </summary>
private void OnApplicationQuit()
{
ApplicationQuitEvent?.Invoke();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 239487c972f53a549a19b8fe475f3610
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,135 @@
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
namespace Unity.XR.XREAL.Samples.NetWork
{
/// <summary> A network utilities. </summary>
public static class NetworkUtils
{
/// <summary> Get local ipv4, return null if faild. </summary>
/// <returns> The local IPv4. </returns>
public static string GetLocalIPv4()
{
string hostName = Dns.GetHostName(); //得到主机名
IPHostEntry iPEntry = Dns.GetHostEntry(hostName);
for (int i = 0; i < iPEntry.AddressList.Length; i++)
{
//从IP地址列表中筛选出IPv4类型的IP地址
if (iPEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
return iPEntry.AddressList[i].ToString();
}
return null;
}
/// <summary> Byte 2 string. </summary>
/// <param name="bytes"> The bytes.</param>
/// <returns> A string. </returns>
public static string Byte2String(byte[] bytes)
{
return Encoding.UTF8.GetString(bytes);
}
/// <summary> String 2 byte. </summary>
/// <param name="str"> The string.</param>
/// <returns> A byte[]. </returns>
public static byte[] String2Byte(string str)
{
return Encoding.UTF8.GetBytes(str);
}
}
/// <summary> Interface for serializer. </summary>
public interface ISerializer
{
/// <summary> Serialize this object to the given stream. </summary>
/// <param name="obj"> The object.</param>
/// <returns> A byte[]. </returns>
byte[] Serialize(object obj);
/// <summary> Deserialize this object to the given stream. </summary>
/// <typeparam name="T"> Generic type parameter.</typeparam>
/// <param name="data"> The data.</param>
/// <returns> A T. </returns>
T Deserialize<T>(byte[] data) where T : class;
}
/// <summary> An object for persisting JSON data. </summary>
public class JsonSerializer : ISerializer
{
/// <summary> Deserialize this object to the given stream. </summary>
/// <typeparam name="T"> Generic type parameter.</typeparam>
/// <param name="data"> The data.</param>
/// <returns> A T. </returns>
public T Deserialize<T>(byte[] data) where T : class
{
return LitJson.JsonMapper.ToObject<T>(Encoding.UTF8.GetString(data));
}
/// <summary> Serialize this object to the given stream. </summary>
/// <param name="obj"> The object.</param>
/// <returns> A byte[]. </returns>
public byte[] Serialize(object obj)
{
return Encoding.UTF8.GetBytes(LitJson.JsonMapper.ToJson(obj));
}
}
/// <summary> An object for persisting binary data. </summary>
public class BinarySerializer : ISerializer
{
/// <summary> obj -> bytes, return null if obj not mark as [Serializable]. </summary>
/// <param name="obj"> The object.</param>
/// <returns> A byte[]. </returns>
public byte[] Serialize(object obj)
{
//物体不为空且可被序列化
if (obj == null || !obj.GetType().IsSerializable)
return null;
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
byte[] data = stream.ToArray();
return data;
}
}
/// <summary> bytes -> obj, return null if obj not mark as [Serializable]. </summary>
/// <typeparam name="T"> Generic type parameter.</typeparam>
/// <param name="data"> The data.</param>
/// <returns> A T. </returns>
public T Deserialize<T>(byte[] data) where T : class
{
//数据不为空且T是可序列化的类型
if (data == null || !typeof(T).IsSerializable)
return null;
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream(data))
{
object obj = formatter.Deserialize(stream);
return obj as T;
}
}
}
/// <summary> A serializer factory. </summary>
public static class SerializerFactory
{
/// <summary> The serializer. </summary>
private static ISerializer _Serializer;
/// <summary> Creates a new ISerializer. </summary>
/// <returns> An ISerializer. </returns>
public static ISerializer Create()
{
if (_Serializer == null)
{
_Serializer = new JsonSerializer();
}
return _Serializer;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b987fb1d08c23e4085e3f56c50c9b00
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c80a416436d3ad046b81659602fcee81
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,380 @@
using System;
using System.Collections;
using System.IO;
using System.Linq;
using Unity.XR.XREAL.Samples.NetWork;
using UnityEngine;
using UnityEngine.UI;
namespace Unity.XR.XREAL.Samples
{
#if UNITY_ANDROID && !UNITY_EDITOR
using GalleryDataProvider = NativeGalleryDataProvider;
#else
using GalleryDataProvider = MockGalleryDataProvider;
#endif
/// <summary> A first person streamming cast. </summary>
public class FirstPersonStreammingCast : MonoBehaviour
{
public delegate void OnResponse(bool result);
[SerializeField]
private Button m_RecordBtn;
[SerializeField]
private Text m_RecordText;
[SerializeField]
private Button m_StreamBtn;
[SerializeField]
private Text m_StreamText;
public BlendMode m_BlendMode = BlendMode.Blend;
public ResolutionLevel m_ResolutionLevel = ResolutionLevel.Middle;
public LayerMask m_CullingMask = -1;
public AudioState m_AudioState = AudioState.None;
public bool useGreenBackGround = false;
/// <summary> The net worker. </summary>
private NetWorkBehaviour m_NetWorker;
/// <summary> The video capture. </summary>
private XREALVideoCapture m_VideoCapture = null;
public XREALVideoCapture VideoCapture
{
get
{
return m_VideoCapture;
}
}
private string m_ServerIP;
/// <summary> Gets the full pathname of the rtp file. </summary>
/// <value> The full pathname of the rtp file. </value>
public string RTPPath
{
get
{
return string.Format(@"rtp://{0}:5555", m_ServerIP);
}
}
public string VideoSavePath
{
get
{
string timeStamp = Time.time.ToString().Replace(".", "").Replace(":", "");
string filename = string.Format("Xreal_Record_{0}.mp4", timeStamp);
string filepath = Path.Combine(Application.persistentDataPath, filename);
return filepath;
}
}
private bool m_IsInitialized = false;
private bool m_IsStreamLock = false;
private bool m_IsStreamStarted = false;
private bool m_IsRecordStarted = false;
private string m_VideoPath;
private bool m_SavedLocal;
private GalleryDataProvider galleryDataTool;
public enum ResolutionLevel
{
High,
Middle,
Low,
}
/// <summary> Starts this object. </summary>
void Start()
{
this.Init();
}
/// <summary> Initializes this object. </summary>
private void Init()
{
if (m_IsInitialized)
{
return;
}
m_StreamBtn.onClick.AddListener(() =>
{
Debug.Log("m_StreamBtn.onClick");
OnStream();
});
m_RecordBtn.onClick.AddListener(() =>
{
Debug.Log("m_RecordBtn.onClick");
OnRecord();
});
m_IsInitialized = true;
}
private void RefreshUI()
{
m_RecordText.text = m_IsRecordStarted ? "Stop Record" : "Record";
m_StreamText.text = m_IsStreamStarted ? "Stop Stream" : "Stream";
if (m_IsStreamStarted)
{
m_RecordBtn.gameObject.SetActive(false);
m_StreamBtn.gameObject.SetActive(true);
}
else if (m_IsRecordStarted)
{
m_RecordBtn.gameObject.SetActive(true);
m_StreamBtn.gameObject.SetActive(false);
}
else
{
m_RecordBtn.gameObject.SetActive(true);
m_StreamBtn.gameObject.SetActive(true);
}
}
private void OnRecord()
{
if (!m_IsRecordStarted)
{
CreateAndStart();
}
else
{
StopVideoCapture();
}
m_IsRecordStarted = !m_IsRecordStarted;
RefreshUI();
}
private void OnStream()
{
if (m_IsStreamLock)
{
return;
}
m_IsStreamLock = true;
if (m_NetWorker == null)
{
m_NetWorker = new NetWorkBehaviour();
m_NetWorker.Listen();
}
if (!m_IsStreamStarted)
{
LocalServerSearcher.CreateSingleton().Search((result) =>
{
Debug.LogFormat("[FPStreammingCast] Get the server result:{0} ip:{1}:{2}", result.isSuccess, result.endPoint?.Address, result.endPoint.Port);
if (result.isSuccess)
{
string ip = result.endPoint.Address.ToString();
int port = result.endPoint.Port;
m_NetWorker.CheckServerAvailable(ip, port, (isAvailable) =>
{
Debug.LogFormat("[FPStreammingCast] Is the server {0}:{1} ok? {2}", ip, result.endPoint.Port, isAvailable);
if (isAvailable)
{
m_ServerIP = ip;
m_IsStreamStarted = true;
CreateAndStart();
RefreshUI();
}
m_IsStreamLock = false;
});
}
else
{
m_IsStreamLock = false;
Debug.LogError("[FPStreammingCast] Can not find the server...");
}
});
}
else
{
StopVideoCapture();
m_IsStreamStarted = false;
m_IsStreamLock = false;
RefreshUI();
}
}
/// <summary> Converts this object to a server. </summary>
private void CreateAndStart()
{
CreateVideoCapture(delegate ()
{
Debug.LogFormat("[FPStreammingCast] Start video capture.");
StartCoroutine(StartVideoCapture());
});
}
private Resolution GetResolutionByLevel(ResolutionLevel level)
{
var resolutions = XREALVideoCaptureUtility.SupportedResolutions.OrderByDescending((res) => res.width * res.height);
Resolution resolution = new Resolution();
switch (level)
{
case ResolutionLevel.High:
resolution = resolutions.ElementAt(0);
break;
case ResolutionLevel.Middle:
resolution = resolutions.ElementAt(1);
break;
case ResolutionLevel.Low:
resolution = resolutions.ElementAt(2);
break;
default:
break;
}
return resolution;
}
#region video capture
/// <summary> Creates video capture. </summary>
/// <param name="callback"> The callback.</param>
private void CreateVideoCapture(Action callback)
{
Debug.LogFormat("[FPStreammingCast] Created VideoCapture Instance!");
if (m_VideoCapture != null)
{
callback?.Invoke();
return;
}
XREALVideoCaptureUtility.CreateAsync(false, delegate (XREALVideoCapture videoCapture)
{
if (videoCapture != null)
{
m_VideoCapture = videoCapture;
callback?.Invoke();
}
else
{
Debug.LogError("[FPStreammingCast] Failed to create VideoCapture Instance!");
}
});
}
/// <summary> Starts video capture. </summary>
public IEnumerator StartVideoCapture()
{
Resolution cameraResolution = GetResolutionByLevel(m_ResolutionLevel);
Debug.LogFormat("[FPStreammingCast] cameraResolution:" + cameraResolution);
if (m_VideoCapture != null)
{
CameraParameters cameraParameters = new CameraParameters();
cameraParameters.hologramOpacity = 1f;
cameraParameters.frameRate = NativeConstants.RECORD_FPS_DEFAULT;
cameraParameters.cameraResolutionWidth = cameraResolution.width;
cameraParameters.cameraResolutionHeight = cameraResolution.height;
cameraParameters.pixelFormat = CapturePixelFormat.BGRA32;
cameraParameters.blendMode = m_BlendMode;
cameraParameters.audioState = m_AudioState;
cameraParameters.monophonic = true;
// Send the audioState to server.
if (m_NetWorker != null)
{
LitJson.JsonData json = new LitJson.JsonData();
json["useAudio"] = (cameraParameters.audioState != AudioState.None);
m_NetWorker.SendMsg(json, (response) =>
{
bool result;
if (bool.TryParse(response["success"].ToString(), out result) && result)
{
m_VideoCapture.StartVideoModeAsync(cameraParameters, OnStartedVideoCaptureMode, true);
}
else
{
Debug.LogError("[FPStreammingCast] Can not received response from server.");
}
});
}
else
{
m_VideoCapture.StartVideoModeAsync(cameraParameters, OnStartedVideoCaptureMode, true);
}
}
else
{
Debug.Log("[FPStreammingCast] VideoCapture object is null...");
}
yield return new WaitForEndOfFrame();
}
/// <summary> Stops video capture. </summary>
public void StopVideoCapture()
{
Debug.LogFormat("[FPStreammingCast] Stop Video Capture!");
m_VideoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
}
/// <summary> Executes the 'started video capture mode' action. </summary>
/// <param name="result"> The result.</param>
void OnStartedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result)
{
if (!result.success)
{
Debug.LogFormat("[FPStreammingCast] Started Video Capture Mode Faild!");
return;
}
Debug.LogFormat("[FPStreammingCast] Started Video Capture Mode!");
m_VideoPath = m_IsStreamStarted ? RTPPath : VideoSavePath;
m_SavedLocal = !m_IsStreamStarted;
m_VideoCapture.StartRecordingAsync(m_VideoPath, OnStartedRecordingVideo);
m_VideoCapture.GetContext().GetBehaviour().CaptureCamera.cullingMask = m_CullingMask.value;
m_VideoCapture.GetContext().GetBehaviour().CaptureCamera.backgroundColor = useGreenBackGround ? Color.green : Color.black;
}
/// <summary> Executes the 'stopped video capture mode' action. </summary>
/// <param name="result"> The result.</param>
void OnStoppedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result)
{
Debug.LogFormat("[FPStreammingCast] Stopped Video Capture Mode!");
m_VideoCapture = null;
if (m_SavedLocal)
{
string filename = string.Format("Xreal_Shot_Video_{0}.mp4", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
StartCoroutine(DelayInsertVideoToGallery(m_VideoPath, filename, "Record"));
m_SavedLocal = false;
}
}
IEnumerator DelayInsertVideoToGallery(string originFilePath, string displayName, string folderName)
{
yield return new WaitForSeconds(0.1f);
Debug.LogFormat("[FPStreammingCast] InsertVideoToGallery: {0}, {1} => {2}", displayName, originFilePath, folderName);
if (galleryDataTool == null)
{
galleryDataTool = new GalleryDataProvider();
}
galleryDataTool.InsertVideo(originFilePath, displayName, folderName);
}
/// <summary> Executes the 'started recording video' action. </summary>
/// <param name="result"> The result.</param>
void OnStartedRecordingVideo(XREALVideoCapture.VideoCaptureResult result)
{
Debug.LogFormat("[FPStreammingCast] Started Recording Video!");
}
/// <summary> Executes the 'stopped recording video' action. </summary>
/// <param name="result"> The result.</param>
void OnStoppedRecordingVideo(XREALVideoCapture.VideoCaptureResult result)
{
Debug.LogFormat("[FPStreammingCast] Stopped Recording Video!");
m_VideoCapture.StopVideoModeAsync(OnStoppedVideoCaptureMode);
if (m_NetWorker != null)
{
m_NetWorker?.Close();
m_NetWorker = null;
}
}
#endregion
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8bf566b5d7062da48bd2a6b677c9b9a6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: