开始开发
This commit is contained in:
8
Assets/Samples/XREAL XR Plugin/3.1.0.meta
Normal file
8
Assets/Samples/XREAL XR Plugin/3.1.0.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ddfbaa35ef2f1a448be8d71efaa2b1b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 694ef3f356e692b49966d5f0cfd6f3a3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32eecde47216a794f82eaa23cbcc57ab
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d540e896be756e4c9c44271661ff99a
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a538ab8a177eb1c4383f0bea91849c4e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 21904ce73f7ce384f8a41f1dd541c8ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38a9bd66235df964a8bf046f62fdf635
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bff7b6ddfdba8024d901862cc2ca22e1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e6ed9cc50af3ff74eb306b3a6646d172
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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) {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15328b784a96a4a42a85ba2527624cd5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7778b8c42260e4445bbb0fc7f8277fc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6160566037632bb43b0cd6d238abc261
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e230f1808e11ba46aaf2ed818c3bb3b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f14b5f652a240d49afb61f7eeb51bf1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96d5025c0642e094c828bd45f22255c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f57b24297b333ce49a6ea2a6aaed1e99
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1361081bc4466d94796ef0d593a960d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a310a14a9e3851f47a5041b928fdf819
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 20c6ebff010f798409adcf0cfa4b57fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 64d6788171afdaf4ea7aa77cd447bdf7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 81d4af6fac544cc498693b34606a6330
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e157ed67b5af0f74ba3dcbc64fce2cee
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3ad4b2ef850781438a4531d3c8843d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 239487c972f53a549a19b8fe475f3610
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b987fb1d08c23e4085e3f56c50c9b00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c80a416436d3ad046b81659602fcee81
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8bf566b5d7062da48bd2a6b677c9b9a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d818debf0f1df448b721512ddd2b003
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbd5e8cde9a31f840984899768932e65
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_Name: MatVideo
|
||||
m_Shader: {fileID: 10752, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords:
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7e7287421125684092160210210c506
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,91 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: YUVTexture
|
||||
m_Shader: {fileID: 4800000, guid: 00d866b188488114283719ad682ee1a3, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_LockedProperties:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BumpMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailAlbedoMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailMask:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _DetailNormalMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _EmissionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _MetallicGlossMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _OcclusionMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _ParallaxMap:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _UTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
- _VTex:
|
||||
m_Texture: {fileID: 0}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _BumpScale: 1
|
||||
- _Cutoff: 0.5
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbd448ddc4cd0cb42a5f809e967a4477
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
Shader "Unlit/YUVTransRGB"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex("Texture", 2D) = "black" {}
|
||||
_UTex("U", 2D) = "black" {}
|
||||
_VTex("V", 2D) = "black" {}
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType" = "Opaque" }
|
||||
LOD 100
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD0;
|
||||
UNITY_FOG_COORDS(1)
|
||||
float4 vertex : SV_POSITION;
|
||||
};
|
||||
|
||||
sampler2D _MainTex;
|
||||
sampler2D _UTex;
|
||||
sampler2D _VTex;
|
||||
float4 _MainTex_ST;
|
||||
|
||||
v2f vert(appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f i) : SV_Target
|
||||
{
|
||||
fixed2 uv = fixed2(i.uv.x, i.uv.y);
|
||||
fixed4 ycol = tex2D(_MainTex, uv);
|
||||
fixed4 ucol = tex2D(_UTex, uv);
|
||||
fixed4 vcol = tex2D(_VTex, uv);
|
||||
|
||||
float r = ycol.a + 1.4022 * vcol.a - 0.7011;
|
||||
float g = ycol.a - 0.3456 * ucol.a - 0.7145 * vcol.a + 0.53005;
|
||||
float b = ycol.a + 1.771 * ucol.a - 0.8855;
|
||||
|
||||
fixed4 col = fixed4(b, g, r, 1);
|
||||
col.rgb = GammaToLinearSpace(col.rgb);
|
||||
return col;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00d866b188488114283719ad682ee1a3
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d86868521ba3954d99c23196bc13949
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17a0cbb09e9a6644f933eb06e9fdd525
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,154 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Unity.XR.XREAL.Samples
|
||||
{
|
||||
public enum ButtonState
|
||||
{
|
||||
Normal,
|
||||
Pressed,
|
||||
Hovered,
|
||||
Disabled
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class listens to button state changes and updates the text color accordingly.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Button))]
|
||||
public class ButtonTextColor : MonoBehaviour
|
||||
{
|
||||
private Text buttonText;
|
||||
private Button button;
|
||||
[SerializeField]
|
||||
private Color TextNormalColor;
|
||||
[SerializeField]
|
||||
private Color TextPressColor;
|
||||
[SerializeField]
|
||||
private Color TextHoverColor;
|
||||
[SerializeField]
|
||||
private Color TextDisableColor;
|
||||
|
||||
private ButtonStateListener buttonStateListener;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
button = GetComponent<Button>();
|
||||
if (button != null)
|
||||
{
|
||||
buttonStateListener = button.AddOrGetComponent<ButtonStateListener>();
|
||||
buttonStateListener.onButtonStateChanged += HandleButtonStateChange;
|
||||
}
|
||||
if (buttonText == null)
|
||||
{
|
||||
for (var i = 0; i < transform.childCount; ++i)
|
||||
{
|
||||
var text = transform.GetChild(i).GetComponent<Text>();
|
||||
if (text != null)
|
||||
{
|
||||
buttonText = text;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void HandleButtonStateChange(ButtonState state)
|
||||
{
|
||||
if (buttonText != null)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case ButtonState.Normal:
|
||||
buttonText.color = TextNormalColor;
|
||||
break;
|
||||
case ButtonState.Pressed:
|
||||
buttonText.color = TextPressColor;
|
||||
break;
|
||||
case ButtonState.Hovered:
|
||||
buttonText.color = TextHoverColor;
|
||||
break;
|
||||
case ButtonState.Disabled:
|
||||
buttonText.color = TextDisableColor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
buttonStateListener.onButtonStateChanged -= HandleButtonStateChange;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Listens to pointer events to determine the state of a button.
|
||||
/// </summary>
|
||||
[HideInInspector]
|
||||
public class ButtonStateListener : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler
|
||||
{
|
||||
public delegate void OnButtonStateChanged(ButtonState buttonState);
|
||||
|
||||
/// <summary>
|
||||
/// Event triggered when the button state changes.
|
||||
/// </summary>
|
||||
public event OnButtonStateChanged onButtonStateChanged;
|
||||
|
||||
private Button button;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
button = GetComponent<Button>();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
UpdateState(button.interactable ? ButtonState.Normal : ButtonState.Disabled);
|
||||
}
|
||||
|
||||
public void OnPointerEnter(PointerEventData eventData)
|
||||
{
|
||||
if (button.interactable)
|
||||
{
|
||||
UpdateState(ButtonState.Hovered);
|
||||
Debug.Log("Button Highlighted (Pointer Enter)");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
if (button.interactable)
|
||||
{
|
||||
UpdateState(ButtonState.Normal);
|
||||
Debug.Log("Button Normal (Pointer Exit)");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
if (button.interactable)
|
||||
{
|
||||
UpdateState(ButtonState.Pressed);
|
||||
Debug.Log("Button Pressed (Pointer Down)");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData eventData)
|
||||
{
|
||||
if (button.interactable)
|
||||
{
|
||||
UpdateState(ButtonState.Normal);
|
||||
Debug.Log("Button Released (Pointer Up)");
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
UpdateState(ButtonState.Disabled);
|
||||
}
|
||||
|
||||
private void UpdateState(ButtonState newState)
|
||||
{
|
||||
onButtonStateChanged?.Invoke(newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 371b427884fde244a8e036ef34091480
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,593 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Unity.XR.XREAL.Samples
|
||||
{
|
||||
#if UNITY_ANDROID && !UNITY_EDITOR
|
||||
using GalleryDataProvider = NativeGalleryDataProvider;
|
||||
#else
|
||||
using GalleryDataProvider = MockGalleryDataProvider;
|
||||
#endif
|
||||
public class CaptureExample : MonoBehaviour
|
||||
{
|
||||
public enum ResolutionLevel
|
||||
{
|
||||
High,
|
||||
Middle,
|
||||
Low,
|
||||
}
|
||||
[SerializeField] private Button m_VideoButton;
|
||||
[SerializeField] private Button m_PhotoButton;
|
||||
|
||||
[SerializeField] private Slider m_SliderMic;
|
||||
[SerializeField] private Text m_TextMic;
|
||||
[SerializeField] private Slider m_SliderApp;
|
||||
[SerializeField] private Text m_TextApp;
|
||||
|
||||
[SerializeField] private Dropdown m_QualityDropDown;
|
||||
[SerializeField] private Dropdown m_RenderModeDropDown;
|
||||
[SerializeField] private Dropdown m_AudioStateDropDown;
|
||||
[SerializeField] private Dropdown m_CaptureSideDropDown;
|
||||
[SerializeField] private Toggle m_UseGreenBGToggle;
|
||||
|
||||
[SerializeField] private RawImage m_PreviewRawImage;
|
||||
|
||||
List<string> _ResolutionOptions = new List<string>() {
|
||||
ResolutionLevel.High.ToString(),
|
||||
ResolutionLevel.Middle.ToString(),
|
||||
ResolutionLevel.Low.ToString()
|
||||
};
|
||||
List<string> _RendermodeOptions = new List<string>() {
|
||||
BlendMode.Blend.ToString(),
|
||||
BlendMode.CameraOnly.ToString(),
|
||||
BlendMode.VirtualOnly.ToString()
|
||||
};
|
||||
List<string> _AudioStateOptions = new List<string>() {
|
||||
AudioState.MicAudio.ToString(),
|
||||
AudioState.ApplicationAudio.ToString(),
|
||||
AudioState.ApplicationAndMicAudio.ToString(),
|
||||
AudioState.None.ToString()
|
||||
};
|
||||
List<string> _CaptureSideOptions = new List<string>() {
|
||||
CaptureSide.Single.ToString(),
|
||||
CaptureSide.Both.ToString()
|
||||
};
|
||||
|
||||
public BlendMode blendMode = BlendMode.Blend;
|
||||
public ResolutionLevel resolutionLevel = ResolutionLevel.High;
|
||||
public AudioState audioState = AudioState.ApplicationAudio;
|
||||
public CaptureSide captureside = CaptureSide.Single;
|
||||
public bool useGreenBackGround = false;
|
||||
|
||||
/// <summary> Save the video to Application.persistentDataPath. </summary>
|
||||
/// <value> The full pathname of the video save file. </value>
|
||||
public string VideoSavePath
|
||||
{
|
||||
get
|
||||
{
|
||||
string timeStamp = Time.time.ToString().Replace(".", "").Replace(":", "");
|
||||
string filename = string.Format("Xreal_Record_{0}.mp4", timeStamp);
|
||||
return Path.Combine(Application.persistentDataPath, filename);
|
||||
}
|
||||
}
|
||||
|
||||
GalleryDataProvider galleryDataTool;
|
||||
|
||||
/// <summary> The video capture. </summary>
|
||||
XREALVideoCapture m_VideoCapture = null;
|
||||
|
||||
/// <summary> The photo capture object. </summary>
|
||||
private XREALPhotoCapture m_PhotoCapture;
|
||||
/// <summary> The camera resolution. </summary>
|
||||
private Resolution m_CameraResolution;
|
||||
private bool isOnPhotoProcess = false;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
m_QualityDropDown.options.Clear();
|
||||
m_QualityDropDown.AddOptions(_ResolutionOptions);
|
||||
int default_quality_index = 0;
|
||||
for (int i = 0; i < _ResolutionOptions.Count; i++)
|
||||
{
|
||||
if (_ResolutionOptions[i].Equals(resolutionLevel.ToString()))
|
||||
{
|
||||
default_quality_index = i;
|
||||
}
|
||||
}
|
||||
m_QualityDropDown.value = default_quality_index;
|
||||
m_QualityDropDown.onValueChanged.AddListener((index) =>
|
||||
{
|
||||
Enum.TryParse<ResolutionLevel>(_ResolutionOptions[index],
|
||||
out resolutionLevel);
|
||||
});
|
||||
|
||||
m_RenderModeDropDown.options.Clear();
|
||||
m_RenderModeDropDown.AddOptions(_RendermodeOptions);
|
||||
int default_blendmode_index = 0;
|
||||
for (int i = 0; i < _RendermodeOptions.Count; i++)
|
||||
{
|
||||
if (_RendermodeOptions[i].Equals(blendMode.ToString()))
|
||||
{
|
||||
default_blendmode_index = i;
|
||||
}
|
||||
}
|
||||
m_RenderModeDropDown.value = default_blendmode_index;
|
||||
m_RenderModeDropDown.onValueChanged.AddListener((index) =>
|
||||
{
|
||||
Enum.TryParse<BlendMode>(_RendermodeOptions[index],
|
||||
out blendMode);
|
||||
});
|
||||
|
||||
m_AudioStateDropDown.options.Clear();
|
||||
m_AudioStateDropDown.AddOptions(_AudioStateOptions);
|
||||
int default_audiostate_index = 0;
|
||||
for (int i = 0; i < _AudioStateOptions.Count; i++)
|
||||
{
|
||||
if (_AudioStateOptions[i].Equals(audioState.ToString()))
|
||||
{
|
||||
default_audiostate_index = i;
|
||||
}
|
||||
}
|
||||
m_AudioStateDropDown.value = default_audiostate_index;
|
||||
m_AudioStateDropDown.onValueChanged.AddListener((index) =>
|
||||
{
|
||||
Enum.TryParse<AudioState>(_AudioStateOptions[index],
|
||||
out audioState);
|
||||
});
|
||||
|
||||
m_CaptureSideDropDown.options.Clear();
|
||||
m_CaptureSideDropDown.AddOptions(_CaptureSideOptions);
|
||||
int default_captureside_index = 0;
|
||||
for (int i = 0; i < _CaptureSideOptions.Count; i++)
|
||||
{
|
||||
if (_CaptureSideOptions[i].Equals(captureside.ToString()))
|
||||
{
|
||||
default_captureside_index = i;
|
||||
}
|
||||
}
|
||||
m_CaptureSideDropDown.value = default_captureside_index;
|
||||
m_CaptureSideDropDown.onValueChanged.AddListener((index) =>
|
||||
{
|
||||
Enum.TryParse<CaptureSide>(_CaptureSideOptions[index],
|
||||
out captureside);
|
||||
});
|
||||
|
||||
m_UseGreenBGToggle.isOn = useGreenBackGround;
|
||||
m_UseGreenBGToggle.onValueChanged.AddListener((val) =>
|
||||
{
|
||||
useGreenBackGround = val;
|
||||
});
|
||||
|
||||
if (m_SliderMic != null)
|
||||
{
|
||||
m_SliderMic.maxValue = 5.0f;
|
||||
m_SliderMic.minValue = 0.1f;
|
||||
m_SliderMic.value = 1;
|
||||
m_SliderMic.onValueChanged.AddListener(OnSlideMicValueChange);
|
||||
}
|
||||
|
||||
if (m_SliderApp != null)
|
||||
{
|
||||
m_SliderApp.maxValue = 5.0f;
|
||||
m_SliderApp.minValue = 0.1f;
|
||||
m_SliderApp.value = 1;
|
||||
m_SliderApp.onValueChanged.AddListener(OnSlideAppValueChange);
|
||||
}
|
||||
|
||||
m_VideoButton.onClick.AddListener(RecordVideo);
|
||||
m_PhotoButton.onClick.AddListener(TakeAPhoto);
|
||||
|
||||
RefreshUIState();
|
||||
}
|
||||
|
||||
void OnSlideMicValueChange(float val)
|
||||
{
|
||||
if (m_VideoCapture != null)
|
||||
{
|
||||
VideoEncoder encoder = m_VideoCapture.GetContext().GetEncoder() as VideoEncoder;
|
||||
if (encoder != null)
|
||||
encoder.AdjustVolume(RecorderIndex.REC_MIC, val);
|
||||
}
|
||||
RefreshUIState();
|
||||
}
|
||||
|
||||
void OnSlideAppValueChange(float val)
|
||||
{
|
||||
if (m_VideoCapture != null)
|
||||
{
|
||||
VideoEncoder encoder = m_VideoCapture.GetContext().GetEncoder() as VideoEncoder;
|
||||
if (encoder != null)
|
||||
encoder.AdjustVolume(RecorderIndex.REC_APP, val);
|
||||
}
|
||||
RefreshUIState();
|
||||
}
|
||||
|
||||
void CreateVideoCapture(Action callback)
|
||||
{
|
||||
XREALVideoCaptureUtility.CreateAsync(false, delegate (XREALVideoCapture videoCapture)
|
||||
{
|
||||
Debug.Log("Created VideoCapture Instance!");
|
||||
if (videoCapture != null)
|
||||
{
|
||||
m_VideoCapture = videoCapture;
|
||||
callback?.Invoke();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("Failed to create VideoCapture Instance!");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void RecordVideo()
|
||||
{
|
||||
if (m_VideoCapture == null)
|
||||
{
|
||||
CreateVideoCapture(() =>
|
||||
{
|
||||
StartVideoCapture();
|
||||
});
|
||||
}
|
||||
else if (m_VideoCapture.IsRecording)
|
||||
{
|
||||
this.StopVideoCapture();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.StartVideoCapture();
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshUIState()
|
||||
{
|
||||
var recordText = m_VideoButton.transform.Find("Text");
|
||||
if (recordText)
|
||||
{
|
||||
bool notStarted = m_VideoCapture == null || !m_VideoCapture.IsRecording;
|
||||
recordText.GetComponent<Text>().text = notStarted ? "Start Record" : "Stop Record";
|
||||
}
|
||||
|
||||
if (m_TextMic != null && m_SliderMic != null)
|
||||
m_TextMic.text = m_SliderMic.value.ToString("F1");
|
||||
if (m_TextApp != null && m_SliderApp != null)
|
||||
m_TextApp.text = m_SliderApp.value.ToString("F1");
|
||||
}
|
||||
|
||||
/// <summary> Starts video capture. </summary>
|
||||
public void StartVideoCapture()
|
||||
{
|
||||
if (m_VideoCapture == null || m_VideoCapture.IsRecording)
|
||||
{
|
||||
Debug.LogWarning("Can not start video capture!");
|
||||
return;
|
||||
}
|
||||
|
||||
CameraParameters cameraParameters = new CameraParameters();
|
||||
Resolution cameraResolution = GetResolutionByLevel(resolutionLevel);
|
||||
cameraParameters.cameraType = CameraType.RGB;
|
||||
cameraParameters.hologramOpacity = 0.0f;
|
||||
cameraParameters.frameRate = NativeConstants.RECORD_FPS_DEFAULT;
|
||||
cameraParameters.cameraResolutionWidth = cameraResolution.width;
|
||||
cameraParameters.cameraResolutionHeight = cameraResolution.height;
|
||||
cameraParameters.pixelFormat = CapturePixelFormat.PNG;
|
||||
cameraParameters.blendMode = blendMode;
|
||||
// Set audio state, audio record needs the permission of "android.permission.RECORD_AUDIO",
|
||||
// Add it to your "AndroidManifest.xml" file in "Assets/Plugin".
|
||||
cameraParameters.audioState = audioState;
|
||||
cameraParameters.captureSide = captureside;
|
||||
cameraParameters.backgroundColor = useGreenBackGround ? Color.green : Color.black;
|
||||
|
||||
m_VideoCapture.StartVideoModeAsync(cameraParameters, OnStartedVideoCaptureMode, true);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary> Stops video capture. </summary>
|
||||
public void StopVideoCapture()
|
||||
{
|
||||
if (m_VideoCapture == null || !m_VideoCapture.IsRecording)
|
||||
{
|
||||
Debug.LogWarning("Can not stop video capture!");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("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.Log("Started Video Capture Mode faild!");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("Started Video Capture Mode!");
|
||||
if (m_SliderMic != null && m_SliderApp != null)
|
||||
{
|
||||
float volumeMic = m_SliderMic.value;
|
||||
float volumeApp = m_SliderApp.value;
|
||||
m_VideoCapture.StartRecordingAsync(VideoSavePath, OnStartedRecordingVideo, volumeMic, volumeApp);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_VideoCapture.StartRecordingAsync(VideoSavePath, OnStartedRecordingVideo);
|
||||
}
|
||||
|
||||
m_PreviewRawImage.texture = m_VideoCapture.PreviewTexture;
|
||||
}
|
||||
|
||||
/// <summary> Executes the 'started recording video' action. </summary>
|
||||
/// <param name="result"> The result.</param>
|
||||
void OnStartedRecordingVideo(XREALVideoCapture.VideoCaptureResult result)
|
||||
{
|
||||
if (!result.success)
|
||||
{
|
||||
Debug.Log("Started Recording Video Faild!");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("Started Recording Video!");
|
||||
RefreshUIState();
|
||||
}
|
||||
|
||||
/// <summary> Executes the 'stopped recording video' action. </summary>
|
||||
/// <param name="result"> The result.</param>
|
||||
void OnStoppedRecordingVideo(XREALVideoCapture.VideoCaptureResult result)
|
||||
{
|
||||
if (!result.success)
|
||||
{
|
||||
Debug.Log("Stopped Recording Video Faild!");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log("Stopped Recording Video!");
|
||||
m_VideoCapture.StopVideoModeAsync(OnStoppedVideoCaptureMode);
|
||||
}
|
||||
|
||||
/// <summary> Executes the 'stopped video capture mode' action. </summary>
|
||||
/// <param name="result"> The result.</param>
|
||||
void OnStoppedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result)
|
||||
{
|
||||
Debug.Log("Stopped Video Capture Mode!");
|
||||
RefreshUIState();
|
||||
|
||||
var encoder = m_VideoCapture.GetContext().GetEncoder() as VideoEncoder;
|
||||
string path = encoder.EncodeConfig.outPutPath;
|
||||
string filename = string.Format("Xreal_Shot_Video_{0}.mp4", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
|
||||
|
||||
StartCoroutine(DelayInsertVideoToGallery(path, filename, "Record"));
|
||||
|
||||
// Release video capture resource.
|
||||
m_VideoCapture.Dispose();
|
||||
m_VideoCapture = null;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Release video capture resource.
|
||||
m_VideoCapture?.Dispose();
|
||||
m_VideoCapture = null;
|
||||
|
||||
// Relase photo capture resource
|
||||
m_PhotoCapture?.Dispose();
|
||||
m_PhotoCapture = null;
|
||||
}
|
||||
|
||||
IEnumerator DelayInsertVideoToGallery(string originFilePath, string displayName, string folderName)
|
||||
{
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
InsertVideoToGallery(originFilePath, displayName, folderName);
|
||||
}
|
||||
|
||||
public void InsertVideoToGallery(string originFilePath, string displayName, string folderName)
|
||||
{
|
||||
Debug.LogFormat("InsertVideoToGallery: {0}, {1} => {2}", displayName, originFilePath, folderName);
|
||||
if (galleryDataTool == null)
|
||||
{
|
||||
galleryDataTool = new GalleryDataProvider();
|
||||
}
|
||||
|
||||
galleryDataTool.InsertVideo(originFilePath, displayName, folderName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary> Use this for initialization. </summary>
|
||||
void CreatePhotoCapture(Action<XREALPhotoCapture> onCreated)
|
||||
{
|
||||
if (m_PhotoCapture != null)
|
||||
{
|
||||
Debug.Log("[TakePicture] CreatePhotoCapture: The XREALPhotoCapture has already been created.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a PhotoCapture object
|
||||
XREALPhotoCapture.CreateAsync(false, delegate (XREALPhotoCapture captureObject)
|
||||
{
|
||||
m_CameraResolution = XREALPhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
|
||||
|
||||
if (captureObject == null)
|
||||
{
|
||||
Debug.LogError("Can not get a captureObject.");
|
||||
return;
|
||||
}
|
||||
|
||||
m_PhotoCapture = captureObject;
|
||||
|
||||
CameraParameters cameraParameters = new CameraParameters();
|
||||
Resolution cameraResolution = GetResolutionByLevel(resolutionLevel);
|
||||
cameraParameters.cameraType = CameraType.RGB;
|
||||
cameraParameters.hologramOpacity = 0.0f;
|
||||
cameraParameters.frameRate = NativeConstants.RECORD_FPS_DEFAULT;
|
||||
cameraParameters.cameraResolutionWidth = cameraResolution.width;
|
||||
cameraParameters.cameraResolutionHeight = cameraResolution.height;
|
||||
cameraParameters.pixelFormat = CapturePixelFormat.PNG;
|
||||
cameraParameters.blendMode = blendMode;
|
||||
cameraParameters.audioState = AudioState.None;
|
||||
cameraParameters.captureSide = captureside;
|
||||
cameraParameters.backgroundColor = useGreenBackGround ? Color.green : Color.black;
|
||||
|
||||
// Activate the camera
|
||||
m_PhotoCapture.StartPhotoModeAsync(cameraParameters, delegate (XREALPhotoCapture.PhotoCaptureResult result)
|
||||
{
|
||||
Debug.Log("Start PhotoMode Async");
|
||||
if (result.success)
|
||||
{
|
||||
onCreated?.Invoke(m_PhotoCapture);
|
||||
}
|
||||
else
|
||||
{
|
||||
isOnPhotoProcess = false;
|
||||
this.ClosePhotoCapture();
|
||||
Debug.LogError("[TakePicture] CreatePhotoCapture: Start PhotoMode failed." + result.resultType);
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary> Take a photo. </summary>
|
||||
void TakeAPhoto()
|
||||
{
|
||||
if (isOnPhotoProcess)
|
||||
{
|
||||
Debug.LogWarning("[TakePicture] TakeAPhoto: Currently in the process of taking pictures, Can not take photo .");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
isOnPhotoProcess = true;
|
||||
|
||||
if (m_PhotoCapture == null)
|
||||
{
|
||||
this.CreatePhotoCapture((capture) =>
|
||||
{
|
||||
capture.TakePhotoAsync(OnCapturedPhotoToMemory);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PhotoCapture.TakePhotoAsync(OnCapturedPhotoToMemory);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Executes the 'captured photo memory' action. </summary>
|
||||
/// <param name="result"> The result.</param>
|
||||
/// <param name="photoCaptureFrame"> The photo capture frame.</param>
|
||||
void OnCapturedPhotoToMemory(XREALPhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
|
||||
{
|
||||
Debug.Log("[TakePicture] OnCapturedPhotoToMemory");
|
||||
var targetTexture = new Texture2D(m_CameraResolution.width, m_CameraResolution.height);
|
||||
// Copy the raw image data into our target texture
|
||||
photoCaptureFrame.UploadImageDataToTexture(targetTexture);
|
||||
|
||||
SaveTextureAsPNG(photoCaptureFrame);
|
||||
SaveTextureToGallery(photoCaptureFrame);
|
||||
// Release camera resource after capture the photo.
|
||||
this.ClosePhotoCapture();
|
||||
}
|
||||
|
||||
void SaveTextureAsPNG(PhotoCaptureFrame photoCaptureFrame)
|
||||
{
|
||||
Debug.Log("[TakePicture] SaveTextureAsPNG");
|
||||
if (photoCaptureFrame.TextureData == null)
|
||||
{
|
||||
Debug.LogError("[TakePicture] SaveTextureAsPNG: TextureData is null");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
string filename = string.Format("Xreal_Shot_{0}.png", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
|
||||
string path = string.Format("{0}/XrealShots", Application.persistentDataPath);
|
||||
string filePath = string.Format("{0}/{1}", path, filename);
|
||||
|
||||
byte[] _bytes = photoCaptureFrame.TextureData;
|
||||
Debug.LogFormat("[TakePicture] Photo capture: {0}Kb was saved to [{1}]", _bytes.Length / 1024, filePath);
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
File.WriteAllBytes(string.Format("{0}/{1}", path, filename), _bytes);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Save picture failed! {e}");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary> Closes this object. </summary>
|
||||
void ClosePhotoCapture()
|
||||
{
|
||||
if (m_PhotoCapture == null)
|
||||
{
|
||||
Debug.LogError("The XREALPhotoCapture has not been created.");
|
||||
return;
|
||||
}
|
||||
// Deactivate our camera
|
||||
m_PhotoCapture.StopPhotoModeAsync(OnStoppedPhotoMode);
|
||||
}
|
||||
|
||||
/// <summary> Executes the 'stopped photo mode' action. </summary>
|
||||
/// <param name="result"> The result.</param>
|
||||
void OnStoppedPhotoMode(XREALPhotoCapture.PhotoCaptureResult result)
|
||||
{
|
||||
// Shutdown our photo capture resource
|
||||
m_PhotoCapture?.Dispose();
|
||||
m_PhotoCapture = null;
|
||||
isOnPhotoProcess = false;
|
||||
}
|
||||
|
||||
public void SaveTextureToGallery(PhotoCaptureFrame photoCaptureFrame)
|
||||
{
|
||||
Debug.Log("[TakePicture] SaveTextureToGallery");
|
||||
if (photoCaptureFrame.TextureData == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
string filename = string.Format("Xreal_Shot_{0}.png", DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString());
|
||||
byte[] _bytes = photoCaptureFrame.TextureData;
|
||||
Debug.Log(_bytes.Length / 1024 + "Kb was saved as: " + filename);
|
||||
if (galleryDataTool == null)
|
||||
{
|
||||
galleryDataTool = new GalleryDataProvider();
|
||||
}
|
||||
|
||||
galleryDataTool.InsertImage(_bytes, filename, "Screenshots");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("[TakePicture] Save picture faild!");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0658699caa291c343b0fdfdcf85f0237
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,70 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Unity.XR.XREAL.Samples
|
||||
{
|
||||
public class RGBCameraExample : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private Text m_ImageFormatText;
|
||||
[SerializeField]
|
||||
private RawImage m_YUVImage;
|
||||
[SerializeField]
|
||||
private Button m_PlayButton;
|
||||
[SerializeField]
|
||||
private Button m_StopButton;
|
||||
|
||||
private XREALRGBCameraTexture m_RGBCameraTexture;
|
||||
|
||||
void Start()
|
||||
{
|
||||
Debug.Log($"[RGBCamera] Start");
|
||||
m_RGBCameraTexture = XREALRGBCameraTexture.CreateSingleton();
|
||||
m_PlayButton.onClick.AddListener(Play);
|
||||
m_StopButton.onClick.AddListener(Stop);
|
||||
InitUI();
|
||||
Play();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
var yuvTextures = m_RGBCameraTexture.GetYUVFormatTextures();
|
||||
if (yuvTextures[0] != null)
|
||||
{
|
||||
m_YUVImage.texture = yuvTextures[0];
|
||||
m_YUVImage.material.SetTexture("_UTex", yuvTextures[1]);
|
||||
m_YUVImage.material.SetTexture("_VTex", yuvTextures[2]);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
Debug.Log($"[RGBCamera] OnDestroy");
|
||||
Stop();
|
||||
}
|
||||
|
||||
private void InitUI()
|
||||
{
|
||||
m_ImageFormatText.text = "YUV_420_888";
|
||||
m_YUVImage.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
if (!m_RGBCameraTexture.IsCapturing)
|
||||
{
|
||||
Debug.Log($"[RGBCamera] Play");
|
||||
m_RGBCameraTexture.StartCapture();
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (m_RGBCameraTexture.IsCapturing)
|
||||
{
|
||||
Debug.Log($"[RGBCamera] Stop");
|
||||
m_RGBCameraTexture.StopCapture();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c00e84ada4a57d94ab4f9bfd2a573fc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user