diff --git a/Assets/Epic Toon FX/New Physics Material.physicMaterial b/Assets/Epic Toon FX/New Physics Material.physicMaterial new file mode 100644 index 000000000..e7fd88bdd --- /dev/null +++ b/Assets/Epic Toon FX/New Physics Material.physicMaterial @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!134 &13400000 +PhysicsMaterial: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: New Physics Material + serializedVersion: 2 + m_DynamicFriction: 0.6 + m_StaticFriction: 0.6 + m_Bounciness: 0 + m_FrictionCombine: 0 + m_BounceCombine: 0 diff --git a/Assets/Epic Toon FX/New Physics Material.physicMaterial.meta b/Assets/Epic Toon FX/New Physics Material.physicMaterial.meta new file mode 100644 index 000000000..10842b1f2 --- /dev/null +++ b/Assets/Epic Toon FX/New Physics Material.physicMaterial.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61bb76bf4ca61c4439c808ff61f71eee +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 13400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Main.unity b/Assets/Main.unity new file mode 100644 index 000000000..db722d8c7 --- /dev/null +++ b/Assets/Main.unity @@ -0,0 +1,755 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &436706929 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 436706932} + - component: {fileID: 436706931} + - component: {fileID: 436706930} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &436706930 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 436706929} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 01614664b831546d2ae94a42149d80ac, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_MoveRepeatDelay: 0.5 + m_MoveRepeatRate: 0.1 + m_XRTrackingOrigin: {fileID: 0} + m_ActionsAsset: {fileID: -944628639613478452, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_PointAction: {fileID: -1654692200621890270, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_MoveAction: {fileID: -8784545083839296357, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_SubmitAction: {fileID: 392368643174621059, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_CancelAction: {fileID: 7727032971491509709, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_LeftClickAction: {fileID: 3001919216989983466, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_MiddleClickAction: {fileID: -2185481485913320682, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_RightClickAction: {fileID: -4090225696740746782, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_ScrollWheelAction: {fileID: 6240969308177333660, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_TrackedDevicePositionAction: {fileID: 6564999863303420839, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_TrackedDeviceOrientationAction: {fileID: 7970375526676320489, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3} + m_DeselectOnBackgroundClick: 1 + m_PointerBehavior: 0 + m_CursorLockBehavior: 0 + m_ScrollDeltaPerTick: 6 +--- !u!114 &436706931 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 436706929} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &436706932 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 436706929} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1389274544 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1389274546} + - component: {fileID: 1389274545} + - component: {fileID: 1389274547} + 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 &1389274545 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1389274544} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + 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: 4 + 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_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &1389274546 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1389274544} + 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!114 &1389274547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1389274544} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Version: 3 + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_LightLayerMask: 1 + m_RenderingLayers: 1 + m_CustomShadowLayers: 0 + m_ShadowLayerMask: 1 + m_ShadowRenderingLayers: 1 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 0 +--- !u!1 &1486902902 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1486902906} + - component: {fileID: 1486902905} + - component: {fileID: 1486902904} + - component: {fileID: 1486902903} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1486902903 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1486902902} + 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: 55 +--- !u!114 &1486902904 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1486902902} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1080, y: 1920} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1486902905 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1486902902} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 25 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1486902906 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1486902902} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2005243550} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1563064954 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1563064957} + - component: {fileID: 1563064956} + - component: {fileID: 1563064955} + - component: {fileID: 1563064958} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1563064955 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1563064954} + m_Enabled: 1 +--- !u!20 &1563064956 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1563064954} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1563064957 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1563064954} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1563064958 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1563064954} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 0 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_Version: 2 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 +--- !u!1 &2005243549 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2005243550} + - component: {fileID: 2005243552} + - component: {fileID: 2005243551} + m_Layer: 5 + m_Name: Text (TMP) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2005243550 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2005243549} + 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: 1486902906} + 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: 200, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2005243551 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2005243549} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, 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_text: "\uC548\uB155\uD558\uC138\uC694" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 2f35c40df3d2a1a41b57c8b9eca40913, type: 2} + m_sharedMaterial: {fileID: 1328173432319114220, guid: 2f35c40df3d2a1a41b57c8b9eca40913, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 256 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!222 &2005243552 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2005243549} + m_CullTransparentMesh: 1 +--- !u!1 &2083820693 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2083820694} + - component: {fileID: 2083820695} + m_Layer: 0 + m_Name: GameSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2083820694 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2083820693} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2083820695 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2083820693} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d9900e00b5a026c44bd0dd8b5acdce03, type: 3} + m_Name: + m_EditorClassIdentifier: + loaderID: SLWindowsLoader + systemID: SLSystem + mainManager: DDDMain + managers: + - DDDMain + - ModeManager +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1563064957} + - {fileID: 1389274546} + - {fileID: 1486902906} + - {fileID: 436706932} + - {fileID: 2083820694} diff --git a/Assets/Main.unity.meta b/Assets/Main.unity.meta new file mode 100644 index 000000000..fe501a4ea --- /dev/null +++ b/Assets/Main.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 65901a32867ef6243ab4c87a5858d3c7 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scirpts.meta b/Assets/Scirpts.meta new file mode 100644 index 000000000..ea6df74fb --- /dev/null +++ b/Assets/Scirpts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b41c9ea4d54c4cc41b4b67a9cefde1e7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scirpts/DDDMain.cs b/Assets/Scirpts/DDDMain.cs new file mode 100644 index 000000000..fbea06277 --- /dev/null +++ b/Assets/Scirpts/DDDMain.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +public class DDDMain : SLGameComponent +{ + public override void Begin() + { + SLGame.Session["CurrentMode"] = "Title"; + } + + public override void End() + { + } + + public override void Update() + { + } +} diff --git a/Assets/Scirpts/DDDMain.cs.meta b/Assets/Scirpts/DDDMain.cs.meta new file mode 100644 index 000000000..e856b968b --- /dev/null +++ b/Assets/Scirpts/DDDMain.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8f35ea449573afc498bb9da070fa9431 \ No newline at end of file diff --git a/Assets/Scirpts/ModeManager.cs b/Assets/Scirpts/ModeManager.cs new file mode 100644 index 000000000..8493370de --- /dev/null +++ b/Assets/Scirpts/ModeManager.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +public class ModeManager : SLGameComponent +{ + public override void Begin() + { + SLGame.AddNotify("CurrentMode", OnChangeMode); + } + + private void OnChangeMode() + { + var currentMode = SLGame.Session["CurrentMode"]; + + // TODO: 씬을 바꿔준다 + } + + public override void End() + { + } + + public override void Update() + { + } +} diff --git a/Assets/Scirpts/ModeManager.cs.meta b/Assets/Scirpts/ModeManager.cs.meta new file mode 100644 index 000000000..d6b0b4361 --- /dev/null +++ b/Assets/Scirpts/ModeManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1b059a9cf476ed345a02926176bb9b34 diff --git a/Assets/Settings/Resources.meta b/Assets/Settings/Resources.meta new file mode 100644 index 000000000..fd0fcac34 --- /dev/null +++ b/Assets/Settings/Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40ffb09c51825264ca46b822118d3d97 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Resources/AstarGizmos.asset b/Assets/Settings/Resources/AstarGizmos.asset new file mode 100644 index 000000000..2db24ccab --- /dev/null +++ b/Assets/Settings/Resources/AstarGizmos.asset @@ -0,0 +1,23 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 98e3089fbc7bff2b78412546c703c554, type: 3} + m_Name: AstarGizmos + m_EditorClassIdentifier: + version: 0 + settings: + lineOpacity: 1 + solidOpacity: 0.55 + textOpacity: 1 + lineOpacityBehindObjects: 0.12 + solidOpacityBehindObjects: 0.45 + textOpacityBehindObjects: 0.9 + curveResolution: 1 diff --git a/Assets/Settings/Resources/AstarGizmos.asset.meta b/Assets/Settings/Resources/AstarGizmos.asset.meta new file mode 100644 index 000000000..5cdbbb695 --- /dev/null +++ b/Assets/Settings/Resources/AstarGizmos.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d3f09ade5e063b74fad796a409e8013c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLLogger/ISLLogger.cs b/Packages/SLLogger/ISLLogger.cs new file mode 100644 index 000000000..c6f1cdad8 --- /dev/null +++ b/Packages/SLLogger/ISLLogger.cs @@ -0,0 +1,11 @@ +namespace Superlazy +{ + public interface ISLLogger + { + void Info(string format, params object[] args); + + void Warn(string format, params object[] args); + + void Error(string format, params object[] args); + } +} \ No newline at end of file diff --git a/Packages/SLLogger/ISLLogger.cs.meta b/Packages/SLLogger/ISLLogger.cs.meta new file mode 100644 index 000000000..f42bffe04 --- /dev/null +++ b/Packages/SLLogger/ISLLogger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f93bf8f3ffea29c4db3a7eabd0119ae6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLLogger/SLLog.cs b/Packages/SLLogger/SLLog.cs new file mode 100644 index 000000000..e8a59ac75 --- /dev/null +++ b/Packages/SLLogger/SLLog.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Superlazy +{ + public static class SLLog + { + public static ISLLogger Logger + { + set + { + Loggers ??= new List(); + Loggers.Add(value); + } + } + + private static List Loggers { get; set; } + + [Conditional("SLLOG"), Conditional("UNITY_EDITOR")] + public static void Error(string format, params object[] args) + { + if (Loggers == null) return; + foreach (var logger in Loggers) + { + logger.Error(format, args); + } + } + + [Conditional("SLLOG"), Conditional("UNITY_EDITOR")] + public static void Info(string format, params object[] args) + { + if (Loggers == null) return; + foreach (var logger in Loggers) + { + logger.Info(format, args); + } + } + + [Conditional("SLLOG"), Conditional("UNITY_EDITOR")] + public static void Warn(string format, params object[] args) + { + if (Loggers == null) return; + foreach (var logger in Loggers) + { + logger.Warn(format, args); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLLogger/SLLog.cs.meta b/Packages/SLLogger/SLLog.cs.meta new file mode 100644 index 000000000..9ad29fe62 --- /dev/null +++ b/Packages/SLLogger/SLLog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bea77d7b448102e49bfeebe6a3d23eaa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLLogger/SLLogger.asmdef b/Packages/SLLogger/SLLogger.asmdef new file mode 100644 index 000000000..727e8f7f8 --- /dev/null +++ b/Packages/SLLogger/SLLogger.asmdef @@ -0,0 +1,3 @@ +{ + "name": "SLLogger" +} diff --git a/Packages/SLLogger/SLLogger.asmdef.meta b/Packages/SLLogger/SLLogger.asmdef.meta new file mode 100644 index 000000000..be5d73735 --- /dev/null +++ b/Packages/SLLogger/SLLogger.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f0e91edf4495c2045b34f001325cddb3 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLLogger/SLLogger.csproj.meta b/Packages/SLLogger/SLLogger.csproj.meta new file mode 100644 index 000000000..910531798 --- /dev/null +++ b/Packages/SLLogger/SLLogger.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a18b99084fc30604b9de617a181246f0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLLogger/package.json b/Packages/SLLogger/package.json new file mode 100644 index 000000000..702c79fb7 --- /dev/null +++ b/Packages/SLLogger/package.json @@ -0,0 +1,9 @@ +{ + "name": "com.superlazy.sllogger", + "displayName": "SL Logger", + "description": "SL Logger", + "version": "1.0.0", + "unity": "2018.2", + "license": "MIT", + "dependencies": {} +} \ No newline at end of file diff --git a/Packages/SLLogger/package.json.meta b/Packages/SLLogger/package.json.meta new file mode 100644 index 000000000..60db92e17 --- /dev/null +++ b/Packages/SLLogger/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2a5b4383d891a734aa2cbfaf1f4c1d4c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/ComponentOrderAttribute.cs b/Packages/SLSystem/ComponentOrderAttribute.cs new file mode 100644 index 000000000..af6a8afd2 --- /dev/null +++ b/Packages/SLSystem/ComponentOrderAttribute.cs @@ -0,0 +1,19 @@ +using System; + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] +public class ComponentOrderAttribute : Attribute +{ + public int order; + public string methodOverride; + + public ComponentOrderAttribute(int order) + { + this.order = order; + } + + public ComponentOrderAttribute(string methodOverride, int order) + { + this.order = order; + this.methodOverride = methodOverride; + } +} \ No newline at end of file diff --git a/Packages/SLSystem/ComponentOrderAttribute.cs.meta b/Packages/SLSystem/ComponentOrderAttribute.cs.meta new file mode 100644 index 000000000..e5a872095 --- /dev/null +++ b/Packages/SLSystem/ComponentOrderAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 730f3af4df651064da4cd6a28965353e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/Evaluator.cs b/Packages/SLSystem/Evaluator.cs new file mode 100644 index 000000000..aae22f009 --- /dev/null +++ b/Packages/SLSystem/Evaluator.cs @@ -0,0 +1,135 @@ +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Superlazy; + +public class Evaluator +{ + public static string Evaluate(SLEntity player, string desc) + { + if (desc.StartsWith('$') == false) return desc; + + // 변수 대체: {name} 패턴을 찾아 Global.Get으로 변환 + var replacedDesc = Regex.Replace(desc.Substring(1), @"\{(\w+)\}", match => + { + var varName = match.Groups[1].Value; + var ret = player["EventValues"].Get(varName); // 그냥 글로벌로 하면 변수 길어질듯해서 + if (ret.IsValue && ret.IsNumeric == false) return $"\"{ret}\""; + + return ret; + }); + + return EvaluateExpression(replacedDesc); + } + + private static SLEntity EvaluateExpression(string expression) + { + var values = new Stack(); // 값을 저장하는 스택 (숫자 또는 문자열) + var operators = new Stack(); // 연산자를 저장하는 스택 + + var i = 0; + while (i < expression.Length) + { + if (char.IsDigit(expression[i])) // 숫자 처리 + { + var number = ""; + while (i < expression.Length && (char.IsDigit(expression[i]) || expression[i] == '.')) + { + number += expression[i]; + i++; + } + values.Push(float.Parse(number)); + } + else if (expression[i] == '"') // 문자열 처리 + { + // 문자열 리터럴 처리 (큰 따옴표로 감싸진 문자열) + i++; + var str = ""; + while (i < expression.Length && expression[i] != '"') + { + str += expression[i]; + i++; + } + i++; // 닫는 따옴표 넘기기 + values.Push(str); + } + else if (expression[i] == '(') + { + operators.Push('('); + i++; + } + else if (expression[i] == ')') + { + while (operators.Peek() != '(') + { + values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop())); + } + operators.Pop(); // '(' 제거 + i++; + } + else if (IsOperator(expression[i])) + { + // 연산자 처리 + while (operators.Count > 0 && GetPrecedence(operators.Peek()) >= GetPrecedence(expression[i])) + { + values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop())); + } + operators.Push(expression[i]); + i++; + } + else + { + // 공백 등 기타 문자는 그냥 넘김 + i++; + } + } + + while (operators.Count > 0) + { + values.Push(ApplyOperator(values.Pop(), values.Pop(), operators.Pop())); + } + + return values.Pop(); + } + + // 연산자 우선순위 + private static int GetPrecedence(char op) + { + if (op == '+' || op == '-') return 1; + if (op == '*' || op == '/') return 2; + return 0; + } + + // 연산자 확인 + private static bool IsOperator(char c) + { + return c == '+' || c == '-' || c == '*' || c == '/'; + } + + // 연산자 적용 + private static SLEntity ApplyOperator(SLEntity right, SLEntity left, char op) + { + return op switch + { + '+' => left + right, + '-' => left - right, + '*' => left * right, + '/' => left / right, + _ => SLEntity.Empty, + }; + } + + public static void ApplyEvaluate(SLEntity player, SLEntity current) + { + foreach (var c in current) + { + if (c.IsValue && c.IsNumeric == false) + { + current[c.ID] = Evaluate(player, c); + } + else if (c.IsValue == false) + { + ApplyEvaluate(player, c); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/Evaluator.cs.meta b/Packages/SLSystem/Evaluator.cs.meta new file mode 100644 index 000000000..660e710c7 --- /dev/null +++ b/Packages/SLSystem/Evaluator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5cad9ae5f1395af4187eb9369a165695 \ No newline at end of file diff --git a/Packages/SLSystem/SLDateTimeUtil.cs b/Packages/SLSystem/SLDateTimeUtil.cs new file mode 100644 index 000000000..7ec3119b6 --- /dev/null +++ b/Packages/SLSystem/SLDateTimeUtil.cs @@ -0,0 +1,209 @@ +using System; +using Superlazy; + +public static class SLDateTimeUtil +{ + private const double oADateMaxAsDouble = 2958466.0; + private const double oADateMinAsDouble = -657435.0; + private const int millisPerSecond = 1000; + private const int millisPerMinute = millisPerSecond * 60; + private const int millisPerHour = millisPerMinute * 60; + private const int millisPerDay = millisPerHour * 24; + + // Number of 100ns ticks per time unit + private const long ticksPerMillisecond = 10000; + + private const long ticksPerSecond = ticksPerMillisecond * 1000; + private const long ticksPerMinute = ticksPerSecond * 60; + private const long ticksPerHour = ticksPerMinute * 60; + private const long ticksPerDay = ticksPerHour * 24; + + // Number of days in a non-leap year + private const int daysPerYear = 365; + + // Number of days in 4 years + private const int daysPer4Years = daysPerYear * 4 + 1; // 1461 + + // Number of days in 100 years + private const int daysPer100Years = daysPer4Years * 25 - 1; // 36524 + + // Number of days in 400 years + private const int daysPer400Years = daysPer100Years * 4 + 1; // 146097 + + // Number of days from 1/1/0001 to 12/31/1600 + + // Number of days from 1/1/0001 to 12/30/1899 + private const int daysTo1899 = daysPer400Years * 4 + daysPer100Years * 3 - 367; + + // Number of days from 1/1/0001 to 12/31/1969 + + // Number of days from 1/1/0001 to 12/31/9999 + private const int daysTo10000 = daysPer400Years * 25 - 366; // 3652059 + + private const long doubleDateOffset = daysTo1899 * ticksPerDay; + private const long maxMillis = (long)daysTo10000 * millisPerDay; + + private const long oADateMinAsTicks = (daysPer100Years - daysPerYear) * ticksPerDay; + + private static long DoubleDateToTicks(double value) + { + // The check done this way will take care of NaN + if (!(value < oADateMaxAsDouble) || !(value > oADateMinAsDouble)) + { + return 0; + } + + // Conversion to long will not cause an overflow here, as at this point the "value" is in between OADateMinAsDouble and OADateMaxAsDouble + var millis = (long)(value * millisPerDay + (value >= 0 ? 0.5 : -0.5)); + // The interesting thing here is when you have a value like 12.5 it all positive 12 days and 12 hours from 01/01/1899 + // However if you a value of -12.25 it is minus 12 days but still positive 6 hours, almost as though you meant -11.75 all negative + // This line below fixes up the millis in the negative case + if (millis < 0) + { + millis -= (millis % millisPerDay) * 2; + } + + millis += doubleDateOffset / ticksPerMillisecond; + + if (millis < 0 || millis >= maxMillis) + { + return 0; + } + return millis * ticksPerMillisecond; + } + + private static double TicksToOADate(long value) + { + if (value == 0) + return 0.0; // Returns OleAut's zero'ed date value. + if (value < ticksPerDay) // This is a fix for VB. They want the default day to be 1/1/0001 rathar then 12/30/1899. + value += doubleDateOffset; // We could have moved this fix down but we would like to keep the bounds check. + if (value < oADateMinAsTicks) + throw new OverflowException(); + // Currently, our max date == OA's max date (12/31/9999), so we don't + // need an overflow check in that direction. + var millis = (value - doubleDateOffset) / ticksPerMillisecond; + if (millis < 0) + { + var frac = millis % millisPerDay; + if (frac != 0) millis -= (millisPerDay + frac) * 2; + } + return Math.Round((double)millis / millisPerDay, 10); + } + + public static DateTime FromSLDate(double d) + { + return new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified); + } + + public static DateTime FromSLDateToKRDate(double d) + { + return (new DateTime(DoubleDateToTicks(d), DateTimeKind.Unspecified)).AddHours(9); + } + + public static DateTime ToDateTime(this SLEntity value) + { + return new DateTime(DoubleDateToTicks(value), DateTimeKind.Unspecified); + } + + public static DateTime ToLocalDateTime(this SLEntity value) + { + return new DateTime(DoubleDateToTicks(value), DateTimeKind.Unspecified).ToLocalTime(); + } + + public static DateTime ToDayStart(this DateTime dt) + { + return new DateTime(dt.Year, dt.Month, dt.Day); + } + + public static DateTime ToKRInitTime(this DateTime dt) + { + return dt.AddDays(1).AddHours(3).ToDayStart().AddHours(-3); + } + + public static DateTime ToRankingEndTime(this DateTime dt) + { + return dt.AddDays(1).AddHours(3).AddMinutes(15).ToDayStart().AddHours(-3).AddMinutes(-15); + } + + public static DateTime ToWeekliyInitTime(this DateTime dt) + { + if (dt < dt.ToKRInitTime().AddDays(-1)) + { + return dt.ToKRInitTime().AddDays(-1); + } + else + { + var delta = 7 + DayOfWeek.Monday - dt.DayOfWeek; + return dt.AddDays(delta).AddHours(3).ToDayStart().AddHours(-3); + } + } + + public static double ToSLDate(this DateTime dt) + { + return TicksToOADate(dt.Ticks); + } + + public static double FromKRDateToSLDate(this DateTime dt) + { + return TicksToOADate(dt.AddHours(-9).Ticks); + } + + public static string ToSLDateString(this DateTime dt) + { + return dt.ToString("yyyy-MM-dd"); + } + + public static string ToSLDateTimeString(this DateTime dt) + { + return dt.ToString("yyyy-MM-dd HH:mm:ss"); + } + + public static string ToSLDateTimeString(this DateTimeOffset dt) + { + return dt.ToString("yyyy-MM-dd HH:mm:ss"); + } + + public static bool IsDateIn(DateTime date, SLEntity checkDate) + { + var start = new DateTime(checkDate["YStart"], checkDate["MStart"], checkDate["DStart"], checkDate["HStart"], 0, 0); + + if (checkDate["YEnd"] == false) checkDate["YEnd"] = checkDate["YStart"]; + if (checkDate["MEnd"] == false) checkDate["MEnd"] = checkDate["MStart"]; + if (checkDate["DEnd"] == false) checkDate["DEnd"] = checkDate["DStart"]; + if (checkDate["HEnd"] == false) checkDate["HEnd"] = checkDate["HStart"]; + + var end = new DateTime(checkDate["YEnd"], checkDate["MEnd"], checkDate["DEnd"], checkDate["HEnd"], 0, 0); + return date >= start && date < end; + } +} + +public abstract class SLDateTime +{ + private static SLDateTime instance; + + public static void Init(SLDateTime inst) + { + instance = inst; + } + + public static DateTime Now + { + get + { + if (instance == null) return DateTime.UtcNow; + + return instance.GetNow(); + } + set + { + if (instance == null) return; + + instance.SetNow(value); + } + } + + protected abstract DateTime GetNow(); + + protected abstract void SetNow(DateTime now); +} \ No newline at end of file diff --git a/Packages/SLSystem/SLDateTimeUtil.cs.meta b/Packages/SLSystem/SLDateTimeUtil.cs.meta new file mode 100644 index 000000000..4c26104e3 --- /dev/null +++ b/Packages/SLSystem/SLDateTimeUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 39c2b8bb3f8be6144a6fad50799fa543 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntity.meta b/Packages/SLSystem/SLEntity.meta new file mode 100644 index 000000000..a8b561443 --- /dev/null +++ b/Packages/SLSystem/SLEntity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca529b11f40987640bad27af13b9e13a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntity/Container.cs b/Packages/SLSystem/SLEntity/Container.cs new file mode 100644 index 000000000..d5ad3fc37 --- /dev/null +++ b/Packages/SLSystem/SLEntity/Container.cs @@ -0,0 +1,670 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Superlazy +{ + internal abstract class SLContainerBase : SLEntity + { + public override string ID => id; + + protected SLContainerBase parent; + protected string id; + } + + internal class SLContainer : SLContainerBase + { + private SLEntity original; + private Dictionary attributes; + private HashSet removed; + private List links; + private bool dangled; + + public SLContainer(SLContainerBase original, SLContainerBase parent, string id) + { + this.original = original; + this.parent = parent; + this.id = id; + + if (original.IsNullOrFalse() && this.parent is null == false) + { + dangled = true; + } + } + + internal override SLEntity ToChild(SLContainerBase parent, string id) + { + if (id == null && parent is null) // 삭제시 + { + dangled = true; + + attributes?.Clear(); + removed?.Clear(); + original = null; + + if (links != null) + { + foreach (var link in links) + { + link.DestroyLink(); + } + } + } + else + { + if (dangled == false && this.parent is null == false) + { + return Clone().ToChild(parent, id); + } + else + { + dangled = false; + this.parent = parent; + this.id = id; + } + } + + return this; + } + + public override bool IsNumeric + { + get + { + if (IsExist()) + { + SLLog.Error($"this is not value : {id}"); + } + return false; + } + } + + public override bool IsValue => false; + + internal override bool IsExist() + { + if (dangled && (parent?.HasChild(id) ?? false)) return true; + + if ((attributes?.Count ?? 0) != 0) return true; + + if (original.IsNullOrFalse()) return false; + + if ((removed?.Count ?? 0) == 0) return true; + if (original.Any(e => removed.Contains(e.ID) == false)) return true; + + return false; + } + + public override bool HasChild(string attributeKey) + { + if (attributeKey == "ID") return true; + if (dangled && (parent?.HasChild(id) ?? false)) return parent[id].HasChild(attributeKey); + + if (removed?.Contains(attributeKey) ?? false) return false; + if (attributes?.ContainsKey(attributeKey) ?? false) return true; + + if (original.IsNullOrFalse() == false) + { + return original.HasChild(attributeKey); + } + + return false; + } + + public override IEnumerator GetEnumerator() + { + if (dangled && (parent?.HasChild(id) ?? false)) + { + foreach (var value in parent[id]) + { + yield return value; + } + + yield break; + } + + if (attributes?.Count > 0) + { + var keys = new List(attributes.Keys); + + foreach (var key in keys) + { + yield return attributes[key]; + } + } + + if (original) + { + foreach (var child in original.Where(e => (removed?.Contains(e.ID) ?? false) == false && (attributes?.ContainsKey(e.ID) ?? false) == false).ToList()) + { + yield return this[child.ID]; + } + } + } + + internal override double GetDouble() + { + if (dangled && (parent?.HasChild(id) ?? false)) + { + return parent[id].GetDouble(); + } + + if (IsExist()) + { + SLLog.Error($"this is not value : {id}"); + } + + return 0; + } + + internal override int GetInt() + { + if (dangled && (parent?.HasChild(id) ?? false)) + { + return parent[id].GetInt(); + } + + if (IsExist()) + { + SLLog.Error($"this is not value : {id}"); + } + + return 0; + } + + internal override string GetString() + { + if (dangled && (parent?.HasChild(id) ?? false)) + { + return parent[id].GetString(); + } + + if (IsExist() == false) + { + return string.Empty; + } + + return $"{id}[{attributes?.Count ?? 0}]"; + } + + internal override object GetObj() + { + if (dangled && (parent?.HasChild(id) ?? false)) + { + return parent[id].GetString(); + } + + SLLog.Error($"this is not value : {id}"); + return false; + } + + protected override int GetEntityHashCode() + { + if (dangled && (parent?.HasChild(id) ?? false)) return parent[id].GetHashCode(); + if (attributes != null && removed != null) return attributes.GetHashCode() & removed.GetHashCode(); // TODO: 딕셔너리 대신 정밀한 해시코드를 만들어야함(성능이슈 체크) + if (attributes != null) return attributes.GetHashCode(); // TODO: 딕셔너리 대신 정밀한 해시코드를 만들어야함(성능이슈 체크) + if (removed != null) return removed.GetHashCode(); // TODO: 딕셔너리 대신 정밀한 해시코드를 만들어야함(성능이슈 체크) + if (original.IsNullOrFalse() == false) return original.GetHashCode(); + return 0; + } + + public override SLEntity Link() + { + if (dangled) + { + if (parent?.HasChild(id) ?? false) return parent[id].Link(); + + SLLog.Error("Can't make empty link"); + return false; + } + + if (links == null) + { + links = new List(); + } + + var unusedLink = links.Find(l => l.Unused); + if (unusedLink is null == false) + { + return unusedLink; + } + + var newLink = new SLContainerLink(this); + links.Add(newLink); + return newLink; + } + + public override SLEntity Override() + { + if (dangled) + { + if (parent?.HasChild(id) ?? false) return parent[id].Override(); + + SLLog.Error("Can't make empty override"); + return false; + } + + return new SLContainer(this, null, null); + } + + public override SLEntity this[string attributeKey] + { + get + { + if (attributeKey == "ID") return ID; + + if (dangled) + { + if (parent?.HasChild(id) ?? false) return parent[id][attributeKey]; + return new SLContainer(null, this, attributeKey); // 댕글 + } + + if (removed?.Contains(attributeKey) ?? false) + { + return new SLContainer(null, this, attributeKey); + } + + if (attributes?.ContainsKey(attributeKey) ?? false) + { + return attributes[attributeKey]; + } + + if (original?.HasChild(attributeKey) ?? false) + { + var originalValue = original[attributeKey]; + if (originalValue.IsValue) + { + return originalValue; + } + else + { + if (attributes == null) attributes = new Dictionary(); + attributes[attributeKey] = originalValue.Override().ToChild(this, attributeKey); + return attributes[attributeKey]; + } + } + + return new SLContainer(null, this, attributeKey); + } + + set + { + // 댕글인경우 + if (dangled) + { + if (parent?.HasChild(id) ?? false) // 다른개체로 교체된 댕글 + { + parent[id][attributeKey] = value; + return; + } + + if (value.IsNullOrFalse()) // 삭제 + { + return; + } + + // 새로 등록 + attributes = new Dictionary(); + + Modified(attributeKey); + attributes[attributeKey] = value.ToChild(this, attributeKey); + + if (parent is null) return; + + parent[id] = this; + } + else + { + if (attributes?.ContainsKey(attributeKey) ?? false) // 키가 있는 경우 + { + if (value.IsNullOrFalse()) // 삭제 + { + { + Modified(attributeKey); + var v = attributes[attributeKey]; + attributes.Remove(attributeKey); + v.ToChild(null, null); + } + + if (removed == null) removed = new HashSet(); + removed.Add(attributeKey); + + if (IsExist() == false) + { + if (parent is null == false) + { + parent[id] = null; + } + } + } + else // 변경 + { + if (value == attributes[attributeKey]) return; + + { + Modified(attributeKey); + var v = attributes[attributeKey]; + attributes.Remove(attributeKey); + v.ToChild(null, null); + } + + attributes[attributeKey] = value.ToChild(this, attributeKey); + } + } + else // 키가 없는경우 + { + if (original?.HasChild(attributeKey) ?? false) // 덮어쓰기 + { + if (value.IsNullOrFalse()) // 삭제추가 + { + if (removed == null) removed = new HashSet(); + Modified(attributeKey); + removed.Add(attributeKey); + + if (IsExist() == false) + { + if (parent is null == false) + { + parent[id] = null; + } + } + } + else // 추가 + { + if (attributes == null) attributes = new Dictionary(); + + if (removed?.Contains(attributeKey) ?? false) + { + removed.Remove(attributeKey); + } + + { + Modified(attributeKey); + attributes[attributeKey] = value.ToChild(this, attributeKey); + } + } + } + else + { + // 추가 + if (value.IsNullOrFalse()) return; + + if (attributes == null) attributes = new Dictionary(); + + Modified(attributeKey); + attributes[attributeKey] = value.ToChild(this, attributeKey); + if (removed != null && removed.Contains(attributeKey)) + { + removed.Remove(attributeKey); + } + } + } + } + } + } + + public override SLEntity Clone() + { + if (dangled) + { + if (parent?.HasChild(id) ?? false) return parent[id].Clone(); + SLLog.Error($"Can't clone dangle object: {id}"); + return false; + } + + var ret = new SLContainer(null, null, null); + + foreach (var child in this) + { + ret[child.ID] = child.Clone(); + } + + return ret; + } + + internal override void Move(SLEntity parent, string newID) + { + if (dangled) + { + if (parent?.HasChild(id) ?? false) this.parent[id].Move(parent, newID); + SLLog.Error($"Can't move dangle object : {id} -> {newID}"); + return; + } + + if (id != null) // 이미 루트가 없다면 + { + var attrTemp = attributes; + this.parent[id] = false; + + attributes = attrTemp; + id = null; + } + + parent[id] = this; + } + + private HashSet modified; + + public override bool IsModified(string child) + { + var ret = false; + ret |= original?.IsModified(child) ?? false; + if (child == null) ret |= (modified?.Count ?? 0) != 0; + else ret |= modified?.Contains(child) ?? false; + + return ret; + } + + public override void EndModified() + { + modified?.Clear(); + } + + private void Modified(string child) + { + if (modified == null) modified = new HashSet(); + modified.Add(child); + } + } + + internal class SLContainerLink : SLContainerBase + { + public bool Unused => id == null; + private SLContainer original; + + public SLContainerLink(SLContainer original) + { + this.original = original; + } + + internal override SLEntity ToChild(SLContainerBase parent, string id) + { + if (id == null && parent is null) // 삭제시 + { + this.parent = null; + this.id = null; + return this; + } + + if (this.parent) return Clone().ToChild(parent, id); + + this.parent = parent; + this.id = id; + return this; + } + + internal void DestroyLink() + { + if (Unused) return; + parent[id] = false; + original = null; + } + + public override bool IsNumeric + { + get + { + SLLog.Error($"this is not value : {id}"); + return false; + } + } + + public override bool IsValue + { + get + { + if (original.IsNullOrFalse()) return true; + return false; + } + } + + internal override bool IsExist() + { + if (original.IsNullOrFalse()) return false; + return true; + } + + public override bool HasChild(string attributeKey) + { + if (original.IsNullOrFalse()) return false; + return original.HasChild(attributeKey); + } + + public override IEnumerator GetEnumerator() + { + if (original.IsNullOrFalse()) return Enumerable.Empty().GetEnumerator(); + return original.GetEnumerator(); + } + + internal override double GetDouble() + { + SLLog.Error($"this is not value : {id}"); + return 0; + } + + internal override int GetInt() + { + SLLog.Error($"this is not value : {id}"); + return 0; + } + + internal override object GetObj() + { + SLLog.Error($"this is not value : {id}"); + return false; + } + + public override SLEntity Link() + { + if (original.IsNullOrFalse()) + { + SLLog.Error($"Destroyed Link, {id}"); + return null; + } + + return original.Link(); + } + + public override SLEntity Override() + { + if (original.IsNullOrFalse()) + { + SLLog.Error($"Destroyed Link, {id}"); + return null; + } + + return original.Override(); + } + + internal override string GetString() + { + if (original.IsNullOrFalse()) return string.Empty; + return $"{id} - {original}"; + } + + public override SLEntity this[string attributeKey] + { + get + { + if (attributeKey == "ID") return ID; + + if (original.IsNullOrFalse()) + { + if (parent?.HasChild(id) ?? false) return parent[id][attributeKey]; + return false; + } + + return original[attributeKey]; + } + + set + { + if (original.IsNullOrFalse()) + { + if (parent?.HasChild(id) ?? false) parent[id][attributeKey] = value; + + // 빈객체에 값을 넣어도 이값을 다시참조할 방법이 없음 + SLLog.Error($"Dangle Link. Can't set new Value : {attributeKey}-{value}"); + return; + } + else + { + original[attributeKey] = value; + } + } + } + + public override SLEntity Clone() + { + if (original.IsNullOrFalse()) + { + SLLog.Error($"Destroyed Link, {id}"); + return null; + } + + return original.Clone(); + } + + internal override void Move(SLEntity parent, string id) + { + if (original.IsNullOrFalse()) + { + SLLog.Error($"Destroyed Link, {id}"); + return; + } + + this.parent[id] = null; + parent[id] = this; + } + + protected override int GetEntityHashCode() + { + if (original.IsNullOrFalse()) + { + SLLog.Error($"Destroyed Link, {id}"); + return 0; + } + + return original.GetHashCode(); + } + + public override bool IsModified(string child) + { + if (original.IsNullOrFalse()) + { + return false; + } + + return original.IsModified(child); + } + + public override void EndModified() + { + if (original.IsNullOrFalse()) + { + return; + } + + original.EndModified(); + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntity/Container.cs.meta b/Packages/SLSystem/SLEntity/Container.cs.meta new file mode 100644 index 000000000..0c0afd71c --- /dev/null +++ b/Packages/SLSystem/SLEntity/Container.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dae3057243a613a4b901c956ca43e60e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntity/SLEntity.cs b/Packages/SLSystem/SLEntity/SLEntity.cs new file mode 100644 index 000000000..990e1698c --- /dev/null +++ b/Packages/SLSystem/SLEntity/SLEntity.cs @@ -0,0 +1,941 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace Superlazy +{ + public abstract class SLEntity : IEnumerable, IComparable + { + public abstract bool IsNumeric { get; } + public abstract bool IsValue { get; } + public abstract string ID { get; } + + public abstract bool IsModified(string child); + + public abstract void EndModified(); + + public abstract bool HasChild(string attributeKey); + + internal abstract object GetObj(); + + internal abstract int GetInt(); + + internal abstract double GetDouble(); + + internal abstract string GetString(); + + internal abstract bool IsExist(); + + protected abstract int GetEntityHashCode(); + + internal static IEnumerable emptyEnumerable = Enumerable.Empty(); + + public abstract IEnumerator GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public SLEntity this[SLEntity attributeKey] + { + get + { + if (attributeKey.IsNullOrFalse()) + { + SLLog.Warn($"attributeKey shouldn't null obj {ToString()}, {ID}"); +#if SERVER && LOCALTEST + throw new Exception(); +#endif + return Empty; + } + + return this[attributeKey.ToString()]; + } + set + { + if (attributeKey.IsNullOrFalse()) + { + SLLog.Warn($"attributeKey shouldn't null obj {ToString()}, {ID}"); +#if SERVER && LOCALTEST + throw new Exception(); +#endif + return; + } + + this[attributeKey.ToString()] = value; + } + } + + public abstract SLEntity this[string attributeKey] + { + get; + set; + } + + public abstract SLEntity Clone(); + + public abstract SLEntity Link(); + + public abstract SLEntity Override(); + + public static SLEntity Empty => new SLContainer(null, null, null); + + public static implicit operator double(SLEntity v) + { + return v.GetDouble(); + } + + public static implicit operator float(SLEntity v) + { + return (float)v.GetDouble(); + } + + public static implicit operator int(SLEntity v) + { + return v.GetInt(); + } + + public static implicit operator string(SLEntity v) + { + return v.GetString(); + } + + public static implicit operator bool(SLEntity v) + { + return v != default(SLEntity) && v.IsExist(); + } + + //public static implicit operator Vector2(SLEntity v) + //{ + // return new Vector2(v["X"], v["Y"]); + //} + + public static bool operator <(SLEntity lhs, SLEntity rhs) + { + if (lhs == null && rhs == null) + { + return 0 < 0; + } + else if (lhs.IsNullOrFalse()) + { + return 0 < rhs.GetDouble(); + } + else if (rhs.IsNullOrFalse()) + { + return lhs.GetDouble() < 0; + } + else + { + return lhs.GetDouble() < rhs.GetDouble(); + } + } + + public static bool operator >(SLEntity lhs, SLEntity rhs) + { + if (lhs == null && rhs == null) + { + return 0 > 0; + } + else if (lhs.IsNullOrFalse()) + { + return 0 > rhs.GetDouble(); + } + else if (rhs.IsNullOrFalse()) + { + return lhs.GetDouble() > 0; + } + + return lhs.GetDouble() > rhs.GetDouble(); + } + + public static bool operator <=(SLEntity lhs, SLEntity rhs) + { + if (lhs == null && rhs == null) + { + return 0 <= 0; + } + else if (lhs.IsNullOrFalse()) + { + return 0 <= rhs.GetDouble(); + } + else if (rhs.IsNullOrFalse()) + { + return lhs.GetDouble() <= 0; + } + else + { + return lhs.GetDouble() <= rhs.GetDouble(); + } + } + + public static bool operator >=(SLEntity lhs, SLEntity rhs) + { + if (lhs == null && rhs == null) + { + return 0 >= 0; + } + else if (lhs.IsNullOrFalse()) + { + return 0 >= rhs.GetDouble(); + } + else if (rhs.IsNullOrFalse()) + { + return lhs.GetDouble() >= 0; + } + else + { + return lhs.GetDouble() >= rhs.GetDouble(); + } + } + + public static SLEntity operator +(SLEntity single) + { + return single; + } + + public static SLEntity operator -(SLEntity single) + { + if (single.IsNullOrFalse()) + { + return 0; + } + + return -single.GetDouble(); + } + + public static SLEntity operator +(SLEntity lhs, SLEntity rhs) + { + if (lhs.IsNullOrFalse()) + { + return rhs; + } + + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + if (lhs.IsNumeric && rhs.IsNumeric) + return lhs.GetDouble() + rhs.GetDouble(); + + return lhs.ToString() + rhs.ToString(); + } + + public static double operator +(double lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + if (rhs.IsNumeric) + return lhs + rhs.GetDouble(); + + return lhs; + } + + public static double operator +(SLEntity lhs, double rhs) + { + if (lhs.IsNullOrFalse()) + { + return rhs; + } + + if (lhs.IsNumeric) + return lhs.GetDouble() + rhs; + + return rhs; + } + + public static float operator +(float lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + if (rhs.IsNumeric) + return lhs + (float)rhs.GetDouble(); + + return lhs; + } + + public static float operator +(SLEntity lhs, float rhs) + { + if (lhs.IsNullOrFalse()) + { + return rhs; + } + + if (lhs.IsNumeric) + return (float)lhs.GetDouble() + rhs; + + return rhs; + } + + public static int operator +(SLEntity lhs, int rhs) + { + if (lhs.IsNullOrFalse()) + { + return rhs; + } + + if (lhs.IsNumeric) + return lhs.GetInt() + rhs; + + return rhs; + } + + public static int operator +(int lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + if (rhs.IsNumeric) + return lhs + rhs.GetInt(); + + return lhs; + } + + public static SLEntity operator -(SLEntity lhs, SLEntity rhs) + { + if (lhs.IsNullOrFalse()) + { + if (rhs == default(SLEntity)) return 0; + return -rhs.GetDouble(); + } + + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + return lhs.GetDouble() - rhs.GetDouble(); + } + + public static double operator -(double lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + if (rhs.IsNumeric) + return lhs - rhs.GetDouble(); + + return lhs; + } + + public static double operator -(SLEntity lhs, double rhs) + { + if (lhs.IsNullOrFalse()) + { + return -rhs; + } + + if (lhs.IsNumeric) + return lhs.GetDouble() - rhs; + + return -rhs; + } + + public static float operator -(float lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + if (rhs.IsNumeric) + return lhs - (float)rhs.GetDouble(); + + return lhs; + } + + public static float operator -(SLEntity lhs, float rhs) + { + if (lhs.IsNullOrFalse()) + { + return -rhs; + } + + if (lhs.IsNumeric) + return (float)lhs.GetDouble() - rhs; + + return -rhs; + } + + public static int operator -(SLEntity lhs, int rhs) + { + if (lhs.IsNullOrFalse()) + { + return -rhs; + } + + if (lhs.IsNumeric) + return lhs.GetInt() - rhs; + + return rhs; + } + + public static int operator -(int lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return lhs; + } + + if (rhs.IsNumeric) + return lhs - rhs.GetInt(); + + return lhs; + } + + public static SLEntity operator *(SLEntity lhs, SLEntity rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs.IsNullOrFalse()) + { + return 0; + } + + if (lhs.IsNumeric && rhs.IsNumeric) + return lhs.GetDouble() * rhs.GetDouble(); + + return 0; + } + + public static double operator *(double lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs.IsNumeric) + return lhs * rhs.GetDouble(); + + return 0; + } + + public static double operator *(SLEntity lhs, double rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (lhs.IsNumeric) + return lhs.GetDouble() * rhs; + + return 0; + } + + public static float operator *(float lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs.IsNumeric) + return lhs * (float)rhs.GetDouble(); + + return 0; + } + + public static float operator *(SLEntity lhs, float rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (lhs.IsNumeric) + return (float)lhs.GetDouble() * rhs; + + return 0; + } + + public static int operator *(SLEntity lhs, int rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (lhs.IsNumeric) + return lhs.GetInt() * rhs; + + return 0; + } + + public static int operator *(int lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs.IsNumeric) + return lhs * rhs.GetInt(); + + return 0; + } + + public static SLEntity operator /(SLEntity lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + SLLog.Warn($"Divide by 0 {lhs?.GetDouble() ?? 0} / 0"); + + if (lhs.IsNullOrFalse()) return 0; + else return Math.Sign(lhs.GetDouble()) * double.PositiveInfinity; + } + + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs.IsNumeric == false || rhs == 0.0) + { + SLLog.Warn($"Divide by 0 {lhs.GetDouble()} / 0"); + return Math.Sign(lhs.GetDouble()) * double.PositiveInfinity; + } + + return lhs.GetDouble() / rhs.GetDouble(); + } + + public static double operator /(double lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return Math.Sign(lhs) * double.PositiveInfinity; + } + + if (rhs.IsNumeric == false || rhs == 0.0) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return Math.Sign(lhs) * double.PositiveInfinity; + } + + return lhs / rhs.GetDouble(); + } + + public static double operator /(SLEntity lhs, double rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs == 0.0) + { + SLLog.Warn($"Divide by 0 {lhs.GetDouble()} / 0"); + return Math.Sign(lhs.GetDouble()) * double.PositiveInfinity; + } + + return lhs.GetDouble() / rhs; + } + + public static float operator /(float lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return Math.Sign(lhs) * float.PositiveInfinity; + } + + if (rhs.IsNumeric == false || rhs == 0.0) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return Math.Sign(lhs) * float.PositiveInfinity; + } + + return lhs / (float)rhs.GetDouble(); + } + + public static float operator /(SLEntity lhs, float rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs == 0.0) + { + SLLog.Warn($"Divide by 0 {lhs.GetDouble()} / 0"); + return Math.Sign(lhs.GetDouble()) * float.PositiveInfinity; + } + + return (float)lhs.GetDouble() / rhs; + } + + public static int operator /(int lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return lhs > 0 ? int.MaxValue : int.MinValue; + } + + if (rhs.IsNumeric == false || rhs == 0.0) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return lhs > 0 ? int.MaxValue : int.MinValue; + } + + return lhs / rhs.GetInt(); + } + + public static int operator /(SLEntity lhs, int rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs == 0) + { + SLLog.Warn($"Divide by 0 {lhs.GetInt()} / 0"); + return lhs.GetInt() > 0 ? int.MaxValue : int.MinValue; + } + + return lhs.GetInt() / rhs; + } + + public static int operator %(SLEntity lhs, SLEntity rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs.IsNullOrFalse()) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return lhs; + } + + return lhs.GetInt() % rhs.GetInt(); + } + + public static int operator %(SLEntity lhs, int rhs) + { + if (lhs.IsNullOrFalse()) + { + return 0; + } + + if (rhs == 0) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return lhs; + } + + return lhs.GetInt() % rhs; + } + + public static int operator %(int lhs, SLEntity rhs) + { + if (lhs == 0) + { + return 0; + } + + if (rhs.IsNullOrFalse() || rhs.GetInt() == 0) + { + SLLog.Warn($"Divide by 0 {lhs} / 0"); + return lhs; + } + + return lhs % rhs.GetInt(); + } + + public static bool operator ==(SLEntity lhs, bool rhs) + { + if (lhs.IsNullOrFalse()) return !rhs; + else return lhs.IsExist() == rhs; + } + + public static bool operator !=(SLEntity lhs, bool rhs) + { + return !(lhs == rhs); + } + + public static bool operator ==(bool lhs, SLEntity rhs) + { + if (rhs.IsNullOrFalse()) return !lhs; + else return rhs.IsExist() == rhs; + } + + public static bool operator !=(bool lhs, SLEntity rhs) + { + return !(rhs == lhs); + } + + //public static bool operator ==(SLEntity lhs, string rhs) + //{ + // return (string)lhs == rhs; + //} + + //public static bool operator !=(SLEntity lhs, string rhs) + //{ + // return !(lhs == rhs); + //} + + //public static bool operator ==(string lhs, SLEntity rhs) + //{ + // return rhs == lhs; + //} + + //public static bool operator !=(string lhs, SLEntity rhs) + //{ + // return !(rhs == lhs); + //} + + public static bool operator ==(SLEntity lhs, int rhs) + { + return lhs.GetInt() == rhs; + } + + public static bool operator !=(SLEntity lhs, int rhs) + { + return !(lhs == rhs); + } + + public static bool operator ==(int lhs, SLEntity rhs) + { + return rhs == lhs; + } + + public static bool operator !=(int lhs, SLEntity rhs) + { + return !(rhs == lhs); + } + + public static bool operator ==(SLEntity lhs, double rhs) + { + return lhs.GetDouble() == rhs; + } + + public static bool operator !=(SLEntity lhs, double rhs) + { + return !(lhs == rhs); + } + + public static bool operator ==(double lhs, SLEntity rhs) + { + return rhs == lhs; + } + + public static bool operator !=(double lhs, SLEntity rhs) + { + return !(rhs == lhs); + } + + public static bool operator ==(SLEntity lhs, float rhs) + { + return lhs.GetDouble() == rhs; + } + + public static bool operator !=(SLEntity lhs, float rhs) + { + return !(lhs == rhs); + } + + public static bool operator ==(float lhs, SLEntity rhs) + { + return rhs == lhs; + } + + public static bool operator !=(float lhs, SLEntity rhs) + { + return !(rhs == lhs); + } + + //public static bool operator ==(SLEntity lhs, SLVector2 rhs) + //{ + // return lhs["X"] == rhs.X && lhs["Y"] == rhs.Y; + //} + + //public static bool operator !=(SLEntity lhs, SLVector2 rhs) + //{ + // return lhs["X"] != rhs.X || lhs["Y"] != rhs.Y; + //} + + public static bool operator ==(SLEntity lhs, SLEntity rhs) + { + if (ReferenceEquals(lhs, rhs))// 동일 객체 + { + return true; + } + else if (lhs is null || lhs.IsExist() == false) // 빈객체 + { + return rhs is null || rhs.IsExist() == false; + } + else if (rhs is null || rhs.IsExist() == false) + { + return lhs is null || lhs.IsExist() == false; + } + else if (lhs.IsValue && rhs.IsValue) // 값비교 + { + if (lhs.IsNumeric == false || rhs.IsNumeric == false) + { + return lhs.GetString().Equals(rhs.GetString()); + } + else + { + return lhs.GetDouble() == rhs.GetDouble(); + } + } + else if (lhs.IsValue == false && rhs.IsValue == false) // 리스트 + { + var lhsCount = lhs.Count(); + var rhsCount = rhs.Count(); + + if (lhsCount != rhsCount) + { + return false; + } + + foreach (var l in lhs) + { + if (rhs.HasChild(l.ID) == false) + { + return false; + } + + if (l != rhs[l.ID]) + { + return false; + } + } + + return true; + } + + return false; + } + + public static bool operator !=(SLEntity lhs, SLEntity rhs) + { + return !(lhs == rhs); + } + + public override bool Equals(object obj) + { + if (obj == null) + { + return false; + } + + if ((obj is SLEntity) == false) + { + return obj.Equals(GetObj()); + } + + return (obj as SLEntity) == this; + } + + public override int GetHashCode() + { + return GetEntityHashCode(); + } + + public static implicit operator SLEntity(string v) + { + if (v == null || v == string.Empty) return Empty; + else return new SLValueString(v); + } + + public static implicit operator SLEntity(int v) + { + return new SLValueInt(v); + } + + public static implicit operator SLEntity(double v) + { + return new SLValueDouble(v); + } + + private static SLEntity boolTrue = new SLValueString("True"); + //private static SLEntity boolFalse = new SLContainer(null, null, null); + + public static implicit operator SLEntity(bool v) + { + if (v) + { + if (boolTrue.ID != null) boolTrue = new SLValueString("True"); + return boolTrue; + } + else + { + return new SLContainer(null, null, null); // TODO: 성능상 수정 필요 + //if (boolFalse || boolFalse.ID != null) boolFalse = new SLContainer(null, null, null); + //boolFalse.test = true; + //return boolFalse; + } + } + + //public static implicit operator SLEntity(SLVector2 v) + //{ + // var ret = new SLContainer(null); + // ret["X"] = v.X; + // ret["Y"] = v.Y; + // return ret; + //} + + public override string ToString() + { + return GetString(); + } + + public int CompareTo(SLEntity other) + { + if (IsValue == false || other.IsValue == false) + { + // TODO: 리스트 비교 필요 + return GetHashCode().CompareTo(other.GetHashCode()); + } + + if (IsNumeric && other.IsNumeric) + { + return GetDouble().CompareTo(other.GetDouble()); + } + + var thisSTR = GetString(); + var otherSTR = other.GetString(); + return thisSTR.CompareTo(otherSTR); + } + + internal abstract SLEntity ToChild(SLContainerBase parent, string id); + + internal abstract void Move(SLEntity parent, string id); + + public static bool Changed(SLEntity lhs, SLEntity rhs) + { + if (lhs is null && rhs is null) return false; + + if (lhs.IsNullOrFalse()) return rhs; + if (rhs.IsNullOrFalse()) return lhs; + + if (lhs.IsValue && rhs.IsValue) + { + return lhs != rhs; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntity/SLEntity.cs.meta b/Packages/SLSystem/SLEntity/SLEntity.cs.meta new file mode 100644 index 000000000..f2463d6a3 --- /dev/null +++ b/Packages/SLSystem/SLEntity/SLEntity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5bdef6b90662bde4696cc01d0ac24899 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntity/Utility.cs b/Packages/SLSystem/SLEntity/Utility.cs new file mode 100644 index 000000000..71b375103 --- /dev/null +++ b/Packages/SLSystem/SLEntity/Utility.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Superlazy +{ + public static class Utility + { + public static bool IsNullOrFalse(this SLEntity entity) + { + return entity == null || entity.IsExist() == false; + } + + public static string CombinePath(this string first, string add) + { + if (first == null || first == string.Empty) + { + return add; + } + else if (add == null || add == string.Empty) + { + return first; + } + else + { + return new StringBuilder().Append(first).Append('.').Append(add).ToString(); + } + } + + public static void RemoveIf(this SLEntity entity, Func onRemove) + { + var removes = new List(); + foreach (var e in entity) + { + if (onRemove(e)) removes.Add(e.ID); + } + + foreach (var r in removes) + { + entity[r] = false; + } + } + + public static bool Contains(this SLEntity entity, string value) + { + return entity.ToString().Contains(value); + } + + public static SLEntity Get(this SLEntity entity, string path) + { + if (entity == null) return false; + var list = entity; + + var oldIdx = 0; + var idx = path.IndexOf('.'); + var len = path.Length; + while (idx != -1 && oldIdx < len) + { + { + var sub = path.Substring(oldIdx, idx - oldIdx); + if (string.IsNullOrEmpty(sub) == false) + list = list[sub]; + } + + oldIdx = idx + 1; + if (idx + 1 >= path.Length) + { + idx = -1; + } + else + { + idx = path.IndexOf('.', idx + 1); + } + } + + if (oldIdx < len) + { + var sub = path.Substring(oldIdx); + if (string.IsNullOrEmpty(sub) == false) + list = list[sub]; + } + + return list; + } + + public static void Set(this SLEntity entity, string path, SLEntity value) + { + var list = entity; + var oldIdx = 0; + var idx = path.IndexOf('.'); + var len = path.Length; + + if (idx == -1) + { + list[path] = value; + return; + } + + while (idx != -1 && oldIdx < len) + { + { + var sub = path.Substring(oldIdx, idx - oldIdx); + if (string.IsNullOrEmpty(sub) == false) + list = list[sub]; + } + + oldIdx = idx + 1; + if (idx + 1 >= path.Length) + { + idx = -1; + } + else + { + idx = path.IndexOf('.', idx + 1); + } + } + + if (oldIdx < len) + { + var sub = path.Substring(oldIdx); + if (string.IsNullOrEmpty(sub) == false) + { + list[sub] = value; + } + else + { + SLLog.Error($"Set Can't end with . : {path}"); + } + } + } + + public static bool IsLeft(this SLEntity entity, string value) + { + return entity.ToString().IsLeft(value); + } + + public static bool IsLeft(this string str, string value) + { + if (str.Length >= value.Length) + { + for (var i = 0; i < value.Length; i++) + { + if (str[i] != value[i]) + return false; + } + + return true; + } + + return false; + } + + public static bool IsRight(this SLEntity entity, string value) + { + return entity.ToString().IsRight(value); + } + + public static bool IsRight(this string str, string value) + { + if (str.Length >= value.Length) + { + for (var i = 1; i <= value.Length; ++i) + { + if (str[str.Length - i] != value[value.Length - i]) + return false; + } + + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntity/Utility.cs.meta b/Packages/SLSystem/SLEntity/Utility.cs.meta new file mode 100644 index 000000000..58c3cd4fc --- /dev/null +++ b/Packages/SLSystem/SLEntity/Utility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f3af70c1c51ef34aaca98e9b7dd64ab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntity/Values.cs b/Packages/SLSystem/SLEntity/Values.cs new file mode 100644 index 000000000..02822eb14 --- /dev/null +++ b/Packages/SLSystem/SLEntity/Values.cs @@ -0,0 +1,214 @@ +using System.Collections.Generic; + +namespace Superlazy +{ + internal abstract class SLValue : SLEntity + { + public override bool IsValue => true; + protected string id; + public override string ID => id; + + public override SLEntity Link() + { + SLLog.Error($"Value can't be link {id}: {GetString()}"); + return false; + } + + public override SLEntity Override() + { + SLLog.Error($"Value can't be override {id}: {GetString()}"); + return false; + } + + internal override bool IsExist() + { + return true; + } + + public override bool HasChild(string attributeKey) + { + if (attributeKey == "ID") return true; + + SLLog.Error($"Can't get Child in Value {id}: {GetObj()}"); + return false; + } + + public override IEnumerator GetEnumerator() + { + SLLog.Error($"Can't get Enumerator in Value {id}: {GetObj()}"); + yield break; + } + + public override SLEntity this[string attributeKey] + { + get + { + if (attributeKey == "ID") return ID; + + SLLog.Error($"Can't get attribute in Value {id}: {GetObj()}"); + return false; + } + + set => SLLog.Error($"Can't set attribute in Value : {GetObj()}"); + } + + internal override SLEntity ToChild(SLContainerBase parent, string id) + { + if (this.id != null) + { + return Clone().ToChild(parent, id); + } + + this.id = id; + return this; + } + + internal override void Move(SLEntity parent, string id) + { + this.id = id; + parent[id] = this; + } + + //public override SLEntity Clone() + //{ + // return this; + //} + + public override bool IsModified(string child) + { + return false; + } + + public override void EndModified() + { + } + } + + internal class SLValueDouble : SLValue + { + private readonly double value; + + public SLValueDouble(double value) + { + this.value = value; + } + + public override bool IsNumeric => true; + + internal override double GetDouble() + { + return value; + } + + internal override int GetInt() + { + return (int)value; + } + + internal override object GetObj() + { + return value; + } + + protected override int GetEntityHashCode() + { + return value.GetHashCode(); + } + + internal override string GetString() + { + return value.ToString(); + } + + public override SLEntity Clone() + { + return new SLValueDouble(value); + } + } + + internal class SLValueInt : SLValue + { + private readonly int value; + + public SLValueInt(int value) + { + this.value = value; + } + + public override bool IsNumeric => true; + + internal override double GetDouble() + { + return value; + } + + internal override int GetInt() + { + return value; + } + + internal override object GetObj() + { + return value; + } + + protected override int GetEntityHashCode() + { + return value.GetHashCode(); + } + + internal override string GetString() + { + return value.ToString(); + } + + public override SLEntity Clone() + { + return new SLValueInt(value); + } + } + + internal class SLValueString : SLValue + { + private readonly string value; + + public SLValueString(string value) + { + this.value = value; + } + + public override bool IsNumeric => false; + + internal override double GetDouble() + { + SLLog.Warn($"String is not number {ID}:{GetString()}"); + return 0; + } + + internal override int GetInt() + { + SLLog.Warn($"String is not number {ID}:{GetString()}"); + return 0; + } + + internal override object GetObj() + { + return value; + } + + protected override int GetEntityHashCode() + { + return value.GetHashCode(); + } + + internal override string GetString() + { + return value; + } + + public override SLEntity Clone() + { + return new SLValueString(value); + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntity/Values.cs.meta b/Packages/SLSystem/SLEntity/Values.cs.meta new file mode 100644 index 000000000..77a4f46d4 --- /dev/null +++ b/Packages/SLSystem/SLEntity/Values.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7693ce3a928c5f34e91b146b25143394 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntitySpace.meta b/Packages/SLSystem/SLEntitySpace.meta new file mode 100644 index 000000000..e73fdade6 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5ff8197c3c3246f40aac024382d634fe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntitySpace/Loader.meta b/Packages/SLSystem/SLEntitySpace/Loader.meta new file mode 100644 index 000000000..c3c9f9a46 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/Loader.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 62e4bd6c3eb89044f82f7ecdb26d960f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntitySpace/Loader/JsonLoader.cs b/Packages/SLSystem/SLEntitySpace/Loader/JsonLoader.cs new file mode 100644 index 000000000..25522c74c --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/Loader/JsonLoader.cs @@ -0,0 +1,476 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Superlazy.Loader +{ + public static class JsonLoader + { + private static void ParseElement(SLEntity context, string token, string tokenName, bool quoted) + { + if (context.HasChild(tokenName)) + { + throw new Exception($"{tokenName} Already has child"); + } + + if (quoted) + { + context[tokenName] = token; + return; + } + + { + if (double.TryParse(token, out var val)) + { + if (val < 1 || val > int.MaxValue || (token.IsRight(".0") == false && token.Contains('.'))) + { + context[tokenName] = val; + } + else + { + context[tokenName] = (int)val; + } + } + else + { + context[tokenName] = token; + } + } + } + + public static SLEntity Parse(SLEntity root, string aJSON) + { + var stack = new Stack(); + SLEntity context = null; + var i = 0; + var Token = new StringBuilder(); + var TokenName = ""; + var QuoteMode = false; + var TokenIsQuoted = false; + while (i < aJSON.Length) + { + switch (aJSON[i]) + { + case '{': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + + if (context is null) + { + stack.Push(root); + } + else + { + stack.Push(context[TokenName]); + } + + TokenName = ""; + Token.Length = 0; + context = stack.Peek(); + break; + + case '[': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + + stack.Push(SLEntity.Empty); + if (context != null) + { + context[TokenName] = stack.Peek(); + } + + TokenName = ""; + Token.Length = 0; + context = stack.Peek(); + break; + + case '}': + case ']': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + + if (stack.Count == 0) + throw new Exception("JSON Parse: Too many closing brackets\n" + aJSON); + + stack.Peek().EndModified(); + stack.Pop(); + if (Token.Length > 0 || TokenIsQuoted) + { + ParseElement(context, Token.ToString(), TokenName, TokenIsQuoted); + TokenIsQuoted = false; + } + + TokenName = ""; + Token.Length = 0; + if (stack.Count > 0) + context = stack.Peek(); + break; + + case ':': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + + TokenName = Token.ToString(); + Token.Length = 0; + TokenIsQuoted = false; + break; + + case '"': + QuoteMode ^= true; + TokenIsQuoted |= QuoteMode; + break; + + case ',': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + + if (Token.Length > 0 || TokenIsQuoted) + { + ParseElement(context, Token.ToString(), TokenName, TokenIsQuoted); + } + + TokenName = ""; + Token.Length = 0; + TokenIsQuoted = false; + break; + + case '\r': + case '\n': + break; + + case ' ': + case '\t': + if (QuoteMode) + Token.Append(aJSON[i]); + break; + + case '\\': + ++i; + if (QuoteMode) + { + var C = aJSON[i]; + switch (C) + { + case 't': + Token.Append('\t'); + break; + + case 'r': + Token.Append('\r'); + break; + + case 'n': + Token.Append('\n'); + break; + + case 'b': + Token.Append('\b'); + break; + + case 'f': + Token.Append('\f'); + break; + + case 'u': + { + var s = aJSON.Substring(i + 1, 4); + Token.Append((char)int.Parse( + s, + System.Globalization.NumberStyles.AllowHexSpecifier)); + i += 4; + break; + } + + default: + Token.Append(C); + break; + } + } + + break; + + default: + Token.Append(aJSON[i]); + break; + } + + ++i; + } + + if (QuoteMode) + { + throw new Exception("JSON Parse: Quotation marks seems to be messed up.\n" + aJSON); + } + + return context; + } + + public static SLEntity LoadJson(string v) + { + var obj = Parse(SLEntity.Empty, v); + return obj; + } + + public static SLEntity LoadJson(SLEntity root, string v) + { + var obj = Parse(root, v); + return obj; + } + + public static string SaveToJson(SLEntity entity, int sortDepth = -1, bool indent = false) + { + if (indent) + { + var collection = SaveObj(null, entity, new StringBuilder(1024 * 1024 * 5), 0, sortDepth); + return collection.ToString(); + } + else + { + var collection = SaveObjNoIndent(null, entity, new StringBuilder(1024 * 1024 * 5), 0, sortDepth); + return collection.ToString(); + } + } + + private static StringBuilder SaveObj(string id, SLEntity entity, StringBuilder builder, int depth, int sortDepth = -1) + { + if (depth > 0) builder.Append(' ', depth); + + if (entity.IsValue) + { + if (entity.IsNumeric) + { + builder.Append('\"').Append(id).Append("\": ").Append(RoundAndFormat(entity)); + } + else + { + builder.Append('\"').Append(id).Append("\": \""); + foreach (var ch in entity.ToString()) + { + if (ch == '"') + { + builder.Append("\\\""); + } + else if (ch == '\n') + { + builder.Append("\\n"); + } + else + { + builder.Append(ch); + } + } + + builder.Append("\""); + } + } + else + { + if (depth != 0) + { + builder.Append('\"').Append(id).Append("\": {\r\n"); + } + else + { + builder.Append("{\r\n"); + } + + if (sortDepth != -1 && depth > sortDepth) + { + var count = entity.Count(); + foreach (var child in entity.OrderBy(u => + { + if (int.TryParse(u.ID, out var numberID)) + { + return string.Format("{0}{1:0000}", u.IsValue ? 0 : 1, numberID); + } + + return string.Format("{0}{1}", u.IsValue ? 0 : 1, u.ID); + })) + { + SaveObj(child.ID, child, builder, depth + 2, sortDepth); + count -= 1; + + if (count > 0) + { + builder.Append(",\r\n"); + } + else + { + builder.Append("\r\n"); + } + } + } + else + { + var count = entity.Count(); + foreach (var child in entity) + { + SaveObj(child.ID, child, builder, depth + 2, sortDepth); + count -= 1; + + if (count > 0) + { + builder.Append(",\r\n"); + } + else + { + builder.Append("\r\n"); + } + } + } + + if (depth > 0) builder.Append(' ', depth); + builder.Append('}'); + } + + return builder; + } + + private static StringBuilder SaveObjNoIndent(string id, SLEntity entity, StringBuilder builder, int depth, int sortDepth = -1) + { + if (entity.IsValue) + { + if (entity.IsNumeric) + { + //builder.Append('\"').Append(id).Append("\":").Append(RoundAndFormat(entity)); // 인덴트가 없다는건 데이터 전송용이므로 빠르게 진행 + builder.Append('\"').Append(id).Append("\":").Append(entity.ToString()); + } + else + { + builder.Append('\"').Append(id).Append("\":\""); + foreach (var ch in entity.ToString()) + { + if (ch == '"') + { + builder.Append("\\\""); + } + else if (ch == '\n') + { + builder.Append("\\n"); + } + else + { + builder.Append(ch); + } + } + + builder.Append("\""); + } + } + else + { + if (depth != 0) + { + builder.Append('\"').Append(id).Append("\":{"); + } + else + { + builder.Append("{"); + } + + if (sortDepth != -1 && depth > sortDepth) + { + var count = entity.Count(); + foreach (var child in entity.OrderBy(u => + { + if (int.TryParse(u.ID, out var numberID)) + { + return string.Format("{0}{1:0000}", u.IsValue ? 0 : 1, numberID); + } + + return string.Format("{0}{1}", u.IsValue ? 0 : 1, u.ID); + })) + { + SaveObjNoIndent(child.ID, child, builder, depth + 2, sortDepth); + count -= 1; + + if (count > 0) + { + builder.Append(","); + } + } + } + else + { + var count = entity.Count(); + foreach (var child in entity) + { + SaveObjNoIndent(child.ID, child, builder, depth + 2, sortDepth); + count -= 1; + + if (count > 0) + { + builder.Append(","); + } + } + } + + builder.Append('}'); + } + + return builder; + } + + public static string RoundAndFormat(SLEntity num) + { + var str = num.ToString(); + var decimalIndex = str.IndexOf('.'); + if (decimalIndex >= 0) + { + // 2자리까지 반올림 대상으로 한다 + var roundIndex = str.Length - 2; + if (str[roundIndex] != '9' && str[roundIndex] != '0') + { + roundIndex = str.Length - 3; + } + + var nine = false; + if (str[roundIndex] == '9') nine = true; + while (roundIndex > decimalIndex && ((nine && str[roundIndex] == '9') || (nine == false && str[roundIndex] == '0'))) + { + roundIndex--; + } + + if (str.Length > decimalIndex + 6 && roundIndex <= decimalIndex) + { + // 반올림정수 + return ((int)Math.Round((double)num)).ToString(); + } + + if (str.Length < decimalIndex + 6) + { + return str; // 단순한 소수 + } + + if (roundIndex < str.Length - 6) // 3~4자리 이상 반복 + { + return string.Format("{0:f" + (roundIndex - decimalIndex) + "}", (double)num); + } + else + { + return str; // 복잡한 소수 + } + } + else + { + return str; // 정수 + } + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntitySpace/Loader/JsonLoader.cs.meta b/Packages/SLSystem/SLEntitySpace/Loader/JsonLoader.cs.meta new file mode 100644 index 000000000..f20a6b3fa --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/Loader/JsonLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8dd9a7675f6c7a74b946b262207c0d18 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntitySpace/Loader/XMLLoader.cs b/Packages/SLSystem/SLEntitySpace/Loader/XMLLoader.cs new file mode 100644 index 000000000..193beaee4 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/Loader/XMLLoader.cs @@ -0,0 +1,31 @@ +using System; +using Superlazy; + +namespace SLShared.Entity.Loader +{ + public static class XMLLoader + { + internal static SLEntity LoadFile(string v) + { + //XmlDocument xmldoc = new XmlDocument(); + //xmldoc.LoadXml(xml.text); + //XmlDocument doc = new XmlDocument(); + //doc.Load(dataFolder + fileName); + //string type = doc.DocumentElement.GetAttribute("Name"); + + //if (xmls.ContainsKey(type) == false) + //{ + // xmls[type] = new List(); + //} + //var set = new XMLSet(); + //int dirIdx = doc.BaseURI.IndexOf(dataFolderName) + dataFolderName.Length; + //var file = doc.BaseURI.Substring(dirIdx, doc.BaseURI.Length - dirIdx - ".xml".Length); + + //set.doc = doc; + //set.filePath = file; + //xmls[type].Add(set); + + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntitySpace/Loader/XMLLoader.cs.meta b/Packages/SLSystem/SLEntitySpace/Loader/XMLLoader.cs.meta new file mode 100644 index 000000000..35c2d7df3 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/Loader/XMLLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 787bd37fed2046c4b8983331d51a8eeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntitySpace/Loader/YamlLoader.cs b/Packages/SLSystem/SLEntitySpace/Loader/YamlLoader.cs new file mode 100644 index 000000000..6af8c19b6 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/Loader/YamlLoader.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Superlazy.Loader +{ + public static class YamlLoader + { + public static SLEntity LoadYaml(string yamlString) + { + var root = SLEntity.Empty; + LoadYaml(root, yamlString); + return root; + } + + public static void LoadYaml(SLEntity root, string yamlString) + { + var currentEntity = root; + var stack = new Stack>(); + + using var reader = new StringReader(yamlString); + string line; + while ((line = reader.ReadLine()) != null) + { + var lineBegin = 0; + while (lineBegin < line.Length && line[lineBegin] == ' ') lineBegin++; + + if (line.Length <= lineBegin) continue; + + var separatorIndex = line.IndexOf(':'); + string key; + var isArray = false; + if (separatorIndex == -1) + { + if (line[lineBegin] == '#') + { + continue; + } + else if (line[lineBegin] == '-') + { + isArray = true;// 배열 전용 처리 + key = null; + separatorIndex = lineBegin; + } + else + { + continue; + } + } + else + { + var commentIndex = line.IndexOf('#'); + if (commentIndex >= 0 && commentIndex <= separatorIndex) // 키에는 주석을 넣을수 없기 때문에 구분자 이전은 주석 + { + continue; // 전체 주석 + } + else + { + key = line.Substring(lineBegin, separatorIndex - lineBegin); + } + } + + var valueBegin = separatorIndex + 2; + var valueEnd = line.Length; + + if (valueBegin + 1 < valueEnd) + { + var commentIndex = line.IndexOf('#', valueBegin, valueEnd - valueBegin); + // TODO: 문자열 내의 #은 인식 못하도록 현재가 문자열 내부인지 체크가 필요 + if (commentIndex >= 0 && (commentIndex == 0 || line[commentIndex - 1] == ' ')) // 빈칸이 하나 있어야 주석임 + { + valueEnd = commentIndex - 1; + } + + while (valueEnd > valueBegin && line[valueBegin] == ' ') + { + valueBegin++; + } + + while (valueEnd >= valueBegin && line[valueEnd - 1] == ' ') + { + valueEnd--; + } + } + + while (stack.Count > 0 && lineBegin <= stack.Peek().Item2) + { + currentEntity.EndModified(); + currentEntity = stack.Pop().Item1; + } + + if (isArray) + { + key = (currentEntity.Count() + 1).ToString(); + } + + if (valueBegin >= valueEnd) + { + stack.Push(new Tuple(currentEntity, lineBegin)); + currentEntity = currentEntity[key]; + } + else + { + var forceString = false; + + if (line[valueBegin] == '"' && line[valueEnd - 1] == '"' || line[valueBegin] == '\'' && line[valueEnd - 1] == '\'') + { + valueBegin += 1; + valueEnd -= 1; + forceString = true; + } + + var value = line.Substring(valueBegin, valueEnd - valueBegin); + + if (forceString) + { + currentEntity[key] = value; + } + else if (int.TryParse(value, out var intValue)) + { + currentEntity[key] = intValue; + } + else if (double.TryParse(value, out var doubleValue)) + { + currentEntity[key] = doubleValue; + } + else + { + currentEntity[key] = value; + } + } + } + + while (stack.Count > 0) + { + currentEntity.EndModified(); + currentEntity = stack.Pop().Item1; + } + } + + public static string SaveToYaml(SLEntity entity, int indentation = 0, bool useArray = false) + { + var yamlString = new StringBuilder(); + + var index = 1; + + IEnumerable childs = entity; + if (useArray && entity.All(x => int.TryParse(x.ID, out _))) + { + childs = entity.OrderBy(x => int.Parse(x.ID)); + } + else // 전부 int로 파싱 못하면, 배열로 처리하지 않음 + { + useArray = false; + } + + foreach (var child in childs) + { + var key = child.ID; + var value = child; + + if (useArray && index > 0 && key == index.ToString()) + { + key = "-"; + ++index; + yamlString.Append(' ', indentation).Append(key); + } + else + { + index = -1; + yamlString.Append(' ', indentation).Append(key).Append(':'); + } + + if (value.IsValue) + { + var valueString = value.ToString(); + var needsQuotes = + value.IsNumeric == false && (int.TryParse(valueString, out _) || double.TryParse(valueString, out _)) // 숫자인데 강제로 문자화 한거거나 + || valueString.Contains('#') || valueString.StartsWith('[') || valueString.StartsWith('{') // 특수문자가 포함되어 있거나, 배열이나 객체로 시작하는 경우 {Value} + || valueString.Contains(':') // "남은 시간: {Value}" 꼴 + || (value.IsNumeric == false && valueString.StartsWith('-')); // "- 어쩌고" 꼴, 배열인것으로 이해 + + yamlString.Append(' '); + + if (needsQuotes) + { + yamlString.Append('"').Append(valueString.Replace("\"", "\\\"")).Append('"'); + } + else + { + yamlString.Append(valueString); + } + + yamlString.Append(Environment.NewLine); + } + else + { + yamlString.Append(Environment.NewLine).Append(SaveToYaml(value, indentation + 2, useArray)); + } + } + + return yamlString.ToString(); + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntitySpace/Loader/YamlLoader.cs.meta b/Packages/SLSystem/SLEntitySpace/Loader/YamlLoader.cs.meta new file mode 100644 index 000000000..0c62e9b18 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/Loader/YamlLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 033bc7e19fe121846bba30e7d4c83c37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntitySpace/SLDataLoader.cs b/Packages/SLSystem/SLEntitySpace/SLDataLoader.cs new file mode 100644 index 000000000..75d27c379 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/SLDataLoader.cs @@ -0,0 +1,21 @@ +namespace Superlazy +{ + public abstract class SLDataLoader + { + public delegate void LoadEvent(string fileExt, string data); + + protected event LoadEvent OnLoad; + + public void Register(LoadEvent loadAction) + { + OnLoad += loadAction; + } + + public abstract void Load(); + + protected void Load(string fileExt, string data) + { + OnLoad?.Invoke(fileExt, data); + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntitySpace/SLDataLoader.cs.meta b/Packages/SLSystem/SLEntitySpace/SLDataLoader.cs.meta new file mode 100644 index 000000000..3fb997da7 --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/SLDataLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d36c4befee0ebe540b42adb2d3a165df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLEntitySpace/SLWindowsLoader.cs b/Packages/SLSystem/SLEntitySpace/SLWindowsLoader.cs new file mode 100644 index 000000000..06598be5a --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/SLWindowsLoader.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Superlazy +{ + public class SLWindowsLoader : SLDataLoader + { + public string DataPath { get; set; } = "../Data/"; + + public override void Load() + { + if (Directory.Exists(DataPath) == false) + { + SLLog.Warn($"Cant Find Data Path {Directory.GetCurrentDirectory()}{DataPath}"); + return; + } + + //{ + // string[] files = Directory.GetFiles(dataPath, "*.xml", SearchOption.AllDirectories); + // foreach (string fileName in files) + // { + // var fileRoot = Loader.XMLLoader.LoadFile(fileName); + // MergeToRoot(fileName.Replace(dataPath, string.Empty), root, fileRoot); + // } + //} + + { + var files = Directory.GetFiles(DataPath, "*.json", SearchOption.AllDirectories); + foreach (var fileName in files) + { + using var file = File.OpenText(fileName); + try + { + var json = file.ReadToEnd(); + Load("json", json); + } + catch (Exception e) + { + SLLog.Error($"Cannot Parse {fileName}. \n{e.Message}"); + } + } + + files = Directory.GetFiles(DataPath, "*.yaml", SearchOption.AllDirectories); + + var generatedEvents = new List(); + + foreach (var fileName in files) + { + if (fileName.Contains("Generated")) // 생성된 파일들 + { + generatedEvents.Add(fileName); + continue; + } + using var file = File.OpenText(fileName); + try + { + var json = file.ReadToEnd(); + Load("yaml", json); + } + catch (Exception e) + { + SLLog.Error($"Cannot Parse {fileName}. \n{e.Message}"); + } + } + + foreach (var fileName in generatedEvents) + { + using var file = File.OpenText(fileName); + try + { + var json = file.ReadToEnd(); + Load("yaml", json); + } + catch (Exception e) + { + SLLog.Error($"Cannot Parse {fileName}. \n{e.Message}"); + } + } + } + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLEntitySpace/SLWindowsLoader.cs.meta b/Packages/SLSystem/SLEntitySpace/SLWindowsLoader.cs.meta new file mode 100644 index 000000000..5e959cd7d --- /dev/null +++ b/Packages/SLSystem/SLEntitySpace/SLWindowsLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07385c4442bbc7944a0a44d2d249ce22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLLinqUtil.cs b/Packages/SLSystem/SLLinqUtil.cs new file mode 100644 index 000000000..4929db614 --- /dev/null +++ b/Packages/SLSystem/SLLinqUtil.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; + +namespace Superlazy +{ + public static class SLLinqUtil + { + public static TSource MinBy(this IEnumerable source, Func selector) + { + return source.MinBy(selector, null); + } + + public static TSource MinBy(this IEnumerable source, Func selector, IComparer comparer) + { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + if (comparer == null) comparer = Comparer.Default; + + using var sourceIterator = source.GetEnumerator(); + if (!sourceIterator.MoveNext()) + { + throw new InvalidOperationException("Sequence contains no elements"); + } + + var min = sourceIterator.Current; + var minKey = selector(min); + while (sourceIterator.MoveNext()) + { + var candidate = sourceIterator.Current; + var candidateProjected = selector(candidate); + if (comparer.Compare(candidateProjected, minKey) < 0) + { + min = candidate; + minKey = candidateProjected; + } + } + + return min; + } + + public static TSource MaxBy(this IEnumerable source, Func selector) + { + return source.MaxBy(selector, null); + } + + public static TSource MaxBy(this IEnumerable source, Func selector, IComparer comparer) + { + if (source == null) throw new ArgumentNullException("source"); + if (selector == null) throw new ArgumentNullException("selector"); + if (comparer == null) comparer = Comparer.Default; + + using var sourceIterator = source.GetEnumerator(); + if (!sourceIterator.MoveNext()) + { + throw new InvalidOperationException("Sequence contains no elements"); + } + + var max = sourceIterator.Current; + var maxKey = selector(max); + while (sourceIterator.MoveNext()) + { + var candidate = sourceIterator.Current; + var candidateProjected = selector(candidate); + if (comparer.Compare(candidateProjected, maxKey) > 0) + { + max = candidate; + maxKey = candidateProjected; + } + } + + return max; + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLLinqUtil.cs.meta b/Packages/SLSystem/SLLinqUtil.cs.meta new file mode 100644 index 000000000..8626b5313 --- /dev/null +++ b/Packages/SLSystem/SLLinqUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57b616d93fdce604b9a2ec4e0624e0c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLRandom.cs b/Packages/SLSystem/SLRandom.cs new file mode 100644 index 000000000..cd77bad7d --- /dev/null +++ b/Packages/SLSystem/SLRandom.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Superlazy +{ + public class SLRandom + { + private readonly SLEntity root; + private readonly string key; + + public SLRandom(SLEntity root, string key) + { + this.root = root; + this.key = key; + if (this.root[key] == false) + { + this.root[key] = new Random().Next(); + } + } + + public int Next(int min, int max) + { + int seed = root[key]; + root[key] = new Random(seed).Next(); + + return new Random(seed).Next(min, max); + } + + public double NextDouble() + { + int seed = root[key]; + root[key] = new Random(seed).Next(); + + return new Random(seed).NextDouble(); + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLRandom.cs.meta b/Packages/SLSystem/SLRandom.cs.meta new file mode 100644 index 000000000..32661c447 --- /dev/null +++ b/Packages/SLSystem/SLRandom.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 182fb08274d05ac488182eaea27ed2fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLSystem.asmdef b/Packages/SLSystem/SLSystem.asmdef new file mode 100644 index 000000000..09cee023f --- /dev/null +++ b/Packages/SLSystem/SLSystem.asmdef @@ -0,0 +1,16 @@ +{ + "name": "SLSystem", + "rootNamespace": "", + "references": [ + "GUID:f0e91edf4495c2045b34f001325cddb3" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/SLSystem/SLSystem.asmdef.meta b/Packages/SLSystem/SLSystem.asmdef.meta new file mode 100644 index 000000000..01fbf3ec6 --- /dev/null +++ b/Packages/SLSystem/SLSystem.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 873a4b43aaa8c8440bf2b49356e666ff +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLSystem.cs b/Packages/SLSystem/SLSystem.cs new file mode 100644 index 000000000..e9f06d0f3 --- /dev/null +++ b/Packages/SLSystem/SLSystem.cs @@ -0,0 +1,41 @@ +using System; +using Superlazy.Loader; + +namespace Superlazy +{ + public class SLSystem + { + public void Init(SLDataLoader loader, DateTime now) + { + Load(loader); + } + + protected virtual void Load(SLDataLoader loader) + { + Data = SLEntity.Empty; + loader.Register(LoadJson); + SLLog.Info("Data Loaded"); + } + + protected virtual void LoadJson(string fileExt, string json) + { + if (fileExt == "json") + { + JsonLoader.LoadJson(Data, json); + } + else if (fileExt == "yaml") + { + YamlLoader.LoadYaml(Data, json); + } + } + + public static SLEntity Data { get; private set; } + public static DateTime Now => DateTime.UtcNow; + + //public static DateTime Now + //{ + // get => SLDateTime.Now; + // private set => SLDateTime.Now = value; + //} + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLSystem.cs.meta b/Packages/SLSystem/SLSystem.cs.meta new file mode 100644 index 000000000..26e0dc788 --- /dev/null +++ b/Packages/SLSystem/SLSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f601fedd9e1c0548826ac041c8f37ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLSystem.csproj.meta b/Packages/SLSystem/SLSystem.csproj.meta new file mode 100644 index 000000000..09c09cd80 --- /dev/null +++ b/Packages/SLSystem/SLSystem.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b2f8a18eb8f672b4fae8e545a0e287af +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/SLSystemUtility.cs b/Packages/SLSystem/SLSystemUtility.cs new file mode 100644 index 000000000..22bc96423 --- /dev/null +++ b/Packages/SLSystem/SLSystemUtility.cs @@ -0,0 +1,197 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Superlazy +{ + public static class SLSystemUtility + { + public static void CreateTypeList(this List ret) where T : class + { + ForeachTypeof(typeof(T), (a, t) => + { + ret.Add(t); + }); + } + + public static void CreateInstanceList(this List ret) where T : class + { + ForeachTypeof(typeof(T), (a, t) => + { + var obj = a.CreateInstance(t.FullName); + ret.Add(obj as T); + }); + } + + public static void CreateInstanceList(this List ret, string[] typeNames) where T : class + { + ForeachTypeof(typeof(T), (a, t) => + { + if (typeNames.FirstOrDefault(n => n == t.FullName) == null) return; + + var obj = a.CreateInstance(t.FullName); + ret.Add(obj as T); + }); + } + + public static void CreateInstanceDictionary(this Dictionary ret) where T : class + { + ForeachTypeof(typeof(T), (a, t) => + { + var obj = a.CreateInstance(t.FullName); + ret.Add(t.Name, obj as T); + }); + } + + public static void CreateInstanceDictionary(this Dictionary ret, string[] typeNames) where T : class + { + ForeachTypeof(typeof(T), (a, t) => + { + if (typeNames.FirstOrDefault(n => n == t.FullName) == null) return; + + var obj = a.CreateInstance(t.FullName); + ret.Add(t.Name, obj as T); + }); + } + + public static void CreateMethodInfoDictionary(this Dictionary> ret, bool useReturn, params Type[] argTypes) where T : class + { + ForeachTypeof(typeof(T), (a, t) => + { + var methodArr = t.GetMethods(); + var methodDic = new Dictionary(); + for (var i = 0; i < methodArr.Length; i++) + { + var method = methodArr[i]; + var parameters = method.GetParameters(); + if (parameters.CompareLengthAndTypes(argTypes.Skip(useReturn ? 1 : 0).ToArray()) && (useReturn ? method.ReturnType == argTypes[0] : method.ReturnType == typeof(void))) + methodDic.Add(method.Name, method); + } + ret.Add(t.Name, methodDic); + }); + } + + public static void CreateCommandInfoToBaseType(this Dictionary ret, T instance, params Type[] argTypes) where T : class + { + var methodArr = instance.GetType().GetMethods(); + for (var i = 0; i < methodArr.Length; i++) + { + var method = methodArr[i]; + var parameters = method.GetParameters(); + if (parameters.CompareLengthAndTypes(typeof(SLEntity))) + { + ret.Add(string.Format("{0}/{1}", instance.GetType().Name, method.Name), (instance, method)); + } + } + } + + public static List GetMethods() where T : class + { + var methods = new List(); + var rootType = typeof(T); + + ForeachTypeof(typeof(T), (a, t) => + { + foreach (var m in t.GetMethods()) + { + methods.Add(m); + } + }); + + return methods; + } + + private static bool IsInherited(this Type t, Type inherited) + { + if (t.BaseType == null || t.BaseType == typeof(object)) + return false; + + if (t.BaseType == inherited) + return true; + + return t.BaseType.IsInherited(inherited); + } + + private static Type GetRootBaseType(Type t) + { + if (t.BaseType == null || t.BaseType == typeof(object)) + return t; + else + return GetRootBaseType(t.BaseType); + } + + public static bool CompareLengthAndTypes(this ParameterInfo[] parameters, params Type[] types) + { + if (parameters.Length != types.Length) + return false; + + for (var i = 0; i < parameters.Length; i++) + { + if (parameters[i].ParameterType != types[i]) + { + return false; + } + } + + return true; + } + + public static T CreateInstance(string typeName) where T : class + { + var type = AppDomain.CurrentDomain.GetAssemblies() + .Select(a => a.GetTypes().FirstOrDefault(t => t.Name == typeName)) + .FirstOrDefault(t => t != null); + if (type == null) return null; + + return type.Assembly.CreateInstance(type.FullName) as T; + } + + private static void ForeachTypeof(Type rootType, Action action) + { + foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) + { + if (a.FullName.IsLeft("Mono.")) continue; + if (a.FullName.IsLeft("SyntaxTree.")) continue; + if (a.FullName.IsLeft("nunit.")) continue; + if (a.FullName.IsLeft("Unity.")) continue; + if (a.FullName.IsLeft("ICSharpCode.")) continue; + if (a.FullName.IsLeft("Newtonsoft.")) continue; + if (a.FullName.IsLeft("Facebook")) continue; + if (a.FullName.IsLeft("winrt")) continue; + if (a.FullName.IsLeft("Tizen")) continue; + if (a.FullName.IsLeft("Apple")) continue; + if (a.FullName.IsLeft("Security")) continue; + if (a.FullName.IsLeft("Stores")) continue; + if (a.FullName.IsLeft("Purchasing.")) continue; + if (a.FullName.IsLeft("UnityStore")) continue; + if (a.FullName.IsLeft("Editor")) continue; + if (a.FullName.IsLeft("ChannelPurchase")) continue; + if (a.FullName.IsLeft("Google.")) continue; + if (a.FullName.IsLeft("UnityScript")) continue; + if (a.FullName.IsLeft("Boo.Lan")) continue; + if (a.FullName.IsLeft("System")) continue; + if (a.FullName.IsLeft("I18N")) continue; + if (a.FullName.IsLeft("UnityEngine")) continue; + if (a.FullName.IsLeft("UnityEditor")) continue; + if (a.FullName.IsLeft("mscorlib")) continue; + if (a.FullName.IsLeft("NiceIO")) continue; + if (a.FullName.IsLeft("PP")) continue; + if (a.FullName.IsLeft("PlayerBuild")) continue; + if (a.FullName.IsLeft("AndroidPlayerBuild")) continue; + if (a.FullName.IsLeft("Ex")) continue; + if (a.FullName.IsLeft("ScriptCompilation")) continue; + if (a.FullName.IsLeft("Anonymously")) continue; + + foreach (var t in a.GetTypes()) + { + if (t.IsAbstract) continue; + if (t.IsClass == false) continue; + if (rootType.IsAssignableFrom(t) == false) continue; + + action(a, t); + } + } + } + } +} \ No newline at end of file diff --git a/Packages/SLSystem/SLSystemUtility.cs.meta b/Packages/SLSystem/SLSystemUtility.cs.meta new file mode 100644 index 000000000..fdb1ce9cc --- /dev/null +++ b/Packages/SLSystem/SLSystemUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47baa16888b22b848b00adbfe04cf1e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/UnitComponent.meta b/Packages/SLSystem/UnitComponent.meta new file mode 100644 index 000000000..ae0e8a4a3 --- /dev/null +++ b/Packages/SLSystem/UnitComponent.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5a0a9b72590e6ba4eb531b8cabebcf20 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLSystem/package.json b/Packages/SLSystem/package.json new file mode 100644 index 000000000..8bbb4c263 --- /dev/null +++ b/Packages/SLSystem/package.json @@ -0,0 +1,11 @@ +{ + "name": "com.superlazy.slsystem", + "displayName": "SL System", + "description": "SL System", + "version": "1.0.0", + "unity": "2018.2", + "license": "MIT", + "dependencies": { + "com.superlazy.sllogger": "latest" + } +} \ No newline at end of file diff --git a/Packages/SLSystem/package.json.meta b/Packages/SLSystem/package.json.meta new file mode 100644 index 000000000..37adad196 --- /dev/null +++ b/Packages/SLSystem/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d32afcdffb5cbad43a530a5f7ce853bb +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/CustomSceneCamera.cs b/Packages/SLUnity/CustomSceneCamera.cs new file mode 100644 index 000000000..338992f3a --- /dev/null +++ b/Packages/SLUnity/CustomSceneCamera.cs @@ -0,0 +1,20 @@ +using UnityEngine; +using UnityEngine.Rendering.Universal; + +[RequireComponent(typeof(Camera))] +public class CustomSceneCamera : MonoBehaviour +{ + private void OnEnable() + { + // add stack to camera + var cam = GetComponent(); + SLGame.Camera.GetUniversalAdditionalCameraData().cameraStack.Insert(0, cam); + } + + private void OnDisable() + { + // remove stack to camera + var cam = GetComponent(); + SLGame.Camera.GetUniversalAdditionalCameraData().cameraStack.Remove(cam); + } +} \ No newline at end of file diff --git a/Packages/SLUnity/CustomSceneCamera.cs.meta b/Packages/SLUnity/CustomSceneCamera.cs.meta new file mode 100644 index 000000000..75059b393 --- /dev/null +++ b/Packages/SLUnity/CustomSceneCamera.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 097f62a8d87588f498dcbf5c614e2cb4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor.meta b/Packages/SLUnity/Editor.meta new file mode 100644 index 000000000..1bd8faf18 --- /dev/null +++ b/Packages/SLUnity/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b528e8b40736de4408eb6b9f053c6571 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/FixTexturePlatformSettings.cs b/Packages/SLUnity/Editor/FixTexturePlatformSettings.cs new file mode 100644 index 000000000..a9351b440 --- /dev/null +++ b/Packages/SLUnity/Editor/FixTexturePlatformSettings.cs @@ -0,0 +1,39 @@ +//using UnityEngine; +//using UnityEditor; +//using Unity.EditorCoroutines.Editor; + +//using System.Collections; +//using System.IO; +//using System.Text; + +//public class FixTexturePlatformSettings : AssetPostprocessor +//{ +// private void OnPostprocessTexture(Texture2D texture) +// { +// EditorCoroutineUtility.StartCoroutine(Fix($"{assetPath}.meta"), this); +// } + +// private IEnumerator Fix(string metafile) +// { +// // Wait for .meta to be created +// while (!File.ReadAllText(metafile).Contains("platformSettings:")) +// yield return null; + +// // Read .meta file +// var original = File.ReadAllText(metafile); +// var meta = new StringBuilder(original); + +// if (meta.ToString().Contains("iPhone")) +// { +// meta.Replace("iPhone", "iOS"); +// Debug.Log("Replaced iPhone to iOS"); +// } + +// // Save .meta file +// if (meta.ToString() != original) +// { +// File.WriteAllText(metafile, meta.ToString()); +// AssetDatabase.Refresh(); +// } +// } +//} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/FixTexturePlatformSettings.cs.meta b/Packages/SLUnity/Editor/FixTexturePlatformSettings.cs.meta new file mode 100644 index 000000000..6337c5e0c --- /dev/null +++ b/Packages/SLUnity/Editor/FixTexturePlatformSettings.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1840d074593b59249bc7f1035d9c6259 \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessor.cs b/Packages/SLUnity/Editor/SLAssetPostprocessor.cs new file mode 100644 index 000000000..b9b005816 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessor.cs @@ -0,0 +1,124 @@ +using System.Diagnostics; +using UnityEditor; + +public class SLAssetPostprocessor : AssetPostprocessor +{ + private void OnPreprocessModel() + { + var importer = assetImporter as ModelImporter; + var upperPath = importer.assetPath.ToUpper(); + + if (upperPath.Contains("ASSETS/RAW/")) + { + } + + if (upperPath.Contains("ASSETS/RAW/UNITS/") && upperPath.Contains("_") == false && upperPath.Contains(".FBX")) + { + var fileName = SLFileUtility.FileName(upperPath); + var folderName = SLFileUtility.FolderName(upperPath); + if (fileName == folderName) + { + SLAssetPostprocessorModel.OnPreprocessModel(importer); + } + } + else if (upperPath.Contains("ASSETS/RAW/UNITS/") && upperPath.Contains("_") && upperPath.Contains(".FBX")) + { + SLAssetPostprocessorAnim.OnPreprocessModel(importer); + } + else if (upperPath.Contains("ASSETS/RAW/UNITS/") && upperPath.Contains("_PREFAB.PREFAB")) + { + SLAssetPostprocessorModel.OnPreprocessModel(importer); + } + else if (upperPath.Contains("ASSETS/RAW/EFFECTS/")) + { + SLAssetPostprocessorEffect.OnPreprocessModel(importer); + } + } + + private void OnPreprocessAnimation() + { + var importer = assetImporter as ModelImporter; + var upperPath = importer.assetPath.ToUpper(); + if (upperPath.Contains("ASSETS/RAW/UNITS/") && upperPath.Contains("_") && upperPath.Contains(".FBX")) + { + SLAssetPostprocessorAnim.OnPreprocessAnim(importer); + } + } + + private void OnPreprocessTexture() + { + var importer = assetImporter as TextureImporter; + + var upperPath = importer.assetPath.ToUpper(); + + if (upperPath.Contains("ASSETS/RAW/Units/")) + { + SLAssetPostprocessorModel.OnPreprocessTexture(importer); + } + + if (upperPath.Contains("ASSETS/RAW/SPRITES/")) + { + SLAssetPostprocessorSprite.OnPreprocessTexture(importer); + } + } + + public static void OnPostprocessAllAssets(string[] importedAssets, string[] deleteAssets, string[] movedAssets, string[] movedFromAssetPaths) + { + foreach (var path in deleteAssets) + { + PostRem(path); + } + + var index = 0; + foreach (var path in movedFromAssetPaths) + { + PostRem(path, movedAssets[index]); + ++index; + } + + foreach (var path in movedAssets) + { + PostAdd(path); + } + + foreach (var path in importedAssets) + { + PostAdd(path); + } + + SLAssetPostprocessorModel.BuildTarget(); + SLAssetPostprocessorSprite.BuildTarget(); + } + + private static void PostRem(string path, string movePath = "") + { + try + { + SLAssetPostprocessorModel.OnRemove(path); + SLAssetPostprocessorAnim.OnRemove(path); + SLAssetPostprocessorEffect.OnRemove(path); + SLAssetPostprocessorSprite.OnRemove(path, movePath); + SLAssetPostprocessorScene.OnRemove(path); + } + catch (System.Exception e) + { + UnityEngine.Debug.LogError("Can't remove " + path + "\n" + e); + } + } + + private static void PostAdd(string path) + { + try + { + SLAssetPostprocessorModel.OnAdd(path); + SLAssetPostprocessorAnim.OnAdd(path); + SLAssetPostprocessorEffect.OnAdd(path); + SLAssetPostprocessorSprite.OnAdd(path); + SLAssetPostprocessorScene.OnAdd(path); + } + catch (System.Exception e) + { + UnityEngine.Debug.LogError("Can't import " + path + "\n" + e); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessor.cs.meta b/Packages/SLUnity/Editor/SLAssetPostprocessor.cs.meta new file mode 100644 index 000000000..9e0294d39 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0e900ab5eb37a3469e1c230f61f28f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessor.zip b/Packages/SLUnity/Editor/SLAssetPostprocessor.zip new file mode 100644 index 000000000..df357fed4 Binary files /dev/null and b/Packages/SLUnity/Editor/SLAssetPostprocessor.zip differ diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessor.zip.meta b/Packages/SLUnity/Editor/SLAssetPostprocessor.zip.meta new file mode 100644 index 000000000..6956e0952 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessor.zip.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 33f8acd2e04587f4797ebf227754328a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorAnim.cs b/Packages/SLUnity/Editor/SLAssetPostprocessorAnim.cs new file mode 100644 index 000000000..125e30f74 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorAnim.cs @@ -0,0 +1,79 @@ +using Superlazy; +using UnityEditor; +using UnityEngine; + +public static class SLAssetPostprocessorAnim +{ + private static string GetDestPath(string path) + { + return SLFileUtility.FolderPath(SLFileUtility.FolderPath(path)).Replace("/Raw/", "/Addressables/") + "/" + SLFileUtility.FileName(path) + ".anim"; + } + + public static void OnPreprocessModel(ModelImporter importer) + { + importer.materialImportMode = ModelImporterMaterialImportMode.None; + importer.importAnimation = true; + importer.generateSecondaryUV = false; + } + + internal static void OnPreprocessAnim(ModelImporter importer) + { + var clips = new ModelImporterClipAnimation[importer.defaultClipAnimations.Length]; + var i = 0; + foreach (var clip in importer.defaultClipAnimations) + { + clips[i] = clip; + clips[i].name = SLFileUtility.FileName(importer.assetPath); + i += 1; + } + importer.clipAnimations = clips; + } + + public static void OnRemove(string path) + { + var upperPath = path.ToUpper(); + if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && SLFileUtility.FileName(path).Contains("_") && upperPath.Contains(".FBX")) + { + var newPath = GetDestPath(path); + AssetDatabase.DeleteAsset(newPath); + } + + if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && SLFileUtility.FileName(path).Contains("_") && upperPath.Contains(".ANIM")) + { + var newPath = GetDestPath(path); + AssetDatabase.DeleteAsset(newPath); + } + } + + public static void OnAdd(string path) + { + var upperPath = path.ToUpper(); + if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && SLFileUtility.FileName(path).Contains("_") && upperPath.Contains(".FBX")) + { + CreateAnimation(path, GetDestPath(path)); + } + + if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && SLFileUtility.FileName(path).Contains("_") && upperPath.Contains(".ANIM")) + { + AssetDatabase.CopyAsset(path, GetDestPath(path)); + } + } + + public static void CreateAnimation(string path, string destPath) + { + SLFileUtility.MakeFolderFromFilePath(destPath); + + var motion = AssetDatabase.LoadAssetAtPath(path); + + if (motion == null) + { + Debug.LogError("Cant load motion: " + path); + return; + } + + var newMotion = Object.Instantiate(motion); + AssetDatabase.CreateAsset(newMotion, destPath); + + Debug.Log("Animation Build : " + destPath, newMotion); + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorAnim.cs.meta b/Packages/SLUnity/Editor/SLAssetPostprocessorAnim.cs.meta new file mode 100644 index 000000000..59bb630af --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorAnim.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2467d52cdb48ded4fb37d3ace7c45b16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorEffect.cs b/Packages/SLUnity/Editor/SLAssetPostprocessorEffect.cs new file mode 100644 index 000000000..6f728d00c --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorEffect.cs @@ -0,0 +1,79 @@ +using Superlazy; +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.U2D; +using UnityEngine; +using Object = UnityEngine.Object; + +public interface IPostProcessorEffect +{ + void OnCreateEffectPrefab(GameObject root); +} + +public static class SLAssetPostprocessorEffect +{ + public static void OnPreprocessModel(ModelImporter importer) + { + importer.materialImportMode = ModelImporterMaterialImportMode.None; + } + + public static void CreateEffect(string path, string destPath) + { + var effectCreateComponents = new List(); + effectCreateComponents.CreateInstanceList(); + + var originalPrefab = AssetDatabase.LoadMainAssetAtPath(path) as GameObject; + var obj = Object.Instantiate(originalPrefab); + + if (obj == null) return; + + var root = new GameObject(); + root.SetActive(false); + obj.transform.localPosition = Vector3.zero; + obj.transform.localRotation = Quaternion.identity; + obj.transform.SetParent(root.transform); + obj.name = originalPrefab.name; + + var res = root.AddComponent(); + + foreach (var comp in effectCreateComponents) + { + comp.OnCreateEffectPrefab(root); + } + + res.Init(); + + SLFileUtility.MakeFolderFromFilePath(destPath); + var prefab = PrefabUtility.SaveAsPrefabAsset(root, destPath); + prefab.SetActive(true); + Object.DestroyImmediate(root); + + Debug.Log("Build : " + destPath, prefab); + } + + public static void OnRemove(string path) + { + var upperPath = path.ToUpper(); + if (upperPath.IsLeft("ASSETS/RAW/EFFECTS") && upperPath.Contains(".PREFAB")) + { + var newPath = GetDestPath(path); + AssetDatabase.DeleteAsset(newPath); + } + } + + private static string GetDestPath(string path) + { + var name = SLFileUtility.FileName(path); + return SLFileUtility.FolderPath(path).Replace("/Raw/", "/Addressables/") + "/" + name + ".prefab"; + } + + public static void OnAdd(string path) + { + var upperPath = path.ToUpper(); + if (SLFileUtility.FolderPath(path).IsLeft("Assets/Raw/Effects") && upperPath.Contains(".PREFAB")) + { + var newPath = GetDestPath(path); + CreateEffect(path, newPath); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorEffect.cs.meta b/Packages/SLUnity/Editor/SLAssetPostprocessorEffect.cs.meta new file mode 100644 index 000000000..28f7b901d --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorEffect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 124d528fadb06c1429ff11803a503baa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorModel.cs b/Packages/SLUnity/Editor/SLAssetPostprocessorModel.cs new file mode 100644 index 000000000..0d67a3165 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorModel.cs @@ -0,0 +1,200 @@ +using System.Collections.Generic; +using System.Linq; +using Superlazy; +using UnityEditor; +using UnityEditor.Animations; +using UnityEngine; + +public interface IPostProcessorModel +{ + void OnCreatePrefab(string path, GameObject model); +} + +public static class SLAssetPostprocessorModel +{ + private static readonly HashSet targetPaths = new HashSet(); + + private static string GetDestPath(string path) + { + return SLFileUtility.FolderPath(path).Replace("/Raw/", "/Addressables/") + ".prefab"; + } + + private static string GetPrefabPath(string path) + { + var targetName = SLFileUtility.FolderName(path); + var targetPath = SLFileUtility.FolderPath(path); + + if (SLFileUtility.FolderName(path) == "Materials") + { + targetName = SLFileUtility.FolderName(targetPath); + targetPath = SLFileUtility.FolderPath(targetPath); + } + + return targetPath + "/" + targetName + ".prefab"; + } + + private static string GetTargetFBX(string path) + { + var targetName = SLFileUtility.FolderName(path); + var targetPath = SLFileUtility.FolderPath(path); + + if (SLFileUtility.FolderName(path) == "Materials") + { + targetName = SLFileUtility.FolderName(targetPath); + targetPath = SLFileUtility.FolderPath(targetPath); + } + + return targetPath + "/" + targetName + ".FBX"; + } + + public static void OnPreprocessModel(ModelImporter importer) + { + importer.materialImportMode = ModelImporterMaterialImportMode.None; + importer.generateSecondaryUV = false; + importer.importAnimation = false; + importer.animationType = ModelImporterAnimationType.Generic; + importer.avatarSetup = ModelImporterAvatarSetup.CreateFromThisModel; + } + + public static void OnRemove(string path) + { + var upperPath = path.ToUpper(); + if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && (upperPath.Contains(".FBX") || upperPath.Contains(".MAT"))) + { + if (SLFileUtility.FolderName(path) != SLFileUtility.FileName(path)) return; + var newPath = GetDestPath(path); + AssetDatabase.DeleteAsset(newPath); + + var prefabPath = GetPrefabPath(path); + AssetDatabase.DeleteAsset(prefabPath); + + targetPaths.Add(GetTargetFBX(path)); // 삭제되어도 리빌드 + } + } + + public static void OnAdd(string path) + { + var upperPath = path.ToUpper(); + if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && (upperPath.Contains(".FBX") || upperPath.Contains(".MAT"))) + { + if (SLFileUtility.FolderName(path) != SLFileUtility.FileName(path)) return; + targetPaths.Add(GetTargetFBX(path)); + } + else if (upperPath.IsLeft("ASSETS/RAW/UNITS/") && upperPath.Contains("_PREFAB.PREFAB")) + { + targetPaths.Add(GetPrefabPath(path).Replace(".prefab", "_Prefab.prefab")); + } + } + + public static void CreatePrefab(string path, string destPath) + { + try + { + var modelCreateComponents = new List(); + modelCreateComponents.CreateInstanceList(); + var go = AssetDatabase.LoadAssetAtPath(path); + + if (go == null) return; + + var prefab = new GameObject(go.name); + var model = Object.Instantiate(go); + model.name = "Model"; + model.transform.SetParent(prefab.transform); + model.AddComponent(); + + var guids = AssetDatabase.FindAssets("t:Material", new string[] { SLFileUtility.FolderPath(path) }); + var materials = guids.Select(guid => AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid))).ToDictionary(m => m.name); + + foreach (var renderer in model.GetComponentsInChildren()) + { + var sharedMaterials = new Material[renderer.sharedMaterials.Length]; // Material을 직접 엘리먼트로 대입하면 안되고 배열을 통으로 넣어야함 + for (var i = 0; i < renderer.sharedMaterials.Length; ++i) + { + if (materials.TryGetValue($"{renderer.name}_{i + 1}", out var numMat)) + { + sharedMaterials[i] = numMat; + } + else if (materials.TryGetValue(renderer.name, out var mat)) + { + sharedMaterials[i] = mat; + } + else if (materials.TryGetValue(go.name, out var defaultMat)) + { + sharedMaterials[i] = defaultMat; + } + else + { + sharedMaterials[i] = renderer.sharedMaterials[i]; + // 에러인가? 잠깐 파일 안갖다놨을뿐인가? + } + } + renderer.sharedMaterials = sharedMaterials; + } + + var res = prefab.AddComponent(); + + foreach (var comp in modelCreateComponents) + { + comp.OnCreatePrefab(destPath, model); + } + + res.Init(); + + SLFileUtility.MakeFolderFromFilePath(destPath); + + { + // Make Duumy(for test) + var dummyObj = Object.Instantiate(model); + var anim = dummyObj.GetComponentInChildren(); + var controller = AnimatorController.CreateAnimatorControllerAtPath(GetPrefabPath(path).Replace(".prefab", ".controller")); + + anim.runtimeAnimatorController = controller; + var rootStateMachine = controller.layers[0].stateMachine; + + var clipids = AssetDatabase.FindAssets("t:AnimationClip", new string[] { SLFileUtility.FolderPath(path) }); + foreach (var guid in clipids) + { + var clip = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid)); + if (clip != null) + { + var state = rootStateMachine.AddState(clip.name); + state.motion = clip; + } + } + + var dummy = PrefabUtility.SaveAsPrefabAssetAndConnect(dummyObj, GetPrefabPath(path), InteractionMode.AutomatedAction); + + Object.DestroyImmediate(dummyObj, false); + } + + AssetDatabase.DeleteAsset(destPath); + var newPreafb = PrefabUtility.SaveAsPrefabAssetAndConnect(prefab, destPath, InteractionMode.AutomatedAction); + + Object.DestroyImmediate(prefab, false); + Debug.Log("Build : " + destPath, newPreafb); + } + catch (System.Exception e) + { + Debug.LogError("Cant build " + destPath + "\n" + e); + } + } + + public static void BuildTarget() + { + foreach (var path in targetPaths) + { + CreatePrefab(path, GetDestPath(path)); + } + + targetPaths.Clear(); + } + + internal static void OnPreprocessTexture(TextureImporter importer) + { + importer.sRGBTexture = true; + importer.mipmapEnabled = false; + importer.streamingMipmaps = false; + importer.wrapMode = TextureWrapMode.Clamp; + importer.filterMode = FilterMode.Bilinear; + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorModel.cs.meta b/Packages/SLUnity/Editor/SLAssetPostprocessorModel.cs.meta new file mode 100644 index 000000000..3f2a26b78 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorModel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 68886d6dc8c664d4599d806c35f64197 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorScene.cs b/Packages/SLUnity/Editor/SLAssetPostprocessorScene.cs new file mode 100644 index 000000000..4760cc9c4 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorScene.cs @@ -0,0 +1,36 @@ +using UnityEditor; + +public static class SLAssetPostprocessorScene +{ + private static string GetDestPath(string path) + { + return path.Replace("/Raw/", "/Addressables/"); + } + + public static void OnRemove(string path) + { + var upperPath = path.ToUpper(); + + if (upperPath.Contains("ASSETS/RAW/SCENES/") == false || upperPath.Contains(".UNITY") == false) return; + + var destPath = GetDestPath(path); + AssetDatabase.DeleteAsset(destPath); + } + + public static void OnAdd(string path) + { + var upperPath = path.ToUpper(); + + if (upperPath.Contains("ASSETS/RAW/SCENES/") == false || upperPath.Contains(".UNITY") == false) return; + + var destPath = GetDestPath(path); + AssetDatabase.DeleteAsset(destPath); + + SLFileUtility.MakeFolderFromFilePath(destPath); + + AssetDatabase.CopyAsset(path, destPath); + //var scene = AssetDatabase.LoadAssetAtPath(destPath); + + // TODO: 추가 처리 + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorScene.cs.meta b/Packages/SLUnity/Editor/SLAssetPostprocessorScene.cs.meta new file mode 100644 index 000000000..71cc83382 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorScene.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a74e129d4cb7fb545a1bdf52599ce887 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorSprite.cs b/Packages/SLUnity/Editor/SLAssetPostprocessorSprite.cs new file mode 100644 index 000000000..3535971c8 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorSprite.cs @@ -0,0 +1,180 @@ +using System.Collections.Generic; +using System.IO; +using Superlazy; +using UnityEditor; +using UnityEditor.U2D; +using UnityEngine; +using UnityEngine.U2D; + +public interface IPostProcessorSpriteAtlas +{ + void OnAddSprite(SpriteAtlasAsset atlas); +} + +public static class SLAssetPostprocessorSprite +{ + private static readonly HashSet targetPaths = new HashSet(); + + public static void OnPreprocessTexture(TextureImporter importer) + { + importer.textureType = TextureImporterType.Sprite; + importer.spriteImportMode = SpriteImportMode.Single; + + importer.sRGBTexture = true; + importer.isReadable = false; + importer.mipmapEnabled = false; + importer.streamingMipmaps = false; + importer.wrapMode = TextureWrapMode.Clamp; + importer.filterMode = FilterMode.Bilinear; + + importer.textureCompression = TextureImporterCompression.Uncompressed; + importer.crunchedCompression = false; + importer.spritePixelsPerUnit = 100; + + var textureSettings = new TextureImporterSettings(); + importer.ReadTextureSettings(textureSettings); + textureSettings.spriteMeshType = SpriteMeshType.FullRect; + textureSettings.spriteExtrude = 2; + importer.SetTextureSettings(textureSettings); + } + + public static void OnRemove(string path, string movePath) + { + var upperPath = path.ToUpper(); + if (upperPath.Contains("ASSETS/RAW/SPRITES/") == false || upperPath.Contains(".PNG") == false) return; + + if (targetPaths.Contains(SLFileUtility.FolderPath(path)) == false) + { + targetPaths.Add(SLFileUtility.FolderPath(path)); + } + } + + public static void OnAdd(string path) + { + var upperPath = path.ToUpper(); + if (upperPath.Contains("ASSETS/RAW/SPRITES/") == false || upperPath.Contains(".PNG") == false) return; + + if (targetPaths.Contains(SLFileUtility.FolderPath(path)) == false) + { + targetPaths.Add(SLFileUtility.FolderPath(path)); + } + } + + public static void CreateAtlas(string path, string destPath) + { + var oldAtlas = AssetDatabase.LoadAssetAtPath(destPath); + + if (oldAtlas != null) + { + AssetDatabase.DeleteAsset(destPath); + } + + var di = new DirectoryInfo(path); + if (di.Exists == false) return; + + var objects = new List(); + foreach (var file in di.GetFiles()) + { + if (file.Name.ToUpper().IsRight(".PNG") == false) continue; + var filePath = path + "/" + file.Name; + var fileName = file.Name.Substring(0, file.Name.Length - ".png".Length); + + var sprite = AssetDatabase.LoadAssetAtPath(filePath); + var maxSize = sprite.rect.size.x > sprite.rect.size.y ? sprite.rect.size.x : sprite.rect.size.y; + if (maxSize > 1024) + { + CreateSingleAtlas(filePath, path.Replace("/Raw/", "/Addressables/") + $"_{fileName}.spriteatlasv2"); + continue; + } + + objects.Add(sprite); + } + + if (objects.Count == 0) return; + + SLFileUtility.MakeFolderFromFilePath(destPath); + var atlas = new SpriteAtlasAsset(); + + var spriteAtlasComponents = new List(); + spriteAtlasComponents.CreateInstanceList(); + foreach (var component in spriteAtlasComponents) + { + component.OnAddSprite(atlas); + } + + atlas.Add(objects.ToArray()); + + SpriteAtlasAsset.Save(atlas, destPath); + AssetDatabase.Refresh(); + + var sai = (SpriteAtlasImporter)AssetImporter.GetAtPath(destPath); + sai.packingSettings = new SpriteAtlasPackingSettings + { + enableRotation = false, + enableTightPacking = false, + enableAlphaDilation = false, + padding = 4, + blockOffset = 0 + }; + + sai.textureSettings = new SpriteAtlasTextureSettings + { + filterMode = FilterMode.Bilinear, + sRGB = true, + generateMipMaps = false + }; + } + + public static void CreateSingleAtlas(string path, string destPath) + { + var oldAtlas = AssetDatabase.LoadAssetAtPath(destPath); + + if (oldAtlas != null) + { + AssetDatabase.DeleteAsset(destPath); + } + + SLFileUtility.MakeFolderFromFilePath(destPath); + var atlas = new SpriteAtlasAsset(); + + var sprite = AssetDatabase.LoadAssetAtPath(path); + atlas.Add(new Object[] { sprite }); + + var spriteAtlasComponents = new List(); + spriteAtlasComponents.CreateInstanceList(); + foreach (var component in spriteAtlasComponents) + { + component.OnAddSprite(atlas); + } + + SpriteAtlasAsset.Save(atlas, destPath); + AssetDatabase.Refresh(); + + var sai = (SpriteAtlasImporter)AssetImporter.GetAtPath(destPath); + sai.packingSettings = new SpriteAtlasPackingSettings + { + enableRotation = false, + enableTightPacking = false, + enableAlphaDilation = false, + padding = 4, + blockOffset = 0 + }; + + sai.textureSettings = new SpriteAtlasTextureSettings + { + filterMode = FilterMode.Bilinear, + sRGB = true, + generateMipMaps = false + }; + } + + public static void BuildTarget() + { + foreach (var path in targetPaths) + { + CreateAtlas(path, path.Replace("/Raw/", "/Addressables/") + ".spriteatlasv2"); + } + + targetPaths.Clear(); + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLAssetPostprocessorSprite.cs.meta b/Packages/SLUnity/Editor/SLAssetPostprocessorSprite.cs.meta new file mode 100644 index 000000000..90294e410 --- /dev/null +++ b/Packages/SLUnity/Editor/SLAssetPostprocessorSprite.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 578d2e49b250ea0409205fc26da997bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLBuild.meta b/Packages/SLUnity/Editor/SLBuild.meta new file mode 100644 index 000000000..257ff2cc1 --- /dev/null +++ b/Packages/SLUnity/Editor/SLBuild.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 61b06882e13c02a4dae1dfa10a72848a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLBuild/SLAppBuild.cs b/Packages/SLUnity/Editor/SLBuild/SLAppBuild.cs new file mode 100644 index 000000000..da5acc685 --- /dev/null +++ b/Packages/SLUnity/Editor/SLBuild/SLAppBuild.cs @@ -0,0 +1,345 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using Superlazy; +using Superlazy.Loader; +using UnityEditor; +using UnityEditor.AddressableAssets; +using UnityEditor.AddressableAssets.Build; +using UnityEditor.AddressableAssets.Settings; +using UnityEditor.Callbacks; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +#if UNITY_IOS +using UnityEditor.iOS.Xcode; +#endif + +public class SLAppBuild +{ + public static string dataAssetPath = "Addressables/Data"; + private static readonly SLEntity options = SLEntity.Empty; + + private enum SLAppBuildTarget + { + NONE = -1, + iOS = 0, + Android = 4, + Android_x86 = 5, + iOS_Cheat = 8, + Android_Cheat = 9 + } + + private static void ParseCommandLine() + { + var args = Environment.GetCommandLineArgs(); + + for (var i = 0; i < args.Length; ++i) + { + if (args[i].IsLeft("-")) + { + if (args[i + 1].Contains(",")) + { + var splits = args[i + 1].Split(','); + + for (var j = 0; j < splits.Count(); ++j) + { + options[args[i].Replace("-", "")][j.ToString()] = splits[j]; + } + + ++i; + } + else + { + options[args[i].Replace("-", "")] = args[i + 1]; + ++i; + } + } + } + } + + public static void BuildAndroidAPK() + { + PreBuild(); + + PlayerSettings.Android.bundleVersionCode = options["BuildSettings"]["BuildVersion"]; + + PlayerSettings.Android.keystorePass = options["BuildSettings"]["Android"]["KeystorePass"]; + PlayerSettings.Android.keyaliasName = options["BuildSettings"]["Android"]["KeyaliasName"]; + PlayerSettings.Android.keyaliasPass = options["BuildSettings"]["Android"]["KeyaliasPass"]; + + EditorUserBuildSettings.buildAppBundle = false; + var outputName = Application.productName + ".apk"; + + GenericBuild(outputName, BuildTargetGroup.Android, BuildTarget.Android, BuildOptions.None); + } + + public static void BuildiOSIPA() + { + PreBuild(); + + var targetDir = "./build"; + + PlayerSettings.iOS.buildNumber = options["BuildSettings"]["BuildVersion"]; + + var opt = BuildOptions.None; + + PlayerSettings.statusBarHidden = true; + + if (Directory.Exists(targetDir)) + { + Directory.Delete(targetDir, true); + } + + if (Directory.Exists(targetDir) == false) + { + Directory.CreateDirectory(targetDir); + } + + GenericBuild(targetDir, BuildTargetGroup.iOS, BuildTarget.iOS, opt); + } + + public static void PreBuild() + { + LoadBuildSettings(); + ParseCommandLine(); + + UpdateDataScript(); + UpdateAddressable(); + + UpdateLoaderID(); + } + + private static void GenericBuild(string target_path, BuildTargetGroup buildTargetGroup, BuildTarget build_target, BuildOptions build_options) + { + var levels = GetLevelsFromBuildSettings(); + EditorUserBuildSettings.SwitchActiveBuildTarget(buildTargetGroup, build_target); + + // TODO: NamedBuildTarget으로 개선 + if (options["Def"]) + { + // 기존 심볼들 + var existingDefs = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup) + .Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) + .Select(d => d.Trim()) + .ToHashSet(); + + // 새로 추가할 심볼들 + var newDefs = options["Def"].ToString() + .Split(";", StringSplitOptions.RemoveEmptyEntries) + .Select(d => d.Trim()); + + // 병합 후 중복 제거 + foreach (var def in newDefs) + existingDefs.Add(def); + + // 최종 적용 + var mergedDefs = string.Join(";", existingDefs); + PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, mergedDefs); + } + + var res = BuildPipeline.BuildPlayer(levels, target_path, build_target, build_options); + + if (res.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded) + { + throw new Exception("BuildPlayer failure: " + res.summary.ToString()); + } + } + + private static string[] GetLevelsFromBuildSettings() + { + var levels = new List(); + + foreach (var scene in EditorBuildSettings.scenes) + { + levels.Add(scene.path); + } + + return levels.ToArray(); + } + + public static void LoadBuildSettings() + { + var path = Path.Combine(Application.dataPath, "SLBuild", "BuildSettings.json"); + + options["BuildSettings"] = JsonLoader.LoadJson(File.ReadAllText(path))["BuildSettings"]; + } + + public static void UpdateDataScript() + { + FileUtil.DeleteFileOrDirectory("Assets/Addressables/Data/"); + + var destDir = Path.Combine(Application.dataPath, dataAssetPath); + + Directory.CreateDirectory(destDir); + + var loader = SLSystemUtility.CreateInstance("SLWindowsLoader"); + var system = SLSystemUtility.CreateInstance("SLSystem"); + system.Init(loader, DateTime.UtcNow); + loader.Load(); + + foreach (var session in SLSystem.Data) + { + var fileName = session.ID + ".json"; + var paths = Path.Combine(destDir, fileName).Split(Path.DirectorySeparatorChar); + var path = ""; + + for (var i = 0; i < paths.Length - 1; ++i) + { + path += paths[i] + Path.DirectorySeparatorChar; + if (Directory.Exists(path) == false) + { + Directory.CreateDirectory(path); + } + } + + var saveData = SLEntity.Empty; + saveData[session.ID] = session; + var text = JsonLoader.SaveToJson(saveData); + SLFileUtility.MakeFolderFromFilePath(Path.Combine(destDir, fileName)); + File.WriteAllText(Path.Combine(destDir, fileName), text, Encoding.UTF8); + } + + AssetDatabase.Refresh(); + } + + private static void UpdateAddressable() + { + AssetDatabase.ImportAsset("Assets/Addressables", ImportAssetOptions.ImportRecursive); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + + var settings + = AddressableAssetSettingsDefaultObject.Settings; + + settings.activeProfileId + = settings.profileSettings.GetProfileId("Default"); + var builder + = AssetDatabase.LoadAssetAtPath("Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset") as IDataBuilder; + + settings.ActivePlayerDataBuilderIndex + = settings.DataBuilders.IndexOf((ScriptableObject)builder); + + AddressableAssetSettings.BuildPlayerContent(out var result); + + if (!string.IsNullOrEmpty(result.Error)) + throw new Exception(result.Error); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + + public static void UpdateLoaderID() + { + EditorSceneManager.OpenScene("Assets/Scenes/Game.unity"); + var slunity = UnityEngine.Object.FindFirstObjectByType(); + if (slunity != null) + { + slunity.loaderID = "SLUnityDataLoader"; + } + + EditorSceneManager.SaveScene(SceneManager.GetActiveScene()); + } + + [PostProcessBuild(999)] + public static void OnPostProcessBuild(BuildTarget buildTarget, string path) + { + if (buildTarget == BuildTarget.StandaloneWindows64) + { + var folderPath = SLFileUtility.FolderPath(path); + + var backupFolder = folderPath + "/" + Application.productName + "_BackUpThisFolder_ButDontShipItWithYourGame"; + if (Directory.Exists(backupFolder)) + { + Directory.Delete(backupFolder, true); + } + + var burstDebugFolder = folderPath + "/" + Application.productName + "_BurstDebugInformation_DoNotShip"; + if (Directory.Exists(burstDebugFolder)) + { + Directory.Delete(burstDebugFolder, true); + } + + var fileName = Application.productName; + if (options["FileName"]) + { + fileName = options["FileName"]; + } + + if (File.Exists(folderPath + $"/../{fileName}.zip")) + { + File.Delete(folderPath + $"/../{fileName}.zip"); + } + +; + ZipFile.CreateFromDirectory(folderPath, $"./{fileName}.zip"); + } + + if (buildTarget == BuildTarget.iOS) + { +#if UNITY_IOS + string projectPath = path + "/Unity-iPhone.xcodeproj/project.pbxproj"; + + UnityEditor.iOS.Xcode.PBXProject pbxProject = new UnityEditor.iOS.Xcode.PBXProject(); + pbxProject.ReadFromFile(projectPath); + + string target = pbxProject.GetUnityMainTargetGuid(); + pbxProject.SetBuildProperty(target, "ENABLE_BITCODE", "NO"); + pbxProject.SetBuildProperty(target, "DEBUG_INFORMATION_FORMAT", "dwarf"); + + if (options["iOSProvisionID"]) + { + pbxProject.SetBuildProperty(target, "PROVISIONING_PROFILE", options["iOSProvisionID"]); + } + + if (options["iOSProfileSpecifier"]) + { + pbxProject.SetBuildProperty(target, "PROVISIONING_PROFILE_SPECIFIER", options["iOSProfileSpecifier"]); + } + + if (options["iOSTeamID"]) + { + pbxProject.SetBuildProperty(target, "DEVELOPMENT_TEAM", options["iOSTeamID"]); + } + + if (options["iOSDistribution"]) + { + pbxProject.SetBuildProperty(target, "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "iPhone Distribution"); + } + + pbxProject.WriteToFile(projectPath); + + { + string plistPath = path + "/Info.plist"; + PlistDocument plist = new PlistDocument(); + plist.ReadFromString(File.ReadAllText(plistPath)); + + PlistElementDict rootDict = plist.root; + rootDict.SetBoolean("ITSAppUsesNonExemptEncryption", false); + + File.WriteAllText(plistPath, plist.WriteToString()); + } +#endif + } + } + + public static void BuildWindows() + { + PreBuild(); + + var targetDir = "./build"; + + if (Directory.Exists(targetDir)) + { + Directory.Delete(targetDir, true); + } + + if (Directory.Exists(targetDir) == false) + { + Directory.CreateDirectory(targetDir); + } + + GenericBuild(targetDir + "/" + Application.productName + ".exe", BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows64, BuildOptions.None); + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLBuild/SLAppBuild.cs.meta b/Packages/SLUnity/Editor/SLBuild/SLAppBuild.cs.meta new file mode 100644 index 000000000..b6b53d46f --- /dev/null +++ b/Packages/SLUnity/Editor/SLBuild/SLAppBuild.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76ab71d797cc1d548b395605811ee2f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLBuild/SLBuildMenu.cs b/Packages/SLUnity/Editor/SLBuild/SLBuildMenu.cs new file mode 100644 index 000000000..3e38ed752 --- /dev/null +++ b/Packages/SLUnity/Editor/SLBuild/SLBuildMenu.cs @@ -0,0 +1,34 @@ +using UnityEditor; +using UnityEditor.AddressableAssets.Settings; + +namespace Assets.Scripts.Editor +{ + [InitializeOnLoad] + public class SLBuildMenu + { + [MenuItem("SLBuild/Build Assets")] + public static void BuildAndroidAssets() + { + AssetDatabase.ImportAsset("Assets/Addressables", ImportAssetOptions.ImportRecursive); + AddressableAssetSettings.BuildPlayerContent(); + } + + [MenuItem("SLBuild/Build APK")] + public static void BuildAndroidAPK() + { + SLAppBuild.BuildAndroidAPK(); + } + + [MenuItem("SLBuild/Build iOS IPA")] + public static void BuildiOSIPA() + { + SLAppBuild.BuildiOSIPA(); + } + + [MenuItem("SLBuild/Build Windows")] + public static void BuildWindows() + { + SLAppBuild.BuildWindows(); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLBuild/SLBuildMenu.cs.meta b/Packages/SLUnity/Editor/SLBuild/SLBuildMenu.cs.meta new file mode 100644 index 000000000..7eb09c557 --- /dev/null +++ b/Packages/SLUnity/Editor/SLBuild/SLBuildMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 70051d36fdf85b64d9059a5ca0423c78 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLFileUtility.cs b/Packages/SLUnity/Editor/SLFileUtility.cs new file mode 100644 index 000000000..e3699a084 --- /dev/null +++ b/Packages/SLUnity/Editor/SLFileUtility.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.IO; +using UnityEditor; +using UnityEngine; + +public static class SLFileUtility +{ + public static bool DirectoryCopy(string sourceDirName, string destDirName, bool overwrite, bool copySubDirs, bool displayProgress = false, string pattern = "*.*") + { + var sourceDir = new DirectoryInfo(sourceDirName); + + if (!sourceDir.Exists) + { + return false; + //throw new DirectoryNotFoundException( + // "Source directory does not exist or could not be found: " + // + sourceDirName); + } + + var destDir = new DirectoryInfo(destDirName); + if (!destDir.Exists) + { + destDir = Directory.CreateDirectory(destDirName); + AssetDatabase.Refresh(); + } + + if (copySubDirs) + { + var dirs = sourceDir.GetDirectories(); + for (var i = 0; i < dirs.Length; i++) + { + var subdir = dirs[i]; + + var temppath = Path.Combine(destDirName, subdir.Name); + if (DirectoryCopy(subdir.FullName, temppath, overwrite, copySubDirs, displayProgress, pattern) == false) + return false; + } + } + + var files = sourceDir.GetFiles(pattern); + for (var i = 0; i < files.Length; i++) + { + var file = files[i]; + + if (displayProgress) + { + if (EditorUtility.DisplayCancelableProgressBar( + sourceDir.Name + " > " + destDir.Name, + file.Name, + i / (float)files.Length)) + { + EditorUtility.ClearProgressBar(); + return false; + } + } + + var temppath = Path.Combine(destDirName, file.Name); + file.CopyTo(temppath, overwrite); + } + EditorUtility.ClearProgressBar(); + + AssetDatabase.Refresh(); + return true; + } + + public static void SearchDirectory(string sourceDirName, bool doRecursive, ref List pathList) + { + var dir = new DirectoryInfo(sourceDirName); + + if (!dir.Exists) + { + throw new DirectoryNotFoundException( + "Source directory does not exist or could not be found: " + + sourceDirName); + } + + var dirs = dir.GetDirectories(); + + var files = dir.GetFiles(); + foreach (var file in files) + { + pathList.Add(file.FullName); + } + + if (doRecursive) + { + foreach (var subdir in dirs) + { + pathList.Add(subdir.FullName); + SearchDirectory(subdir.FullName, doRecursive, ref pathList); + } + } + } + + public static string FixPath(string path) + { + path = path.Replace('\\', '/'); + path = path.Replace("//", "/"); + while (path.Length > 0 && path[0] == '/') + { + path = path.Remove(0, 1); + } + return path; + } + + public static string FileName(string path) + { + return Path.GetFileNameWithoutExtension(path); + } + + public static string FolderPath(string path) + { + return FixPath(Path.GetDirectoryName(path)); + } + + public static string FolderName(string path) + { + var dirPath = FolderPath(path); + return FixPath(dirPath.Substring(dirPath.LastIndexOf('/') + 1)); + } + + public static string CombinePaths(params string[] paths) + { + var path = ""; + for (var i = 0; i < paths.Length; i++) + { + path = Path.Combine(path, FixPath(paths[i])); + } + return FixPath(path); + } + + public static string RelativePath(string path) + { + path = FixPath(path); + if (path.StartsWith("Assets")) + { + return path; + } + if (path.StartsWith(FixPath(Application.dataPath))) + { + return "Assets" + path.Substring(FixPath(Application.dataPath).Length); + } + else + { + return ""; + } + } + + public static void MakeFolderFromFilePath(string filePath) + { + var paths = FixPath(filePath).Split('/'); + var path = ""; + + for (var i = 0; i < paths.Length - 1; ++i) + { + path += paths[i] + "/"; + if (Directory.Exists(path) == false) + { + Directory.CreateDirectory(path); + AssetDatabase.Refresh(); + } + } + } + + public static DateTime GetLastWriteTime(string filePath) + { + var fileWriteTime = File.GetLastWriteTime(filePath); + var metaWriteTime = File.GetLastWriteTime(filePath + ".meta"); + + var result = DateTime.Compare(fileWriteTime, metaWriteTime); + if (result < 0) + { + // file이 meta보다 빠름. + return metaWriteTime; + } + else + { + return fileWriteTime; + } + } + + public static void AttrToNormal(string targetDir) + { + File.SetAttributes(targetDir, FileAttributes.Normal); + + var files = Directory.GetFiles(targetDir); + var dirs = Directory.GetDirectories(targetDir); + + foreach (var file in files) + { + try + { + File.SetAttributes(file, FileAttributes.Normal); + } + catch + { + } + } + + foreach (var dir in dirs) + { + AttrToNormal(dir); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLFileUtility.cs.meta b/Packages/SLUnity/Editor/SLFileUtility.cs.meta new file mode 100644 index 000000000..b52a4ba1c --- /dev/null +++ b/Packages/SLUnity/Editor/SLFileUtility.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b67bd58dfce671f41947e39a6f5f70bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLResourceObjectEditor.cs b/Packages/SLUnity/Editor/SLResourceObjectEditor.cs new file mode 100644 index 000000000..f42f8e748 --- /dev/null +++ b/Packages/SLUnity/Editor/SLResourceObjectEditor.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace Superlazy +{ + [CustomEditor(typeof(SLResourceObject))] + public class SLResourceObjectEditor : Editor + { + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + var resourceObject = (SLResourceObject)target; + if (GUILayout.Button("Build Data")) + { + resourceObject.Init(); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLResourceObjectEditor.cs.meta b/Packages/SLUnity/Editor/SLResourceObjectEditor.cs.meta new file mode 100644 index 000000000..8d0bd61be --- /dev/null +++ b/Packages/SLUnity/Editor/SLResourceObjectEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 326bfe8b78262674cab28d020b02f541 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI.meta b/Packages/SLUnity/Editor/SLUI.meta new file mode 100644 index 000000000..f50dd77b1 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ab118eb6615efc418722a3a38ae362c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLBindingEntityView.cs b/Packages/SLUnity/Editor/SLUI/SLBindingEntityView.cs new file mode 100644 index 000000000..cc1d20d1b --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLBindingEntityView.cs @@ -0,0 +1,123 @@ +using System.Collections.Generic; +using System.Linq; +using Superlazy; +using Superlazy.UI; +using UnityEditor; +using UnityEngine; + +public static class SLBindingEntityViewUtil +{ + private static SLUIComponent currentComponent; + private static readonly Dictionary sessionView = new Dictionary(); + + public static void ViewEntity(this SLUIComponent component) + { + if (Application.isPlaying == false) return; + if (component.isActiveAndEnabled == false) return; + + var parent = component.bindParent; + if (component is SLUIObjectOnOff) + { + parent = component as SLUIObjectOnOff; + } + + if (parent == null) return; + + var on = EditorGUILayout.Foldout(component == currentComponent, parent.BindPath); + if (on) + { + if (currentComponent != component) sessionView.Clear(); + currentComponent = component; + SLBindingEntityView.UpdateView(SLGame.Session.Get(parent.BindPath), "", 1, sessionView); + } + } +} + +public class SLBindingEntityView +{ + public static void UpdateView(SLEntity e, string prefix, int depth, Dictionary view) + { + var changed = SLEntity.Empty; + ViewTree(e, prefix, depth, view, changed); + ChangeView(e, changed); + } + + private static void ViewTree(SLEntity e, string prefix, int depth, Dictionary view, SLEntity changed) + { + foreach (var tree in e.OrderBy(child => child.IsValue ? "B" + child.ID : "A" + child.ID)) + { + var id = prefix + tree.ID; + if (view.ContainsKey(id) == false) + { + view[id] = false; + } + + if (tree.IsValue == false) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("", GUILayout.Width(10 * depth)); + view[id] = EditorGUILayout.Foldout(view[id], tree.ToString()); + EditorGUILayout.EndHorizontal(); + + if (view[id]) + { + ViewTree(tree, id + ".", depth + 1, view, changed[tree.ID]); + } + } + else + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("", GUILayout.Width(10 * depth)); + string changeValue; + if (tree.ToString() == "True") + { + changeValue = EditorGUILayout.Toggle(tree.ID, e[tree.ID]).ToString(); + } + else if (tree.IsNumeric) + { + changeValue = EditorGUILayout.DoubleField(tree.ID, e[tree.ID]).ToString(); + } + else + { + changeValue = EditorGUILayout.TextField(tree.ID, e[tree.ID]); + } + + if (changeValue != e[tree.ID]) + { + changed[tree.ID] = changeValue; + } + + EditorGUILayout.EndHorizontal(); + } + } + } + + private static void ChangeView(SLEntity e, SLEntity changed) + { + if (changed) + { + foreach (var entity in changed) + { + if (entity.IsValue == false) + { + ChangeView(e[entity.ID], entity); + } + else + { + if (e[entity.ID].IsNumeric) + { + e[entity.ID] = double.Parse(entity); + } + else if (entity == "False") + { + e[entity.ID] = false; + } + else + { + e[entity.ID] = entity; + } + } + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLBindingEntityView.cs.meta b/Packages/SLUnity/Editor/SLUI/SLBindingEntityView.cs.meta new file mode 100644 index 000000000..4dd8a2bdf --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLBindingEntityView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a38ef110358063428131cbc04847832 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLScreenStick.cs b/Packages/SLUnity/Editor/SLUI/SLScreenStick.cs new file mode 100644 index 000000000..1cc60fcc8 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLScreenStick.cs @@ -0,0 +1,79 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.InputSystem.OnScreen; +using UnityEngine.Serialization; + +namespace Superlazy.UI +{ + public class SLScreenStick : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler + { + public void OnPointerDown(PointerEventData eventData) + { + if (eventData == null) + throw new System.ArgumentNullException(nameof(eventData)); + + RectTransformUtility.ScreenPointToLocalPointInRectangle(transform.parent.GetComponentInParent(), eventData.position, eventData.pressEventCamera, out pointerDownPos); + padImagePos = rangeImage.position; + rangeImage.position = eventData.position; + } + + public void OnDrag(PointerEventData eventData) + { + if (eventData == null) + throw new System.ArgumentNullException(nameof(eventData)); + + RectTransformUtility.ScreenPointToLocalPointInRectangle(transform.parent.GetComponentInParent(), eventData.position, eventData.pressEventCamera, out var position); + var delta = position - pointerDownPos; + + delta = Vector2.ClampMagnitude(delta, MovementRange); + padImage.anchoredPosition = startPos + (Vector3)delta; + + var newPos = new Vector2(delta.x / MovementRange, delta.y / MovementRange); + SendValueToControl(newPos); + } + + public void OnPointerUp(PointerEventData eventData) + { + SendValueToControl(Vector2.zero); + padImage.anchoredPosition = startPos; + rangeImage.position = padImagePos; + } + + private void Start() + { + startPos = padImage.anchoredPosition; + } + + public float MovementRange + { + get => movementRange; + set => movementRange = value; + } + + [FormerlySerializedAs("movementRange")] + [SerializeField] + private float movementRange = 50; + + [FormerlySerializedAs("PadImage")] + [SerializeField] + private readonly RectTransform padImage; + + [FormerlySerializedAs("RangeImage")] + [SerializeField] + private readonly Transform rangeImage; + + [FormerlySerializedAs("ControlPath")] + [SerializeField] + private new string controlPath; + + private Vector3 startPos; + private Vector3 padImagePos; + private Vector2 pointerDownPos; + + protected override string controlPathInternal + { + get => controlPath; + set => controlPath = value; + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLScreenStick.cs.meta b/Packages/SLUnity/Editor/SLUI/SLScreenStick.cs.meta new file mode 100644 index 000000000..dcd46c184 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLScreenStick.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0c80ee5f89e1f6543a183985abbeaae2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIButtonEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIButtonEditor.cs new file mode 100644 index 000000000..aa13fdc60 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIButtonEditor.cs @@ -0,0 +1,95 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(SLUIButton))] + public class SLUIButtonEditor : Editor + { + private SLUIButton component; + private string[] methods; + + private static string filter; + + private void OnEnable() + { + component = target as SLUIButton; + methods = SLUIEditorUtil.GetAllCommands(); + } + + public override void OnInspectorGUI() + { + if (component.button != null) + { + UnityEngine.Events.UnityAction p = component.ButtonAction; + UnityEditor.Events.UnityEventTools.RemovePersistentListener(component.button.onClick, p); + } + + if (component.bindParent == null) + { + EditorGUILayout.LabelField("Can't find session Entity"); + } + else + { + EditorGUILayout.LabelField("SessionEntity : " + component.bindParent.BindPath); + } + + filter = EditorGUILayout.TextField("Binding Command Filter", filter); + + var filterMethods = methods; + if (string.IsNullOrEmpty(filter) == false) + { + filterMethods = methods.Where(name => name.ToLower().Contains(filter.ToLower())).ToArray(); + } + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.LabelField("Binding Command : " + component.command); + var currMethod = Array.FindIndex(filterMethods, methodName => methodName == component.command); + currMethod = currMethod < 0 ? 0 : currMethod; // None 표기용 + var newMethod = EditorGUILayout.Popup(currMethod, filterMethods); + if (newMethod > 0) + { + component.command = filterMethods[newMethod]; + } + else + { + component.command = ""; + } + } + + EditorGUILayout.EndHorizontal(); + + if (component.comparison == null) component.comparison = new SLValueComparison(); + if (component.bindParent) component.comparison.OnInspector(component.bindParent); + + if (component.comparison.useCheckValue) + { + component.useGrayScale = EditorGUILayout.Toggle("Use GrayScale Disable", component.useGrayScale); + } + + component.focus = EditorGUILayout.Toggle("focus", component.focus); + + if (string.IsNullOrEmpty(component.focusBind) == false) EditorGUILayout.LabelField($"focus bind{component.bindParent.BindPath}.{component.focusBind}"); + component.focusBind = EditorGUILayout.TextField("focus bind", component.focusBind); + + component.selectIsHover = EditorGUILayout.Toggle("Select is hover", component.selectIsHover); + + component.fastClick = EditorGUILayout.Toggle("fast click", component.fastClick); + + component.clickSound = EditorGUILayout.TextField("click sound", component.clickSound); + + component.ViewEntity(); + + if (GUI.changed && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIButtonEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIButtonEditor.cs.meta new file mode 100644 index 000000000..c62b369a6 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIButtonEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7327a9c6eb336704b91d3d3f301298ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIComponentEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIComponentEditor.cs new file mode 100644 index 000000000..875acb721 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIComponentEditor.cs @@ -0,0 +1,22 @@ +using UnityEditor; + +namespace Superlazy.UI +{ + [CustomEditor(typeof(SLUIComponent), true)] + public class SLUIComponentEditor : Editor + { + private SLUIComponent component; + + private void OnEnable() + { + component = target as SLUIComponent; + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + component.ViewEntity(); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIComponentEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIComponentEditor.cs.meta new file mode 100644 index 000000000..cc3743ac8 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIComponentEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b1dca5f686102b459e9fb70a35baf51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIDragButtonEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIDragButtonEditor.cs new file mode 100644 index 000000000..c819ffc1e --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIDragButtonEditor.cs @@ -0,0 +1,111 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(SLUIDragButton))] + public class SLUIDragButtonEditor : Editor + { + private SLUIDragButton component; + private string[] methods; + + private static string filter; + + private void OnEnable() + { + component = target as SLUIDragButton; + methods = SLUIEditorUtil.GetAllCommands(); + } + + public override void OnInspectorGUI() + { + if (component.button != null) + { + UnityEngine.Events.UnityAction p = component.ButtonAction; + UnityEditor.Events.UnityEventTools.RemovePersistentListener(component.button.onClick, p); + } + + if (component.bindParent == null) + { + EditorGUILayout.LabelField("Can't find session Entity"); + } + else + { + EditorGUILayout.LabelField("SessionEntity : " + component.bindParent.BindPath); + } + + filter = EditorGUILayout.TextField("Binding Command Filter", filter); + + var filterMethods = methods; + if (string.IsNullOrEmpty(filter) == false) + { + filterMethods = methods.Where(name => name.ToLower().Contains(filter.ToLower())).ToArray(); + } + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.LabelField("Binding Command : " + component.command); + var currMethod = Array.FindIndex(filterMethods, methodName => methodName == component.command); + currMethod = currMethod < 0 ? 0 : currMethod; // None 표기용 + var newMethod = EditorGUILayout.Popup(currMethod, filterMethods); + if (newMethod > 0) + { + component.command = filterMethods[newMethod]; + } + else + { + component.command = ""; + } + } + + EditorGUILayout.EndHorizontal(); + + if (component.comparison == null) component.comparison = new SLValueComparison(); + if (component.bindParent) component.comparison.OnInspector(component.bindParent); + + if (component.comparison.useCheckValue) + { + component.useGrayScale = EditorGUILayout.Toggle("Use GrayScale Disable", component.useGrayScale); + } + + component.focus = EditorGUILayout.Toggle("focus", component.focus); + + if (string.IsNullOrEmpty(component.focusBind) == false) EditorGUILayout.LabelField($"focus bind{component.bindParent.BindPath}.{component.focusBind}"); + component.focusBind = EditorGUILayout.TextField("focus bind", component.focusBind); + + component.fastClick = EditorGUILayout.Toggle("fast click", component.fastClick); + + component.clickSound = EditorGUILayout.TextField("click sound", component.clickSound); + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.LabelField("Cancel Command : " + component.cancelCommand); + var currMethod = Array.FindIndex(filterMethods, methodName => methodName == component.cancelCommand); + currMethod = currMethod < 0 ? 0 : currMethod; // None 표기용 + var newMethod = EditorGUILayout.Popup(currMethod, filterMethods); + if (newMethod > 0) + { + component.cancelCommand = filterMethods[newMethod]; + } + else + { + component.cancelCommand = ""; + } + } + + EditorGUILayout.EndHorizontal(); + + component.ViewEntity(); + + if (GUI.changed && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIDragButtonEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIDragButtonEditor.cs.meta new file mode 100644 index 000000000..6dfc7fe9a --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIDragButtonEditor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f85962de31620974db815db221005a57 \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIEntityEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIEntityEditor.cs new file mode 100644 index 000000000..1b60d47d7 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIEntityEditor.cs @@ -0,0 +1,124 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(SLUIEntity))] + public class SLUIEntityEditor : Editor + { + private SLUIEntity component; + private static string filter; + private static string[] methods; + + private void OnEnable() + { + component = target as SLUIEntity; + + methods = SLUIEditorUtil.GetAllCommands(); + } + + public override void OnInspectorGUI() + { + BindCheck(); + + component.useOnOff = EditorGUILayout.Toggle("Use On Off", component.useOnOff); + + if (component.useOnOff) + { + if (component.comparison == null) component.comparison = new SLValueComparison(); + component.comparison.OnInspector(component); + + filter = EditorGUILayout.TextField("Binding Command Filter", filter); + + var filterMethods = methods; + if (string.IsNullOrEmpty(filter) == false) + { + filterMethods = methods.Where(name => name.ToLower().Contains(filter.ToLower())).ToArray(); + } + + { + var currMethod = Array.FindIndex(filterMethods, 0, methodName => methodName == component.onCommand); + + var newMethod = EditorGUILayout.Popup("Turn On : " + component.onCommand, currMethod, filterMethods); + if (newMethod > 0) + { + component.onCommand = filterMethods[newMethod]; + } + else + { + component.onCommand = ""; + } + } + { + var currMethod = Array.FindIndex(filterMethods, 0, methodName => methodName == component.offCommand); + + var newMethod = EditorGUILayout.Popup("Turn Off : " + component.offCommand, currMethod, filterMethods); + if (newMethod > 0) + { + component.offCommand = filterMethods[newMethod]; + } + else + { + component.offCommand = ""; + } + } + } + + component.ViewEntity(); + + if (GUI.changed && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + + public void BindCheck() + { + EditorGUILayout.LabelField("Bind :" + component.BindPath); + + var parent = component.transform.parent?.GetComponentInParent(); + component.inherit = EditorGUILayout.Toggle("Use Inherit : " + parent?.BindPath, component.inherit); + if (parent != null) + { + component.bindParent = parent; + } + else + { + component.bindParent = null; + } + + if (component.inherit) + { + EditorGUILayout.ObjectField("Inherit", component.bindParent, typeof(SLUIObjectOnOff), false); + } + + if (component.bindParent == null) // no inherit + { + component.bind = EditorGUILayout.TextField("Bind", component.bind); + } + else if (component.bindParent is SLUIList) // list inherit + { + if (Application.isPlaying == false) + { + if (component.inherit == false || component.bind != "[~]" || component.useOnOff) + { + EditorUtility.SetDirty(component); + } + + component.inherit = true; + component.bind = "[~]"; + component.useOnOff = false; + } + } + else // entity inherit + { + component.bind = EditorGUILayout.TextField("Bind", component.bind); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIEntityEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIEntityEditor.cs.meta new file mode 100644 index 000000000..9d586ea4a --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIEntityEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 71366620685ac88418d07ba51c8c7bcd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIFadeEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIFadeEditor.cs new file mode 100644 index 000000000..354df74a2 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIFadeEditor.cs @@ -0,0 +1,32 @@ +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(SLUIFade))] + public class SLUIFadeEditor : Editor + { + private SLUIFade component; + + private void OnEnable() + { + component = target as SLUIFade; + } + + public override void OnInspectorGUI() + { + component.fadeInTime = EditorGUILayout.FloatField("Fade In(On) Time", component.fadeInTime); + component.fadeOutTime = EditorGUILayout.FloatField("Fade Out(Off) Time", component.fadeOutTime); + + component.ViewEntity(); + + if (GUI.changed && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIFadeEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIFadeEditor.cs.meta new file mode 100644 index 000000000..920f35412 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIFadeEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab626f98682b21c4aab1a2e9f73ac359 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIInputFieldEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIInputFieldEditor.cs new file mode 100644 index 000000000..9f8f1a639 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIInputFieldEditor.cs @@ -0,0 +1,82 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(SLUIInputField))] + public class SLUIInputFieldEditor : Editor + { + private SLUIInputField component; + private string[] methods; + private static string filter; + + private void OnEnable() + { + component = target as SLUIInputField; + methods = SLUIEditorUtil.GetAllCommands(); + } + + public override void OnInspectorGUI() + { + if (component.bindParent == null) + { + EditorGUILayout.LabelField("Can't find session Entity"); + } + else + { + component.bindingValue = EditorGUILayout.TextField("Binding Value", component.bindingValue); + component.isNumber = EditorGUILayout.Toggle("Is Number", component.isNumber); + + component.useChangeValue = EditorGUILayout.Toggle("Use ChangeValue", component.useChangeValue); + + if (component.useChangeValue) + { + filter = EditorGUILayout.TextField("Binding Command Filter", filter); + + var filterMethods = methods; + if (string.IsNullOrEmpty(filter) == false) + { + filterMethods = methods.Where(name => name.ToLower().Contains(filter.ToLower())).ToArray(); + } + + var currMethod = Array.FindIndex(filterMethods, 0, methodName => methodName == component.changeCommand); + + EditorGUILayout.BeginHorizontal(); + { + EditorGUILayout.LabelField("Change Command : " + component.changeCommand); + var newMethod = EditorGUILayout.Popup(currMethod, filterMethods); + if (newMethod > 0) + { + component.changeCommand = filterMethods[newMethod]; + } + else + { + component.changeCommand = ""; + } + } + + EditorGUILayout.EndHorizontal(); + } + else + { + component.changeCommand = ""; + } + + if (component.comparison == null) component.comparison = new SLValueComparison(); + component.comparison.OnInspector(component.bindParent); + } + + component.ViewEntity(); + + if (GUI.changed && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIInputFieldEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIInputFieldEditor.cs.meta new file mode 100644 index 000000000..e68abdb61 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIInputFieldEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: daf19569fb1ea37448d6cccdfa9fa3fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIListEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIListEditor.cs new file mode 100644 index 000000000..df5c3edd7 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIListEditor.cs @@ -0,0 +1,99 @@ +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(SLUIList))] + public class SLUIListEditor : Editor + { + private SLUIList component; + + private void OnEnable() + { + component = target as SLUIList; + } + + public override void OnInspectorGUI() + { + BindCheck(); + + component.listElement = component.GetComponentInChildren(true); + EditorGUILayout.ObjectField("Bind Session", component.listElement, typeof(SLUIEntity), true); + + component.useSort = EditorGUILayout.Toggle("Use Sort", component.useSort); + if (component.useSort) + { + var idx = component.descending ? 1 : 0; + idx = EditorGUILayout.Popup("Order", idx, new string[] { "A-Z", "Z-A" }); + component.descending = idx == 1; + component.sortKey = EditorGUILayout.TextField("Sort Key : ", component.sortKey); + } + + component.bindMaxCount = EditorGUILayout.TextField("Bind Max Bind", component.bindMaxCount); + component.bindMinCount = EditorGUILayout.TextField("Bind Min Bind", component.bindMinCount); + + component.addDelay = EditorGUILayout.FloatField("Add Delay(0 to stop)", component.addDelay); + + if (component.comparison == null) component.comparison = new SLValueComparison(); + if (component.listElement != null) + { + if (component.listElement.inherit == false || component.listElement.bind != "[~]" || component.listElement.useOnOff) + { + EditorUtility.SetDirty(component.listElement); + } + + component.listElement.useOnOff = false; + component.listElement.inherit = true; + + component.comparison.OnInspector(component.listElement); + } + + component.ViewEntity(); + + if (GUI.changed && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + + public void BindCheck() + { + EditorGUILayout.LabelField("Bind :" + component.BindPath); + + var parent = component.transform.parent?.GetComponentInParent(); + component.inherit = EditorGUILayout.Toggle("Use Inherit : " + parent?.BindPath, component.inherit); + if (parent != null) + { + component.bindParent = parent; + } + else + { + component.bindParent = null; + } + + if (component.inherit) + { + EditorGUILayout.ObjectField("Inherit", component.bindParent, typeof(SLUIObjectOnOff), false); + } + + if (component.bindParent == null) // no inherit + { + component.bind = EditorGUILayout.TextField("Bind", component.bind); + } + else if (component.bindParent is SLUIList) // list inherit + { + if (Application.isPlaying == false) + { + EditorGUILayout.LabelField("Cant bind list in list :" + component.BindPath); + } + } + else // entity inherit + { + component.bind = EditorGUILayout.TextField("Bind", component.bind); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIListEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIListEditor.cs.meta new file mode 100644 index 000000000..2af5c7b62 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIListEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca482e59fda34cc4089895340c1d9d8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIResourceEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIResourceEditor.cs new file mode 100644 index 000000000..00a9bd9a2 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIResourceEditor.cs @@ -0,0 +1,46 @@ +using UnityEditor; +using UnityEngine; + +namespace Superlazy.UI +{ + [CustomEditor(typeof(SLUIResource))] + public class SLUIResourceEditor : Editor + { + private SLUIResource component; + + private GameObject obj; + private Editor preview; + + private void OnEnable() + { + component = target as SLUIResource; + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + var newObj = AssetDatabase.LoadAssetAtPath($"Assets/Addressables/{component.effectBind}.prefab"); + + if (obj != newObj) + { + obj = newObj; + if (preview != null) DestroyImmediate(preview); + } + + if (obj == null) + { + EditorGUILayout.HelpBox("Can't Find Prefab", MessageType.Error); + } + else + { + if (preview == null) + { + preview = Editor.CreateEditor(obj); + } + + preview.OnInteractivePreviewGUI(GUILayoutUtility.GetRect(200, 200), new GUIStyle()); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIResourceEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIResourceEditor.cs.meta new file mode 100644 index 000000000..d86fef34e --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIResourceEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4bca9eb28ee7dc4409fc5c03bab792c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIUtil.cs b/Packages/SLUnity/Editor/SLUI/SLUIUtil.cs new file mode 100644 index 000000000..57ed5f98e --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIUtil.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Superlazy.UI +{ + public static class SLUIEditorUtil + { + public static string[] GetAllCommands() + { + var methods = new Dictionary>(); + methods.CreateMethodInfoDictionary(false, typeof(SLEntity)); + + var components = new List(); + components.CreateInstanceList(); + + var commands = new Dictionary(); + commands.Add("None", (null, null)); + foreach (var component in components) + { + commands.CreateCommandInfoToBaseType(component, typeof(SLEntity)); + } + + return commands.Keys.ToArray(); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIUtil.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIUtil.cs.meta new file mode 100644 index 000000000..cb3ad8897 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2672498a4a5f6f545b6c6e7a133846ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLUIValueEditor.cs b/Packages/SLUnity/Editor/SLUI/SLUIValueEditor.cs new file mode 100644 index 000000000..a21ef68c0 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIValueEditor.cs @@ -0,0 +1,135 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy.UI +{ + [CanEditMultipleObjects] + [CustomEditor(typeof(SLUIValue))] + public class SLUIValueEditor : Editor + { + private SLUIValue component; + + private void OnEnable() + { + component = target as SLUIValue; + } + + public override void OnInspectorGUI() + { + if (component.bindParent == null) + { + EditorGUILayout.LabelField("Can't find session Entity"); + } + else + { + EditorGUILayout.LabelField("Bind : " + component.bindParent.BindPath); + } + + if (component.text != null) + { + component.useRaw = EditorGUILayout.Toggle("UseRaw", component.useRaw); + + component.bindingValue = EditorGUILayout.TextField("Binding[Text]", component.bindingValue); + if (string.IsNullOrEmpty(component.bindingValue) == false) + { + component.gameObject.name = component.bindingValue; + } + if (component.useRaw == false) + { + component.prefix = EditorGUILayout.TextField("Prefix", component.prefix); + component.postfix = EditorGUILayout.TextField("Postfix", component.postfix); + + component.userInput = EditorGUILayout.Toggle("User Input", component.userInput); + + component.tagID ??= string.Empty; + + var formats = new List(); + formats.CreateInstanceList(); + + var optionSTRs = new List(formats.Select(p => p.ToString() + "(" + p.Tag + ")")); + var currOption = formats.FindIndex(pair => pair.Tag == component.tagID); + + var newOption = EditorGUILayout.Popup("TagOption", currOption, optionSTRs.ToArray()); + component.tagID = formats.ElementAt(newOption).Tag; + } + + component.ignoreColorTag = EditorGUILayout.Toggle("Ignore Color Tag", component.ignoreColorTag); + + component.useUpdate = EditorGUILayout.Toggle("Use Update Value", component.useUpdate); + + if (component.useUpdate) + { + component.useTypingEffect = false; + component.typingEndBind = string.Empty; + component.typingEndState = string.Empty; + component.startDelay = 0.2f; + component.delay = 0.03f; + } + else + { + component.useTypingEffect = EditorGUILayout.Toggle("Use Typing Effect", component.useTypingEffect); + if (component.useTypingEffect) + { + component.startDelay = EditorGUILayout.FloatField("Typing Effect Delay", component.startDelay); + component.delay = EditorGUILayout.FloatField("Typing Effect Duration", component.delay); + component.typingEndBind = EditorGUILayout.TextField("Typing End Bind", component.typingEndBind); + + if (string.IsNullOrEmpty(component.typingEndState) == false) + { + EditorGUILayout.LabelField($"On Typing End : Session.UIState.{component.typingEndState} = true"); + } + component.typingEndState = EditorGUILayout.TextField("Typing Effect EndState", component.typingEndState); + } + } + + component.useSmoothing = EditorGUILayout.Toggle("Use Smoothing", component.useSmoothing); + if (component.useSmoothing) + { + component.smoothingDelay = EditorGUILayout.FloatField("Delay", component.smoothingDelay); + component.beforeSmoothingValue = EditorGUILayout.TextField("BeforeValue", component.beforeSmoothingValue); + } + } + else if (component.image != null) + { + component.bindingValue = EditorGUILayout.TextField("Binding[Image]", component.bindingValue); + + var formats = new List(); + formats.CreateInstanceList(); + + component.tagID ??= string.Empty; + + var optionSTRs = new List(formats.Select(p => p.ToString() + "(" + p.Tag + ")")); + var currOption = formats.FindIndex(pair => pair.Tag == component.tagID); + + var newOption = EditorGUILayout.Popup("TagOption", currOption, optionSTRs.ToArray()); + component.tagID = formats.ElementAt(newOption).Tag; + } + else if (component.slider != null) + { + component.bindingValue = EditorGUILayout.TextField("Bind Text[Current]", component.bindingValue); + component.bindingMaxValue = EditorGUILayout.TextField("Bind Text[Max]", component.bindingMaxValue); + + component.useSmoothing = EditorGUILayout.Toggle("Use Smoothing", component.useSmoothing); + if (component.useSmoothing) + { + component.smoothingDelay = EditorGUILayout.FloatField("Delay", component.smoothingDelay); + } + } + else + { + EditorGUILayout.LabelField("Can't find UI Component"); + } + + component.ViewEntity(); + + if (GUI.changed && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLUIValueEditor.cs.meta b/Packages/SLUnity/Editor/SLUI/SLUIValueEditor.cs.meta new file mode 100644 index 000000000..1dcc0841d --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLUIValueEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f5fa502db026bd42a242c010d106196 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUI/SLValueComparisonInspector.cs b/Packages/SLUnity/Editor/SLUI/SLValueComparisonInspector.cs new file mode 100644 index 000000000..29320afdd --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLValueComparisonInspector.cs @@ -0,0 +1,54 @@ +using UnityEditor; + +namespace Superlazy.UI +{ + public static class SLValueComparisonInspector + { + public static void OnInspector(this SLValueComparison comp, SLUIObjectOnOff session, string inspectorName = "Check Value") + { + comp.checkValue = EditorGUILayout.TextField(inspectorName, comp.checkValue); + comp.useCheckValue = string.IsNullOrEmpty(comp.checkValue) == false; + if (comp.useCheckValue == false) + { + EditorGUILayout.LabelField("[" + session.BindPath + "] Check"); + } + else + { + var checkValuePath = + comp.checkValue.IsLeft(".") || + double.TryParse(comp.checkValue, out _) || + comp.checkValue == "True" || + comp.checkValue == "False" ? + comp.checkValue : session.BindPath.CombinePath(comp.checkValue); + + if (checkValuePath.IsLeft(".")) + { + checkValuePath = checkValuePath.Substring(1); + } + + comp.useCompValue = EditorGUILayout.Toggle("Use Comparison", comp.useCompValue); + if (comp.useCompValue) + { + EditorGUILayout.BeginHorizontal(); + { + var comps = new string[] { ">", "<", "==", "!=", ">=", "<=" }; + var type = (int)comp.compType; + var newComp = EditorGUILayout.Popup("[" + checkValuePath + "]", type, comps); + + if (newComp >= 0) + { + comp.compType = (SLValueComparison.CompType)newComp; + comp.compValue = EditorGUILayout.TextField(comp.compValue); + comp.useCheckValue = comp.checkValue != ""; + } + } + EditorGUILayout.EndHorizontal(); + } + else + { + EditorGUILayout.LabelField("[" + checkValuePath + "] Check"); + } + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUI/SLValueComparisonInspector.cs.meta b/Packages/SLUnity/Editor/SLUI/SLValueComparisonInspector.cs.meta new file mode 100644 index 000000000..6ef196751 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUI/SLValueComparisonInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bde4ea02cb1a2cb448daedf6be82ec4a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUnityEditor.asmdef b/Packages/SLUnity/Editor/SLUnityEditor.asmdef new file mode 100644 index 000000000..f18b7ff39 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUnityEditor.asmdef @@ -0,0 +1,27 @@ +{ + "name": "SLUnityEditor", + "rootNamespace": "", + "references": [ + "GUID:775573db2ba530e429a6432260c2ed34", + "GUID:69448af7b92c7f342b298e06a37122aa", + "GUID:9e24947de15b9834991c9d8411ea37cf", + "GUID:f0e91edf4495c2045b34f001325cddb3", + "GUID:873a4b43aaa8c8440bf2b49356e666ff", + "GUID:75469ad4d38634e559750d17036d5f7c", + "GUID:343deaaf83e0cee4ca978e7df0b80d21", + "GUID:2bafac87e7f4b9b418d9448d219b01ab", + "GUID:6055be8ebefd69e48b49212b09b47b2f", + "GUID:478a2357cc57436488a56e564b08d223" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUnityEditor.asmdef.meta b/Packages/SLUnity/Editor/SLUnityEditor.asmdef.meta new file mode 100644 index 000000000..1697f4bae --- /dev/null +++ b/Packages/SLUnity/Editor/SLUnityEditor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 195e490de97086945912e32bd0fa79cc +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUnityEditor.csproj.meta b/Packages/SLUnity/Editor/SLUnityEditor.csproj.meta new file mode 100644 index 000000000..b19c7b021 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUnityEditor.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7a6f2da32e6912b479ae93dbf3821eb2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUnityInspector.cs b/Packages/SLUnity/Editor/SLUnityInspector.cs new file mode 100644 index 000000000..c04981870 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUnityInspector.cs @@ -0,0 +1,392 @@ +using System.Collections.Generic; +using System.Linq; +using Superlazy.Loader; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Superlazy +{ + [CustomEditor(typeof(SLUnity))] + public class SLUnityInspector : Editor + { + private SLUnity component; + private bool sessionRoot; + private readonly Dictionary sessionView = new Dictionary(); + + private bool dataRoot; + private readonly Dictionary dataView = new Dictionary(); + + private string sessionSearch; + + [MenuItem("Window/SLUnity %#W")] + public static void ShowWindow() + { + Selection.activeObject = FindFirstObjectByType(); + } + + private void OnEnable() + { + component = target as SLUnity; + + //if (component.managers != null && component.managers.Length > 0 && component.managers[0] == "All") + //{ + // var behaviors = new List(); + // behaviors.CreateTypeList(); + // foreach (var type in behaviors) + // { + // useManagers.Add(type.FullName); + // } + //} + //else + //{ + // foreach (var managerName in component.managers) + // { + // useManagers.Add(managerName); + // } + //} + } + + public override void OnInspectorGUI() + { + base.OnInspectorGUI(); + + var requireSave = false; + + //component.Loader + + //SLUnityBoot.mobileData = EditorGUILayout.Toggle("Mobile Data", SLUnityBoot.mobileData); + //if (SLUnityBoot.mobileData == false) + //{ + // SLUnityBoot.dataPath = EditorGUILayout.TextField("Data Path", SLUnityBoot.dataPath); + //} + //SLUnityBoot.UpdateData(); + + EditorGUILayout.Separator(); + + //var behaviors = new List(); + //behaviors.CreateTypeList(); + //var subject = "SLManager :"; + //if (component.managers != null && component.managers.Length > 0 && component.managers[0] == "All") + //{ + // subject += " All"; + //} + //EditorGUILayout.LabelField(subject); + //var oldCount = useManagers.Count; + //foreach (var type in behaviors) + //{ + // bool old = useManagers.Contains(type.FullName); + // var use = EditorGUILayout.Toggle(type.FullName, old); + // if (use != old) + // { + // requireSave = true; + // if (use == false) + // { + // useManagers.Remove(type.FullName); + // } + // else + // { + // useManagers.Add(type.FullName); + // } + // } + //} + //if (useManagers.Count != oldCount) + //{ + // if (behaviors.Count == useManagers.Count) + // { + // component.managers = new string[] { "All" }; + // } + // else + // { + // component.managers = useManagers.ToArray(); + // } + //} + + EditorGUILayout.Separator(); + + ShowDataTree(); + + EditorGUILayout.Separator(); + + sessionSearch = EditorGUILayout.TextField("Search", sessionSearch); + if (sessionSearch == null || sessionSearch == string.Empty) + { + ShowSessionTree(); + } + else + { + ShowSessionSearch(sessionSearch); + } + + //var caches = SLGame.SessionCacheKeys; + //sessionCache = EditorGUILayout.Foldout(sessionCache, "SessionCache(" + caches.Count() + ")"); + //if (sessionCache) + //{ + // foreach (var key in caches) + // { + // EditorGUILayout.LabelField(key); + // } + //} + + ViewPlayerPref(); + + if (requireSave && Application.isPlaying == false) + { + EditorUtility.SetDirty(component); + EditorSceneManager.MarkAllScenesDirty(); + } + } + + private void ShowSessionTree() + { + sessionRoot = EditorGUILayout.Foldout(sessionRoot, "Session"); + if (sessionRoot && SLGame.Session) + { + var changed = SLEntity.Empty; + ViewTree(SLGame.Session, "", 1, sessionView, changed); + ChangeView(SLGame.Session, changed); + } + + Repaint(); + } + + private void ShowDataTree() + { + dataRoot = EditorGUILayout.Foldout(dataRoot, "Data"); + if (dataRoot && SLSystem.Data) + { + var changed = SLEntity.Empty; + ViewTree(SLSystem.Data, "", 1, dataView, changed); + ChangeView(SLSystem.Data, changed); + } + Repaint(); + } + + private void ViewTree(SLEntity e, string prefix, int depth, Dictionary view, SLEntity changed) + { + foreach (var tree in e.OrderBy(child => child.IsValue ? "B" + child.ID : "A" + child.ID)) + { + var id = prefix + tree.ID; + if (view.ContainsKey(id) == false) + { + view[id] = false; + } + if (tree.IsValue == false) + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("", GUILayout.Width(10 * depth)); + view[id] = EditorGUILayout.Foldout(view[id], tree.ToString()); + EditorGUILayout.EndHorizontal(); + + if (view[id]) + { + ViewTree(tree, id + ".", depth + 1, view, changed[tree.ID]); + } + } + else + { + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField("", GUILayout.Width(10 * depth)); + string changeValue; + if (tree.ToString() == "True") + { + changeValue = EditorGUILayout.Toggle(tree.ID, e[tree.ID]).ToString(); + } + else if (tree.IsNumeric) + { + changeValue = EditorGUILayout.DoubleField(tree.ID, e[tree.ID]).ToString(); + } + else + { + changeValue = EditorGUILayout.TextField(tree.ID, e[tree.ID]); + } + if (changeValue != e[tree.ID]) + { + changed[tree.ID] = changeValue; + } + EditorGUILayout.EndHorizontal(); + } + } + } + + private void ChangeView(SLEntity e, SLEntity changed) + { + if (changed) + { + foreach (var entity in changed) + { + if (entity.IsValue == false) + { + ChangeView(e[entity.ID], entity); + } + else + { + if (e[entity.ID].IsNumeric) + { + e[entity.ID] = double.Parse(entity); + } + else if (entity == "False") + { + e[entity.ID] = false; + } + else + { + e[entity.ID] = entity; + } + } + } + } + } + + private void ShowSessionSearch(string sessionSearch) + { + SessionSearch(SLGame.Session, sessionSearch, null); + } + + private void SessionSearch(SLEntity session, string sessionSearch, string path) + { + foreach (var child in session) + { + if (path != null) + { + var newPath = path + "." + child.ID; + if (child.IsValue) + { + if (newPath.Contains(sessionSearch)) + { + EditorGUILayout.LabelField(newPath + ": " + child); + } + } + else + { + SessionSearch(child, sessionSearch, newPath); + } + } + else + { + if (child.IsValue) + { + if (child.ID.Contains(sessionSearch)) + { + EditorGUILayout.LabelField(child.ID + ": " + child); + } + } + else + { + SessionSearch(child, sessionSearch, child.ID); + } + } + } + } + +#if UNITY_EDITOR_WIN + private bool viewPref; + private SLEntity pref; + private Dictionary> prefView = new Dictionary>(); + private Dictionary prefOn = new Dictionary(); +#endif + + private void ViewPlayerPref() + { +#if UNITY_EDITOR_WIN + if (Application.platform != RuntimePlatform.WindowsEditor) return; + viewPref = EditorGUILayout.Foldout(viewPref, "PlayerPref"); + + if (viewPref) + { + if (GUILayout.Button("Refresh")) + { + pref = null; + } + + if (pref == null) + { + MakePref(); + } + + foreach (var value in pref) + { + if (value.ID.IsLeft("unity") || value.ID.IsLeft("Unity")) continue; + + using (new EditorGUILayout.HorizontalScope()) + { + if (value.IsValue) + { + EditorGUILayout.LabelField(value.ID + " " + value); + } + else + { + if (prefOn.ContainsKey(value.ID) == false) prefOn[value.ID] = false; + prefOn[value.ID] = EditorGUILayout.Foldout(prefOn[value.ID], value.ID); + if (prefOn[value.ID]) + { + if (prefView.ContainsKey(value.ID) == false) prefView[value.ID] = new Dictionary(); + SLBindingEntityView.UpdateView(value, "", 1, prefView[value.ID]); + Repaint(); + } + } + + if (GUILayout.Button("Remove", GUILayout.Width(200))) + { + PlayerPrefs.DeleteKey(value.ID); + pref = null; + return; + } + } + } + } + } + + private void MakePref() + { + Microsoft.Win32.RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Unity\\UnityEditor\\" + PlayerSettings.companyName + "\\" + PlayerSettings.productName); + if (registryKey != null) + { + string[] valueNames = registryKey.GetValueNames(); + + pref = SLEntity.Empty; + + // Parse and convert the registry saved player prefs into our array + //int i = 0; + foreach (string valueName in valueNames) + { + string key = valueName; + + // Remove the _h193410979 style suffix used on player pref keys in Windows registry + int index = key.LastIndexOf("_"); + key = key.Remove(index, key.Length - index); + + // Get the value from the registry + object ambiguousValue = registryKey.GetValue(valueName); + + // Unfortunately floats will come back as an int (at least on 64 bit) because the float is stored as + // 64 bit but marked as 32 bit - which confuses the GetValue() method greatly! + if (ambiguousValue.GetType() == typeof(int)) + { + // If the player pref is not actually an int then it must be a float, this will evaluate to true + // (impossible for it to be 0 and -1 at the same time) + if (PlayerPrefs.GetInt(key, -1) == -1 && PlayerPrefs.GetInt(key, 0) == 0) + { + // Fetch the float value from PlayerPrefs in memory + pref[key] = PlayerPrefs.GetFloat(key); + } + else + { + pref[key] = (int)ambiguousValue; + } + } + else if (ambiguousValue.GetType() == typeof(byte[])) + { + // On Unity 5 a string may be stored as binary, so convert it back to a string + pref[key] = System.Text.Encoding.UTF8.GetString((byte[])ambiguousValue); + if (pref[key].IsLeft("{")) + { + pref[key] = JsonLoader.LoadJson(pref[key]); + } + } + } + } +#endif + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUnityInspector.cs.meta b/Packages/SLUnity/Editor/SLUnityInspector.cs.meta new file mode 100644 index 000000000..78f694a52 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUnityInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3de72f68b2acfa045879979dcfcf7948 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/SLUnityLogger.cs b/Packages/SLUnity/Editor/SLUnityLogger.cs new file mode 100644 index 000000000..9c571e417 --- /dev/null +++ b/Packages/SLUnity/Editor/SLUnityLogger.cs @@ -0,0 +1,127 @@ +using System.Diagnostics; +using System.Linq; +using Superlazy; +using UnityEngine; +using Debug = UnityEngine.Debug; +using Object = UnityEngine.Object; + +public class SLUnityLogger : ISLLogger +{ + private readonly string[] hideClasses = new string[] { "SLSystem", "SLGame", "SLEntity", "SLUnityLogger", "SLLog", "SLContainer", "SLValue" }; + public string[] hideKeys = new string[0]; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)] + private static void Load() + { + SLLog.Logger = new SLUnityLogger(); + } + + public void Info(string format, params object[] args) + { + var trace = new StackTrace(true); + var frames = trace.GetFrames(); + var frame = frames.FirstOrDefault(f => hideClasses.Any(hc => f.GetMethod().DeclaringType.Name == hc) == false); + var fullText = $"[{frame.GetMethod().DeclaringType.Name}.{frame.GetMethod().Name}:{frame.GetFileLineNumber()}]{string.Format(format, args)}"; + + if (hideKeys.Where(k => fullText.Contains(k)).FirstOrDefault() != null) return; + +#if UNITY_EDITOR + //UnityEditor.EditorUtility.DisplayDialog("Info", fullText, "확인", UnityEditor.DialogOptOutDecisionType.ForThisSession, "UnityLoggerDialog"); +#endif + + if (args.Length > 0 && args[0] is Object obj) + { + Debug.Log(fullText, obj); + } + else + { + Debug.Log(fullText); + } + } + + public void Warn(string format, params object[] args) + { + var trace = new StackTrace(true); + var frames = trace.GetFrames(); + var frame = frames.FirstOrDefault(f => hideClasses.Any(hc => f.GetMethod().DeclaringType.Name == hc) == false); + var fullText = $"[{frame.GetMethod().DeclaringType.Name}.{frame.GetMethod().Name}:{frame.GetFileLineNumber()}]{string.Format(format, args)}"; + +#if UNITY_EDITOR + UnityEditor.EditorUtility.DisplayDialog("Warn", fullText, "확인", UnityEditor.DialogOptOutDecisionType.ForThisSession, "UnityLoggerDialog"); +#endif + + if (args.Length > 0 && args[0] is Object obj) + { + Debug.LogWarning(fullText, obj); + } + else + { + Debug.LogWarning(fullText); + } + } + + public void Error(string format, params object[] args) + { + var trace = new StackTrace(true); + var frames = trace.GetFrames(); + var frame = frames.FirstOrDefault(f => hideClasses.Any(hc => f.GetMethod().DeclaringType.Name == hc) == false); + var fullText = $"[{frame.GetMethod().DeclaringType.Name}.{frame.GetMethod().Name}:{frame.GetFileLineNumber()}]{string.Format(format, args)}"; + +#if UNITY_EDITOR + UnityEditor.EditorUtility.DisplayDialog("Warn", fullText, "확인", UnityEditor.DialogOptOutDecisionType.ForThisSession, "UnityLoggerDialog"); +#endif + + if (args.Length > 0 && args[0] is Object obj) + { + Debug.LogError(fullText, obj); + } + else + { + Debug.LogError(fullText); + } + } + + //private void OnUnityLog(string condition, string stackTrace, UnityEngine.LogType errorType, bool isThread) + //{ + // string type = null; + // switch (errorType) + // { + // case LogType.Assert: + // type = "Debug"; + // break; + + // case LogType.Error: + // case LogType.Exception: + // type = "Error"; + // break; + + // case LogType.Log: + // type = "Log"; + // break; + + // case LogType.Warning: + // type = "Warn"; + // break; + // } + + // OnUnityLog(type, condition, stackTrace); + //} + + // public void OnUnityLog(string type, string condition, string stackTrace) + // { + // if (type == "Error" && SLSystem.GetConfig("BuildTag").ToString().Contains("SL")) + // { + // NMGameSaver.SetOption("Debug", true); + // } + + //#if !UNITY_EDITOR + // condition += "\n" + stackTrace; + //#endif + // if (filter[type]) + // { + // logs.Add(new KeyValuePair(type, condition)); + // logScroll.y = float.MaxValue; + // filter["Session"] = false; + // } + // } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/SLUnityLogger.cs.meta b/Packages/SLUnity/Editor/SLUnityLogger.cs.meta new file mode 100644 index 000000000..f48209f6b --- /dev/null +++ b/Packages/SLUnity/Editor/SLUnityLogger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a7b2577124c0c244bb51fc6929ffba5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/Tools.meta b/Packages/SLUnity/Editor/Tools.meta new file mode 100644 index 000000000..8ba191c0b --- /dev/null +++ b/Packages/SLUnity/Editor/Tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1cf0db66f9b0424cb6d62dd7eed6667 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/Editor/Tools/AnimatorUtil.cs b/Packages/SLUnity/Editor/Tools/AnimatorUtil.cs new file mode 100644 index 000000000..cc34ccf2c --- /dev/null +++ b/Packages/SLUnity/Editor/Tools/AnimatorUtil.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using UnityEditor; +using UnityEditor.Animations; +using UnityEngine; + +namespace SLUnityEditor.Tools +{ + public class AnimatorUtil + { + [MenuItem("Assets/Nest AnimationClips in Controller", true)] + public static bool NestAnimClipsValidate() => Selection.activeObject != null && Selection.activeObject.GetType() == typeof(AnimatorController); + + [MenuItem("Assets/Nest AnimationClips in Controller")] + public static void NestAnimClips() + { + var anim_controller = (AnimatorController)Selection.activeObject; + if (anim_controller == null) return; + + // Get all objects currently in Controller asset, we'll destroy them later + var objects = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(anim_controller)); + + AssetDatabase.SaveAssets(); + + // Add animations from all animation layers, without duplicating them + var oldToNew = new Dictionary(); + foreach (var layer in anim_controller.layers) + { + foreach (var state in layer.stateMachine.states) + { + var old = state.state.motion as AnimationClip; + if (old == null) continue; + + if (!oldToNew.ContainsKey(old)) // New animation in list - create new instance + { + var newClip = UnityEngine.Object.Instantiate(old) as AnimationClip; + newClip.name = old.name; + AssetDatabase.AddObjectToAsset(newClip, anim_controller); + AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(newClip)); + oldToNew[old] = newClip; + Debug.Log("Nested animation clip: " + newClip.name); + } + + state.state.motion = oldToNew[old]; + } + } + + // Destroy all old AnimationClips in asset + for (var i = 0; i < objects.Length; i++) + { + if (objects[i].GetType() == typeof(AnimationClip)) + { + UnityEngine.Object.DestroyImmediate(objects[i], true); + } + } + AssetDatabase.SaveAssets(); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/Editor/Tools/AnimatorUtil.cs.meta b/Packages/SLUnity/Editor/Tools/AnimatorUtil.cs.meta new file mode 100644 index 000000000..c4f1553d1 --- /dev/null +++ b/Packages/SLUnity/Editor/Tools/AnimatorUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a132e0ae02aa9e40abd4e47931a26f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLContextController.cs b/Packages/SLUnity/SLContextController.cs new file mode 100644 index 000000000..8fa22b387 --- /dev/null +++ b/Packages/SLUnity/SLContextController.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace Superlazy +{ + public abstract class SLContextController : MonoBehaviour + { + public abstract void Init(); + + public abstract void Clear(); + + public abstract void SetContext(SLEntity context); + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLContextController.cs.meta b/Packages/SLUnity/SLContextController.cs.meta new file mode 100644 index 000000000..da65fb3b0 --- /dev/null +++ b/Packages/SLUnity/SLContextController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd46c498f52854e4689781b8e1bac13f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLGame.cs b/Packages/SLUnity/SLGame.cs new file mode 100644 index 000000000..b8f44a9d5 --- /dev/null +++ b/Packages/SLUnity/SLGame.cs @@ -0,0 +1,483 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Superlazy; +using UnityEngine; + +public class SLGame +{ + public static SLEntity Session { get; private set; } + + public static IEnumerable SessionCacheKeys => sessionCache.Keys; + + public static Camera Camera { get; private set; } + + private class SessionCache + { + public bool validState = false; + public string id = null; + public SessionCache parent = null; + public SLEntity sessionCache; + public List sessionHandlers; + public float duration; + public bool isChanged; + } + + private static bool currValidState = false; + private static readonly Dictionary sessionCache = new Dictionary(); + private static readonly List sessionCacheIndex = new List(); + + private static int handlerIndex = 0; + private static readonly Dictionary sessionHandlers = new Dictionary(); + private static readonly Dictionary sessionCounters = new Dictionary(); + private static readonly SortedList runHandlers = new SortedList(); + + private static Dictionary gameComponents; + private static List activeComponents; + private static List readyActiveComponents; + + private static Dictionary commands; + private static List<(string command, SLEntity entity)> commandQueue; + private static bool canCommand = false; // 커맨드 즉시 실행 or queue + private static bool updateSessionCache = false; // 세션 캐시 업데이트 이후에는 필요시 핸들러를 즉시 실행 + + public static SLEntity SessionGet(string path) + { + if (sessionCache.TryGetValue(path, out var cache)) + { + cache.duration = 2f; + var parent = cache.parent; + while (parent != null) + { + parent.duration = 2f; + parent = parent.parent; + } + + if (cache.validState == currValidState) + { + return cache.sessionCache; + } + else + { + SLLog.Error($"{path} is expired."); + return Session.Get(path); + } + } + else + { + string parentPath = null; + var subLength = path.LastIndexOf('.'); + if (subLength > 0) + { + parentPath = path.Substring(0, subLength); + SessionGet(parentPath); + } + + var ret = Session.Get(path); + sessionCache[path] = new SessionCache + { + id = path.Substring(subLength + 1, path.Length - subLength - 1), + parent = parentPath != null ? sessionCache[parentPath] : sessionCache[""], + duration = 2f, + validState = currValidState, + sessionCache = ret + }; + sessionCacheIndex.Add(path); + return ret; + } + } + + private readonly List removeKeyIndex = new List(); + + private void SessionCacheUpdate() + { + currValidState = !currValidState; + var cacheCount = sessionCacheIndex.Count; + for (var i = 0; i < cacheCount; i++) + { + var c = sessionCacheIndex[i]; + var cache = sessionCache[c]; + var newValue = cache.sessionCache; // 현재값 + + var update = false; + if (cache.parent != null) + { + if (cache.parent.sessionCache.HasChild(cache.id)) + { + newValue = cache.parent.sessionCache[cache.id]; + } + else if (cache.sessionCache) // 자식이 없고 캐시는 있는경우 삭제를 위해 // 아이디가 null이라면 삭제된거라 다시 댕글 건다 // 근데 아이디는 상관없음 + { + newValue = false; + } + + update |= cache.parent.isChanged; + update |= cache.parent.sessionCache.IsModified(cache.id); + } + else + { + if (string.IsNullOrEmpty(c)) + { + newValue = Session; + } + else + { + if (Session.HasChild(c)) + { + newValue = Session[c]; + } + else if (cache.sessionCache) // 자식이 없고 캐시는 있는경우 삭제를 위해 + { + newValue = false; + } + } + } + + cache.validState = currValidState; + // 상위가 변경되거나/업데이트틱이 지났다면 캐시 변경 + // 삭제/변경되었다면 캐시가 바뀜 + // 추가/변경 되었다면 뉴가 바뀜 + + update |= SLEntity.Changed(cache.sessionCache, newValue); + + if (update) + { + cache.isChanged = true; + + cache.sessionCache = newValue; + + if (cache.sessionHandlers != null) + { + foreach (var handler in cache.sessionHandlers) + { + var handle = sessionHandlers[handler]; + if (runHandlers.ContainsKey(handle) == false) runHandlers[handle] = handler; + } + } + } + else if (cache.sessionCache.IsModified(null)) // 추가 삭제인경우 아래로 전파하진 않는다 + { + cache.sessionCache = newValue; + if (cache.sessionHandlers != null) + { + foreach (var handler in cache.sessionHandlers) + { + var handle = sessionHandlers[handler]; + if (runHandlers.ContainsKey(handle) == false) runHandlers[handle] = handler; + } + } + } + + if (cache.sessionHandlers == null || cache.sessionHandlers.Count == 0) + { + if (cache.duration < 0) + { + removeKeyIndex.Add(i); + } + else + { + cache.duration -= Time.unscaledDeltaTime; + } + } + else + { + // 부모의 유지시간 갱신 + var parent = cache.parent; + while (parent != null) + { + parent.duration = parent.duration > 2f ? parent.duration : 2f; + parent = parent.parent; + } + } + } + + for (var i = 0; i < cacheCount; i++) + { + var c = sessionCacheIndex[i]; + var cache = sessionCache[c]; + cache.sessionCache.EndModified(); + cache.isChanged = false; + } + + for (var i = removeKeyIndex.Count - 1; i >= 0; i--) + { + var key = sessionCacheIndex[removeKeyIndex[i]]; + var duration = sessionCache[key].duration; + if (duration <= 0) + { + sessionCache.Remove(key); + sessionCacheIndex.RemoveAt(removeKeyIndex[i]); + } + } + + removeKeyIndex.Clear(); + + while (runHandlers.Count != 0) + { + var handler = runHandlers.Values[0]; + runHandlers.RemoveAt(0); + handler.Invoke(); + } + } + + public static void AddNotify(string sessionPath, Action onChange) + { + SessionGet(sessionPath); + + if (sessionCache[sessionPath].sessionHandlers == null) + { + sessionCache[sessionPath].sessionHandlers = new List(); + } + + sessionCache[sessionPath].sessionHandlers.Add(onChange); + + if (sessionHandlers.ContainsKey(onChange) == false) + { + sessionHandlers[onChange] = handlerIndex; + handlerIndex += 1; + sessionCounters[onChange] = 0; + } + + sessionCounters[onChange] += 1; + + var handlerId = sessionHandlers[onChange]; + + if (runHandlers.ContainsKey(handlerId) == false) + { + runHandlers[handlerId] = onChange; + } + + if (updateSessionCache == false) // 코루틴 등에서 첫프레임 실행 보장 + { + while (runHandlers.Count != 0) + { + var handler = runHandlers.Values[0]; + runHandlers.RemoveAt(0); + handler.Invoke(); + } + } + } + + public static void RemoveNotify(string sessionPath, Action onChange) + { + sessionCounters[onChange] -= 1; + if (sessionCounters[onChange] == 0) + { + sessionHandlers.Remove(onChange); + sessionCounters.Remove(onChange); + } + + if (sessionCache.TryGetValue(sessionPath, out var cache)) + { + cache.sessionHandlers.Remove(onChange); + } + else + { + SLLog.Error($"Cannot RemoveNotify : {sessionPath}", onChange.Target); + } + } + + public SLGame(string[] managers, string main) + { + var sessionRoot = SLEntity.Empty; + sessionRoot["Session"]["Data"] = SLSystem.Data; + Session = sessionRoot["Session"]; + + Camera = Camera.main; + + sessionCache[""] = new SessionCache + { + id = "", + parent = null, + duration = float.PositiveInfinity, + validState = currValidState, + sessionCache = Session + }; + sessionCacheIndex.Add(""); + + gameComponents = new Dictionary(); + commandQueue = new List<(string command, SLEntity entity)>(); + activeComponents = new List(); + readyActiveComponents = new List(); + gameComponents.CreateInstanceDictionary(managers); + commands = new Dictionary(); + foreach (var component in gameComponents) + { + commands.CreateCommandInfoToBaseType(component.Value, typeof(SLEntity)); + } + + if (main == string.Empty) + { + main = managers[0]; + } + + ActiveComponent(main, true); + } + + internal void Update() + { + Session["Time"] += 1; + + foreach (var component in readyActiveComponents) + { + activeComponents.Add(component); + } + + readyActiveComponents.Clear(); + + canCommand = true; + updateSessionCache = true; + + foreach (var command in commandQueue) + { +#if UNITY_EDITOR + try + { +#endif + Command(command.command, command.entity); +#if UNITY_EDITOR + } + catch (Exception e) + { + SLLog.Error($"Can't Run [{command.command}]. {e.Message} {e.StackTrace}"); + } +#endif + } + + foreach (var component in activeComponents) + { +#if UNITY_EDITOR + try + { +#endif + component.Update(); +#if UNITY_EDITOR + } + catch (Exception e) + { + SLLog.Error($"Can't Update [{component.GetType().Name}]. {e.Message} {e.StackTrace}"); + } +#endif + } + + commandQueue.Clear(); + + activeComponents.RemoveAll(c => + { + if (c.Active == false) + { +#if UNITY_EDITOR + try + { +#endif + c.End(); +#if UNITY_EDITOR + } + catch (Exception e) + { + SLLog.Error($"Can't Update [{c.GetType().Name}]. {e.Message} {e.StackTrace}"); + } +#endif + return true; + } + return false; + }); + + canCommand = false; + + SessionCacheUpdate(); + + updateSessionCache = false; + } + + public static void ActiveComponent(string component, bool active) + { + // TODO: 중복 추가등 체크필요가 있을까? + var instance = gameComponents[component]; + if (active) + { + if (instance.Active == false) + { + if (activeComponents.Contains(instance)) // 이번 프레임에 삭제된 경우 + { + instance.End(); + } + else + { + readyActiveComponents.Add(instance); + } + instance.Active = true; + instance.Begin(); + } + } + else + { + instance.Active = false; + } + } + + public static void ActiveComponent(bool active) where T : SLGameComponent + { + ActiveComponent(typeof(T).Name, active); + } + + public static void Command(string commandName, SLEntity entity) + { +#if UNITY_EDITOR + try + { +#endif + if (commands.ContainsKey(commandName) == false) + { + SLLog.Error($"Can't Run [{commandName}]"); + return; + } + + if (canCommand == false) + { + commandQueue.Add((commandName, entity)); + return; + } + + var (component, method) = commands[commandName]; + + if (component.Active == false) + { + SLLog.Error($"Can't Run [{commandName}]. Component is not active"); + return; + } + method.Invoke(component, new[] { entity }); +#if UNITY_EDITOR + } + catch (Exception e) + { + var message = $"Can't Run [{commandName}]. \n{e.Message} \n{e.StackTrace}"; + var inner = e.InnerException; + while (inner != null) + { + message += $"\n{inner.Message} \n{inner.StackTrace}"; + inner = inner.InnerException; + } + SLLog.Error(message); + } +#endif + } + + public static void Event(string eventName, SLEntity context) + { + if (context == false) + { + context = SLEntity.Empty; + context["EventName"] = eventName; + } + var id = Session["Events"].Get(eventName).Count(); + context = context.Override(); + Session["Events"].Set($"{eventName}.{id}", context); + } + + public static void ClearEvent() + { + Session["Events"] = false; + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLGame.cs.meta b/Packages/SLUnity/SLGame.cs.meta new file mode 100644 index 000000000..cc40035cb --- /dev/null +++ b/Packages/SLUnity/SLGame.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65c4579dd6948da4fa59f0d03e51717d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLGameComponent.cs b/Packages/SLUnity/SLGameComponent.cs new file mode 100644 index 000000000..9b7ccf23d --- /dev/null +++ b/Packages/SLUnity/SLGameComponent.cs @@ -0,0 +1,13 @@ +using Superlazy; + +public abstract class SLGameComponent +{ + public static SLEntity Player => SLGame.Session["Player"]; + public bool Active { get; internal set; } + + public abstract void Begin(); + + public abstract void Update(); + + public abstract void End(); +} \ No newline at end of file diff --git a/Packages/SLUnity/SLGameComponent.cs.meta b/Packages/SLUnity/SLGameComponent.cs.meta new file mode 100644 index 000000000..47479cd31 --- /dev/null +++ b/Packages/SLUnity/SLGameComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56d0350b0c71c314c8e379c2e2219ed7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLGameSaver.cs b/Packages/SLUnity/SLGameSaver.cs new file mode 100644 index 000000000..9df1c4772 --- /dev/null +++ b/Packages/SLUnity/SLGameSaver.cs @@ -0,0 +1,206 @@ +using System.IO; +using System.IO.Compression; +using System.Text; +using Superlazy; +using Superlazy.Loader; +using UnityEngine; + +public interface IGameSaver +{ + public void Init(); + + void Set(string key, SLEntity value); + + SLEntity Get(string key, SLEntity defaultValue); +} + +public class RuntimeSaver : IGameSaver +{ + private SLEntity entity; + + public void Init() + { + if (File.Exists(@"./Saves/Save.sav")) + { + var yaml = LoadCompressedTextFromFile(@"./Saves/Save.sav"); + entity = YamlLoader.LoadYaml(yaml); + } + else + { + var text = PlayerPrefs.GetString("Save", ""); + entity = YamlLoader.LoadYaml(text); + } + } + + public SLEntity Get(string path, SLEntity defaultValue) + { + if (defaultValue == null) return entity.Get(path); + if (entity.Get(path)) return entity.Get(path); + + return defaultValue; + } + + public void Set(string path, SLEntity value) + { + entity.Set(path, value); + SaveCompressedTextToFile(YamlLoader.SaveToYaml(entity), @"./Saves/Save.sav"); + } + + private string LoadCompressedTextFromFile(string filePath) + { + using var fileStream = File.OpenRead(filePath); + using var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress); + using var resultStream = new MemoryStream(); + gzipStream.CopyTo(resultStream); + var decompressedData = resultStream.ToArray(); + return Encoding.UTF8.GetString(decompressedData); + } + + private void SaveCompressedTextToFile(string text, string filePath) + { + // 압축할 텍스트를 UTF8 바이트 배열로 변환 + var data = Encoding.UTF8.GetBytes(text); + + // 경로가 없으면 디렉토리 생성 + var directory = Path.GetDirectoryName(filePath); + if (!Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + // 파일 스트림 열고 압축된 데이터를 기록 + using var fileStream = File.Create(filePath); + using var gzipStream = new GZipStream(fileStream, CompressionMode.Compress); + gzipStream.Write(data, 0, data.Length); + } +} + +public class RuntimePlayerPrefSaver : IGameSaver +{ + private SLEntity entity; + + public void Init() + { + var text = PlayerPrefs.GetString("SaveData", ""); + entity = JsonLoader.LoadJson(text); + } + + public SLEntity Get(string path, SLEntity defaultValue) + { + if (defaultValue == null) return entity.Get(path); + if (entity.Get(path)) return entity.Get(path); + + return defaultValue; + } + + public void Set(string path, SLEntity value) + { + entity.Set(path, value); + PlayerPrefs.SetString("SaveData", JsonLoader.SaveToJson(entity, -1, true)); + } +} + +public class PlayerPrefOptionSaver : IGameSaver +{ + private SLEntity entity; + + public void Init() + { + var text = PlayerPrefs.GetString("Options", ""); + entity = YamlLoader.LoadYaml(text); + } + + public SLEntity Get(string path, SLEntity defaultValue) + { + if (defaultValue == null) return entity.Get(path); + if (entity.Get(path)) return entity.Get(path); + + return defaultValue; + } + + public void Set(string path, SLEntity value) + { + entity.Set(path, value); + PlayerPrefs.SetString("Options", YamlLoader.SaveToYaml(entity)); + } +} + +public class FileSaver : IGameSaver +{ + private SLEntity entity; + private readonly string filePath; + + public FileSaver(string path) + { + filePath = path; + } + + public void Init() + { + if (File.Exists(filePath)) + { + using var file = File.OpenText(filePath); + var yaml = file.ReadToEnd(); + entity = YamlLoader.LoadYaml(yaml); + } + else + { + entity = SLEntity.Empty; + } + } + + public SLEntity Get(string path, SLEntity defaultValue) + { + if (defaultValue == null) return entity.Get(path); + if (entity.Get(path)) return entity.Get(path); + + return defaultValue; + } + + public void Set(string path, SLEntity value) + { + entity.Set(path, value); + var yaml = YamlLoader.SaveToYaml(entity); + File.WriteAllText(this.filePath, yaml); + } +} + +// TODO: SLSystem과 통합 +public static class SLGameSaver +{ + private static IGameSaver saver = new DefaultSaver(); + private static IGameSaver optionSaver = new DefaultSaver(); + + public static void Init(IGameSaver inst, IGameSaver optionInst) + { + saver = inst; + saver.Init(); + + optionSaver = optionInst; + optionSaver.Init(); + } + + public static void Set(string key, SLEntity value) => saver.Set(key, value); + + public static SLEntity Get(string key, SLEntity deafaultValue = null) => saver.Get(key, deafaultValue); + + public static void OptionSet(string key, SLEntity value) => optionSaver.Set(key, value); + + public static SLEntity OptionGet(string key, SLEntity deafaultValue = null) => optionSaver.Get(key, deafaultValue); +} + +public class DefaultSaver : IGameSaver +{ + public void Init() + { + } + + public SLEntity Get(string path, SLEntity defaultValue) + { + return defaultValue; + } + + public void Set(string path, SLEntity value) + { + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLGameSaver.cs.meta b/Packages/SLUnity/SLGameSaver.cs.meta new file mode 100644 index 000000000..775988f16 --- /dev/null +++ b/Packages/SLUnity/SLGameSaver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d80af66251202934d925faaef8ceab80 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLOption.cs b/Packages/SLUnity/SLOption.cs new file mode 100644 index 000000000..ba1f37e33 --- /dev/null +++ b/Packages/SLUnity/SLOption.cs @@ -0,0 +1,64 @@ +using System; +using System.Globalization; +using UnityEngine; + +namespace Superlazy +{ + internal class SLOption + { + internal static void Init() + { + CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; + if (PlayerPrefs.HasKey("AppID") == false) + { + PlayerPrefs.SetString("AppID", Guid.NewGuid().ToString()); + PlayerPrefs.Save(); + } + } + + public static void InitOption(string key, SLEntity option) + { + if (PlayerPrefs.HasKey(OptionString(key))) + { + SetOption(key, PlayerPrefs.GetString(OptionString(key))); + } + else + { + SetOption(key, option); + } + } + + public static void SetOption(string key, SLEntity option) + { + if (option.ToString() == string.Empty) + { + option = false; + } + SLGame.Session["Options"][key] = option; + PlayerPrefs.SetString(OptionString(key), option); + } + + public static SLEntity GetOption(string key) + { + if (SLGame.Session["Options"][key]) + { + return SLGame.Session["Options"][key]; + } + else + { + SLLog.Error($"Option not found: {key}"); + return SLEntity.Empty; + } + } + + private static string OptionString(string key) + { + return "Option_" + key; + } + + internal static void Save() + { + PlayerPrefs.Save(); + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLOption.cs.meta b/Packages/SLUnity/SLOption.cs.meta new file mode 100644 index 000000000..a44f0b19e --- /dev/null +++ b/Packages/SLUnity/SLOption.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6bc8ae0000d83bf4ea2621bde88d68ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLResource.cs b/Packages/SLUnity/SLResource.cs new file mode 100644 index 000000000..87e53582f --- /dev/null +++ b/Packages/SLUnity/SLResource.cs @@ -0,0 +1,200 @@ +using System.Collections.Generic; +using Superlazy; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; +using UnityEngine.ResourceManagement.ResourceLocations; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.SceneManagement; +using UnityEngine.U2D; + +public static class SLResources +{ + private static Dictionary> unusedResourceObjects; + private static Dictionary> unusedPrefabs; + private static Transform unusedRoot; + + public static SLResourceObject CreateInstance(string prefabName, Transform parent = null) + { + if (unusedResourceObjects != null && unusedResourceObjects.ContainsKey(prefabName) && unusedResourceObjects[prefabName].Count > 0) + { + var instance = unusedResourceObjects[prefabName].Dequeue(); + instance.transform.SetParent(parent, false); + return instance; + } + else + { + var obj = GetPrefab(prefabName); + if (obj == null) + { + SLLog.Error($"Can't Find Preafb. [{prefabName}]"); + return null; + } + + var objectInstance = Object.Instantiate(obj, parent); + + objectInstance.name = prefabName; + var instance = objectInstance.GetComponent(); + + if (instance == null) + { + SLLog.Error($"Can't Find SLResourceObject. [{prefabName}]"); + return null; + } + return instance; + } + } + + internal static void DestroyInstance(this SLResourceObject go) + { + unusedResourceObjects ??= new Dictionary>(); + + if (unusedRoot == null) + { + unusedRoot = new GameObject("UnusedInstance").transform; + unusedRoot.gameObject.SetActive(false); + } + + go.transform.SetParent(unusedRoot, false); + if (unusedResourceObjects.ContainsKey(go.name) == false) + { + unusedResourceObjects.Add(go.name, new Queue()); + } + + unusedResourceObjects[go.name].Enqueue(go); + } + + public static GameObject CreatePrefabInstance(string prefabName, Transform parent = null) + { + if (unusedPrefabs != null && unusedPrefabs.ContainsKey(prefabName) && unusedPrefabs[prefabName].Count > 0) + { + var instance = unusedPrefabs[prefabName].Dequeue(); + instance.transform.SetParent(parent, false); + return instance; + } + else + { + var obj = GetPrefab(prefabName); + if (obj == null) + { + SLLog.Error($"Can't Find Preafb. [{prefabName}]"); + return null; + } + + var instance = Object.Instantiate(obj, parent); + + instance.name = prefabName; + return instance; + } + } + + public static void Destroy(this GameObject go) + { + unusedPrefabs ??= new Dictionary>(); + + if (unusedRoot == null) + { + unusedRoot = new GameObject("UnusedInstance").transform; + unusedRoot.gameObject.SetActive(false); + } + + go.transform.SetParent(unusedRoot, false); + if (unusedPrefabs.ContainsKey(go.name) == false) + { + unusedPrefabs.Add(go.name, new Queue()); + } + + unusedPrefabs[go.name].Enqueue(go); + } + + public static GameObject GetPrefab(string prefabName) + { + if (string.IsNullOrEmpty(prefabName)) return null; + var obj = Load(prefabName); + return obj; + } + + public static Sprite GetSprite(string spritePath) + { + if (string.IsNullOrEmpty(spritePath)) return null; + if (spritePath.Contains('/') == false) return null; + + //TODO: 문자열 분할이 일어나지 않게끔 캐싱 + var seperateIdx = spritePath.LastIndexOf('/'); + var atlasPath = spritePath.Substring(0, seperateIdx); + var spriteName = spritePath.Substring(seperateIdx + 1); + + { + // check big + var bigPath = $"{atlasPath}_{spriteName}"; + if (AddressableResourceExists(bigPath)) + { + return Load(bigPath).GetSprite(spriteName); + } + } + + return Load(atlasPath).GetSprite(spriteName); + } + + public static RuntimeAnimatorController GetAnimatorController(string controler) + { + return Load(controler); + } + + public static IList LoadAll(string path) where T : Object + { + return Addressables.LoadAssetsAsync(path, (t) => { }).WaitForCompletion(); + } + + public static T Load(string resourceName) where T : Object + { +#if UNITY_EDITOR + try + { +#endif + //if (AddressableResourceExists(resourceName) == false) return default; // TODO: 원인 파악해서 에디터에서 에러 정상발생하도록 수정 + + return Addressables.LoadAssetAsync(resourceName).WaitForCompletion(); +#if UNITY_EDITOR + } + catch + { + SLLog.Error($"Can't Find Resource. [{resourceName}]"); + return default; + } +#endif + } + + public static AsyncOperationHandle LoadScene(string resourceName, LoadSceneMode mode, bool active = false) + { +#if UNITY_EDITOR + try + { +#endif + // if (AddressableResourceExists(resourceName) == false) return default; // TODO: 원인 파악해서 에디터에서 에러 정상발생하도록 수정 + return Addressables.LoadSceneAsync(resourceName, mode, active); +#if UNITY_EDITOR + } + catch + { + SLLog.Error($"Can't Find Resource. [{resourceName}]"); + return default; + } +#endif + } + + public static AsyncOperationHandle UnloadScene(SceneInstance inst) + { + return Addressables.UnloadSceneAsync(inst); + } + + private static bool AddressableResourceExists(object key) // TODO: 성능이슈 개선필요 // TODO: 원인 파악해서 에디터에서 에러 정상발생하도록 수정 + { + foreach (var l in Addressables.ResourceLocators) + { + if (l.Locate(key, typeof(T), out var _)) + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLResource.cs.meta b/Packages/SLUnity/SLResource.cs.meta new file mode 100644 index 000000000..20b1b798a --- /dev/null +++ b/Packages/SLUnity/SLResource.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e74d3b038b9a4547b3155f43db0e214 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLResourceObject.cs b/Packages/SLUnity/SLResourceObject.cs new file mode 100644 index 000000000..38c73fbcf --- /dev/null +++ b/Packages/SLUnity/SLResourceObject.cs @@ -0,0 +1,188 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Superlazy +{ + public class SLResourceObject : MonoBehaviour + { + public Animator[] anims; + public Renderer[] renderers; + public ParticleSystem[] particles; + public TrailRenderer[] trails; + public SLStateController[] stateControllers; + public SLContextController[] contextControllers; + public float destroyDelay; + + private Dictionary transforms; // 자주 안쓰일듯해 필요할때 캐싱 + + public void Init() + { + anims = GetComponentsInChildren(); + renderers = GetComponentsInChildren().Where(r => r is MeshRenderer || r is SkinnedMeshRenderer).ToArray(); + particles = GetComponentsInChildren(); + trails = GetComponentsInChildren(); + stateControllers = GetComponentsInChildren(); + contextControllers = GetComponentsInChildren(); + + foreach (var a in anims) + { + a.keepAnimatorStateOnDisable = true; + a.updateMode = AnimatorUpdateMode.Normal; + a.cullingMode = AnimatorCullingMode.AlwaysAnimate; + } + + // TODO: destroyDelay 를 컨트롤하는 별도의 상수 개념 추가 + foreach (var t in trails) + { + destroyDelay = Mathf.Max(destroyDelay, t.time); + } + + foreach (var p in particles) + { + var main = p.main; + if (main.loop) continue; + var lt = main.startLifetime; + switch (main.startLifetime.mode) + { + case ParticleSystemCurveMode.Constant: + destroyDelay = Mathf.Max(destroyDelay, lt.constant); + break; + + case ParticleSystemCurveMode.TwoConstants: + destroyDelay = Mathf.Max(destroyDelay, lt.constantMax, lt.constantMin); + break; + + case ParticleSystemCurveMode.Curve: + case ParticleSystemCurveMode.TwoCurves: + destroyDelay = Mathf.Max(destroyDelay, lt.curveMultiplier * main.startLifetimeMultiplier); + break; + } + } + + foreach (var c in stateControllers) + { + c.Init(); + } + + foreach (var c in contextControllers) + { + c.Init(); + } + } + + public void OnEnable() + { + foreach (var r in renderers) + { + r.enabled = true; + } + + foreach (var p in particles) + { + p.Clear(); + p.Play(); + } + + foreach (var t in trails) + { + t.Clear(); + t.emitting = true; + } + + foreach (var c in stateControllers) + { + c.Clear(); + } + + foreach (var c in contextControllers) + { + c.Clear(); + } + } + + public void Destroy(bool force = false) + { + foreach (var r in renderers) + { + r.enabled = false; + } + + foreach (var p in particles) + { + p.Stop(); + } + + foreach (var t in trails) + { + t.emitting = false; + } + + foreach (var c in stateControllers) + { + c.Clear(); + } + + foreach (var c in contextControllers) + { + c.Clear(); + } + + if (force == false && destroyDelay > 0.0f && gameObject.activeInHierarchy) + { + StartCoroutine(DelayEnd()); + } + else + { + SLResources.DestroyInstance(this); + } + } + + private IEnumerator DelayEnd() + { + transform.SetParent(null, true); + yield return new WaitForSeconds(destroyDelay); + transform.localPosition = Vector3.zero; + transform.localRotation = Quaternion.identity; + transform.localScale = Vector3.one; + SLResources.DestroyInstance(this); + } + + public void SetKeyword(string state, bool enable = true) + { + foreach (var c in stateControllers) + { + c.EnableKeyword(state, enable); + } + } + + public void SetContext(SLEntity context) + { + foreach (var c in contextControllers) + { + c.SetContext(context); + } + } + + public Transform GetTransform(string name) + { + if (transforms == null) + { + transforms = new Dictionary(); + foreach (var t in GetComponentsInChildren()) + { + if (transforms.ContainsKey(t.name)) continue; + transforms[t.name] = t; + } + } + + if (transforms.ContainsKey(name)) + { + return transforms[name]; + } + + return transform; // 없다면 Root + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLResourceObject.cs.meta b/Packages/SLUnity/SLResourceObject.cs.meta new file mode 100644 index 000000000..ff7bd4c7b --- /dev/null +++ b/Packages/SLUnity/SLResourceObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f793fbf2fb02714bb5f8982d3419f2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLSceneController.cs b/Packages/SLUnity/SLSceneController.cs new file mode 100644 index 000000000..fa6b76f12 --- /dev/null +++ b/Packages/SLUnity/SLSceneController.cs @@ -0,0 +1,160 @@ +using Superlazy; +using System.Collections; +using UnityEngine; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.SceneManagement; + +public class SLSceneController : MonoBehaviour +{ + public static void Init() + { + inst = new GameObject("SceneController").AddComponent(); + } + + public static bool Loaded { get; private set; } = true; + private static SLSceneController inst; + + private SceneInstance oldScene; + private SceneInstance currentScene; + private bool setupEnd = false; + private bool activeEnd = false; + + private string scene = ""; + + public static void ChangeScene(string newScene) // 구버전 하위 호환성 + { + inst.SetupAndChange(newScene); + } + + public static void SetupScene(string newScene) + { + inst.Setup(newScene); + } + + public static void ChangeScene() + { + inst.Change(); + } + + private void Setup(string newScene) + { + if (newScene == scene) + { + return; + } + + if (Loaded == false) + { + SLLog.Error($"Already Load [{scene}] Can't Load [{newScene}]"); + return; + } + + scene = newScene; + Loaded = false; + setupEnd = false; + activeEnd = false; + + oldScene = currentScene; + currentScene = default; + + if (string.IsNullOrEmpty(newScene) == false) + { + var handler = SLResources.LoadScene(newScene, LoadSceneMode.Additive); + + handler.Completed += (op) => + { + currentScene = op.Result; + foreach (var rootObj in currentScene.Scene.GetRootGameObjects()) + { + rootObj.SetActive(false); + } + setupEnd = true; + }; + } + else + { + setupEnd = true; + } + } + + private void Change() + { + StartCoroutine(ChangeSceneCoroutine()); + } + + private IEnumerator ChangeSceneCoroutine() + { + yield return new WaitUntil(() => setupEnd); + + if (oldScene.Scene.IsValid()) + { + var deactiveHandler = SLResources.UnloadScene(oldScene); + + deactiveHandler.Completed += (op) => + { + oldScene = default; + }; + } + + if (currentScene.Scene.IsValid()) + { + var activeHandler = currentScene.ActivateAsync(); + activeHandler.completed += (op) => + { + foreach (var rootObj in currentScene.Scene.GetRootGameObjects()) + { + rootObj.SetActive(true); + } + activeEnd = true; + }; + } + else + { + //activeEnd = true; + } + + yield return new WaitUntil(() => oldScene.Scene.IsValid() == false && activeEnd); + + LightProbes.Tetrahedralize(); + + Loaded = true; + } + + private void SetupAndChange(string newScene) + { + if (newScene == scene) + { + return; + } + + if (Loaded == false) + { + SLLog.Error($"Already Load [{scene}] Can't Load [{newScene}]"); + return; + } + + StartCoroutine(ChangeRoutine(newScene)); + } + + private IEnumerator ChangeRoutine(string newScene) + { + Loaded = false; + if (string.IsNullOrEmpty(scene) == false) + { + yield return SLResources.UnloadScene(currentScene); + } + + scene = newScene; + + if (string.IsNullOrEmpty(scene) == false) + { + var handler = SLResources.LoadScene(scene, LoadSceneMode.Additive, true); + yield return handler; + currentScene = handler.Result; + } + + LightProbes.Tetrahedralize(); + + Loaded = true; + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLSceneController.cs.meta b/Packages/SLUnity/SLSceneController.cs.meta new file mode 100644 index 000000000..2deaa86e6 --- /dev/null +++ b/Packages/SLUnity/SLSceneController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: abc1374404c136148807b6d2e6fe2440 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLSound.cs b/Packages/SLUnity/SLSound.cs new file mode 100644 index 000000000..daa4edbab --- /dev/null +++ b/Packages/SLUnity/SLSound.cs @@ -0,0 +1,295 @@ +using Superlazy; +using System.Collections.Generic; +using UnityEngine; + +public class SLSound : SLGameComponent +{ + private static GameObject soundRoot; + + private static bool mute = false; + + // 재생 관리를 위한 큐 + private static readonly Dictionary> enableObjects = new Dictionary>(); + + // 페이드 + private static readonly List fades = new List(); + + private static readonly List removes = new List(); + + // 리소스 풀 + private static int unusedCount = 0; + + private static readonly Dictionary> unused = new Dictionary>(); + + // mute 정보 + private static readonly HashSet muteTagList = new HashSet(); + + private static readonly List currentFramePlays = new List(); + + private static readonly Dictionary delaySounds = new Dictionary(); + + private static AudioSource GetAudioSource(string clipName) + { + if (currentFramePlays.Contains(clipName)) return null; + + currentFramePlays.Add(clipName); + + AudioSource audioSource = null; + if (unused.ContainsKey(clipName) && unused[clipName].Count != 0) + { + audioSource = unused[clipName].Dequeue(); + --unusedCount; + } + else + { + //TODO : 추후 사운드도 ResourceManager 로 이관해야함 + var sound = SLResources.Load(clipName); + if (sound != null) + { + sound.name = clipName; + audioSource = soundRoot.AddComponent(); + audioSource.clip = sound; + } + } + + return audioSource; + } + + public static void MuteSounds(bool mute) + { + SLSound.mute = mute; + } + + public static void ClearPool() + { + foreach (var queue in unused) + { + foreach (var source in queue.Value) + { + Object.Destroy(source); + } + } + unused.Clear(); + unusedCount = 0; + } + + public static void PlaySound(string clipName, string tag = "Effect", bool loop = false, bool unique = false, bool reset = true, float volume = 1, float delay = 0) + { + if (string.IsNullOrEmpty(clipName)) return; + + if (clipName == "Off") return; // TODO: Off라는 이름의 사운드가 없어 임시 처리. 추후 수정 필요 + + if (soundRoot == null) return; + + if (tag == "BGM") + { + volume *= SLGame.Session["Option"]["Volume"]["BGM"] * 0.1f; + } + else + { + volume *= SLGame.Session["Option"]["Volume"]["SE"] * 0.1f; + } + + if (delay > 0) + { + SLEntity context = SLEntity.Empty; + context["Tage"] = tag; + context["Loop"] = loop; + context["Unique"] = unique; + context["Reset"] = reset; + context["Volume"] = volume; + context["Delay"] = delay; + delaySounds.Add(clipName, context); + return; + } + + var exist = false; + if (unique) + { + if (enableObjects.ContainsKey(tag)) + { + var stopList = new List(); + foreach (var source in enableObjects[tag]) + { + if (reset == false && source.clip.name == clipName) + { + exist = true; + source.volume = volume; + continue; + } + + if (source.loop) + { + fades.Add(source); + } + else + { + source.Stop(); + removes.Add(source); + } + stopList.Add(source); + } + foreach (var source in stopList) + { + enableObjects[tag].Remove(source); + } + } + } + if (exist) return; + if (tag != "BGM" && tag != "Weather" && IsMuteTag(tag)) return; + + if (enableObjects.ContainsKey(tag) && tag != "TextSound") + { + if (enableObjects[tag].Count > 4) return; + } + + var audioSource = GetAudioSource(clipName); + + if (audioSource != null) + { + // 여기서 각종 옵션을 제어한다. + { + audioSource.loop = loop; + audioSource.volume = volume; + audioSource.mute = IsMuteTag(tag); + } + audioSource.enabled = true; + audioSource.Play(); + + if (enableObjects.ContainsKey(tag) == false) + enableObjects[tag] = new List(); + enableObjects[tag].Add(audioSource); + } + } + + public static void StopSound(string tag) + { + if (enableObjects.ContainsKey(tag)) + { + foreach (var source in enableObjects[tag]) + { + if (source.loop) + { + fades.Add(source); + } + else + { + source.Stop(); + removes.Add(source); + } + } + enableObjects[tag].Clear(); + } + } + + public static void SetMute(string tag, bool mute) + { + if (mute) muteTagList.Add(tag); + else muteTagList.Remove(tag); + } + + private static bool IsMuteTag(string tag) + { + if (mute) return true; + + if (tag == "BGM" || tag == "Weather") + { + return muteTagList.Contains("BGM"); + } + else + { + return muteTagList.Contains("Effect"); + } + } + + public static void VolumeChange(float before, float next) + { + foreach (var clip in enableObjects["BGM"]) + { + clip.volume = before == 0f ? next * 0.1f : clip.volume * next / before; + } + } + + public override void Begin() + { + if (soundRoot == null) + { + soundRoot = new GameObject("SoundRoot"); + Object.DontDestroyOnLoad(soundRoot); + } + } + + public override void Update() + { + foreach (var sourceList in enableObjects) + { + foreach (var audioSource in sourceList.Value) + { + if (audioSource.clip.loadInBackground == false && audioSource.isPlaying == false) + { + removes.Add(audioSource); + } + else + { + audioSource.mute = IsMuteTag(sourceList.Key); + } + } + sourceList.Value.RemoveAll(u => u.clip.loadInBackground == false && u.isPlaying == false); + } + + foreach (var source in fades) + { + source.volume -= Time.unscaledDeltaTime; + if (source.volume <= 0) + { + source.Stop(); + removes.Add(source); + } + } + fades.RemoveAll(u => u.volume <= 0); + + foreach (var audioSource in removes) + { + var name = audioSource.clip.name; + + if (unused.ContainsKey(name) == false) + { + unused[name] = new Queue(); + } + unused[name].Enqueue(audioSource); + ++unusedCount; + audioSource.enabled = false; + } + removes.Clear(); + + if (unusedCount >= 30) + { + ClearPool(); + } + + if (delaySounds.Count > 0) + { + var removeDelaySounds = new List(); + foreach (var delaySound in delaySounds) + { + delaySound.Value["Delay"] -= Time.unscaledDeltaTime; + if (delaySound.Value["Delay"] <= 0) + { + var context = delaySound.Value; + PlaySound(delaySound.Key, context["Tag"], context["Loop"], context["Unique"], context["Reset"], context["Volume"]); + removeDelaySounds.Add(delaySound.Key); + } + } + foreach (var key in removeDelaySounds) + { + delaySounds.Remove(key); + } + } + + currentFramePlays.Clear(); + } + + public override void End() + { + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLSound.cs.meta b/Packages/SLUnity/SLSound.cs.meta new file mode 100644 index 000000000..80fc1a1d9 --- /dev/null +++ b/Packages/SLUnity/SLSound.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23c5c799fa084534ba4b33858a61377b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLStateController.cs b/Packages/SLUnity/SLStateController.cs new file mode 100644 index 000000000..d0835c4d3 --- /dev/null +++ b/Packages/SLUnity/SLStateController.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace Superlazy +{ + public abstract class SLStateController : MonoBehaviour + { + public abstract void Init(); + + public abstract void Clear(); + + public abstract void EnableKeyword(string quest, bool enable); + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLStateController.cs.meta b/Packages/SLUnity/SLStateController.cs.meta new file mode 100644 index 000000000..d9447e47e --- /dev/null +++ b/Packages/SLUnity/SLStateController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ff9a45a2b64588469a47677133d63e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLString.cs b/Packages/SLUnity/SLString.cs new file mode 100644 index 000000000..2a2eed626 --- /dev/null +++ b/Packages/SLUnity/SLString.cs @@ -0,0 +1,394 @@ +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +using Superlazy; + +public static class SLString +{ + private static readonly List tags = new List() + { + new char[]{ 's', 'c' }, + new char[]{ '/', 's', 'c' }, + new char[]{ 's', 'c', 'o', 'l', 'o', 'r' }, + new char[]{ '/', 's', 'c', 'o', 'l', 'o', 'r' }, + new char[]{ 'n', 'l', }, + new char[]{ 's', 't', 'r' } + }; + + private static readonly List koreanPostpositionStrTags = new List() + { + new string[] { "을(를)", "을", "를" }, + new string[] { "을/를", "을", "를" }, + new string[] { "이(가)", "이", "가" }, + new string[] { "이/가", "이", "가" }, + new string[] { "은(는)", "은", "는" }, + new string[] { "은/는", "은", "는" }, + new string[] { "과(와)", "과", "와" }, + new string[] { "과/와", "과", "와" } + }; + + private static readonly string englishPluralStrTags = "(s)"; + + public static string GetString(string str, SLEntity context) + { + return Translation(str, context); + } + + private static string Translation(string str, SLEntity context) + { + if (string.IsNullOrEmpty(str)) return string.Empty; + + if (str.IsLeft("STR_") == false) return Format(str, context); + + var strKey = SLSystem.Data["Strings"][str]; + var lang = SLGame.Session["Option"]["Language"]; + + if (strKey[lang]) + { + return Format(strKey[lang], context); + } + else if (strKey["EN"]) + { + return Format(strKey["EN"], context); + } + else if (strKey["KR"]) + { + return Format(strKey["KR"], context); + } + else + { + return Format(str, context); + } + } + + private static string Format(string value, SLEntity context) + { + var tagStart = value.LastIndexOf('{', value.Length - 1); + + if (tagStart != -1) + { + var tagEnd = value.IndexOf('}', tagStart); + if (tagEnd == -1) + { + SLLog.Error($"Tagging Error [{value}]"); + return value; + } + + var sb = new StringBuilder(value); + + var tagParamIdx = value.IndexOf(':', tagStart + 1, tagEnd - tagStart - 1); + + string tagAttribute; + string tagType; + if (tagParamIdx != -1) + { + tagAttribute = sb.ToString(tagStart + 1, tagParamIdx - tagStart - 1); + tagType = sb.ToString(tagParamIdx + 1, tagEnd - tagParamIdx - 1); + } + else + { + tagAttribute = sb.ToString(tagStart + 1, tagEnd - tagStart - 1); + tagType = string.Empty; + } + var format = Translation(SLTag.Apply(context.Get(tagAttribute), tagType), context); + + sb.Remove(tagStart, tagEnd - tagStart + 1); + sb.Insert(tagStart, format); + return Format(sb.ToString(), context); // 태그를 반복적으로 적용 + } + else + { + return CustomTag(value, context); + } + } + + private static string CustomTag(string str, SLEntity context) + { + if (string.IsNullOrEmpty(str)) return str; + + var sb = new StringBuilder(GetTagApplyString(str, context)); + + return PostPositionCheck(sb); + } + + private static string GetTagApplyString(string str, SLEntity context) + { + if (string.IsNullOrEmpty(str)) return str; + + var tagStart = str.LastIndexOf('<', str.Length - 1); + + var hasTag = tagStart != -1; + // end + + if (hasTag == false) + { + return str; + } + + var tagEnd = str.IndexOf('>', tagStart); + if (tagEnd == -1) + { + SLLog.Error($"Tagging Error [{str}]"); + return str; + } + + var sb = new StringBuilder(str); + + if (TagCheck(sb, tagStart, tagEnd, tags[0])) + { + var colorTag = SLSystem.Data["SpecialColors"][sb.ToString(tagStart + 4, tagEnd - tagStart - 4)].ToString(); + sb.Remove(tagStart + 1, tagEnd - tagStart - 1); + sb.Insert(tagStart + 1, colorTag); + sb.Insert(tagStart + 1, "color="); + } + else if (TagCheck(sb, tagStart, tagEnd, tags[1])) + { + sb.Remove(tagStart + 2, tagEnd - tagStart - 2); + sb.Insert(tagStart + 2, "color"); + } + else if (TagCheck(sb, tagStart, tagEnd, tags[2])) + { + var colorTag = SLSystem.Data["SpecialColors"][sb.ToString(tagStart + 8, tagEnd - tagStart - 8)].ToString(); + sb.Remove(tagStart + 1, tagEnd - tagStart - 1); + sb.Insert(tagStart + 1, colorTag); + sb.Insert(tagStart + 1, "color="); + } + else if (TagCheck(sb, tagStart, tagEnd, tags[3])) + { + sb.Remove(tagStart + 2, tagEnd - tagStart - 2); + sb.Insert(tagStart + 2, "color"); + } + else if (TagCheck(sb, tagStart, tagEnd, tags[4])) + { + sb.Remove(tagStart, tagEnd - tagStart + 1); + sb.Insert(tagStart, "\n"); + } + else if (TagCheck(sb, tagStart, tagEnd, tags[5])) + { + var newString = sb.ToString(tagStart + 5, tagEnd - tagStart - 5); + + sb.Remove(tagStart, tagEnd - tagStart + 1); + sb.Insert(tagStart, Translation(newString, context)); + } + + var left = GetTagApplyString(sb.ToString(0, tagStart), context); // 태그 반복 + sb.Remove(0, tagStart); + sb.Insert(0, left); + + return sb.ToString(); + } + + private static string PostPositionCheck(StringBuilder sb) + { + var lang = SLGame.Session["Option"]["Language"]; + if (lang == "KR") + { + foreach (var tag in koreanPostpositionStrTags) + { + int index = LastIndexOf(sb, tag[0]); + while (index != -1) + { + // index가 0보다 작으면 이전 문자가 없으므로 안전하게 체크 + if (index - 1 < 0) + break; + + char priorWord = sb[index - 1]; + string correction = HasEndConsonant(priorWord) ? tag[1] : tag[2]; + int tagLength = tag[0].Length; + + sb.Remove(index, tagLength); + sb.Insert(index, correction); + + // sb를 직접 검색하여 갱신 + index = LastIndexOf(sb, tag[0]); + } + } + } + else if (lang == "EN") + { + int index = LastIndexOf(sb, englishPluralStrTags); + while (index != -1) + { + int blankEndIndex = LastIndexOf(sb, ' ', index - 1); + int blankStartIndex = LastIndexOf(sb, ' ', blankEndIndex - 1); + if (blankEndIndex == -1 || blankStartIndex == -1) + break; + + string numberStr = Substring(sb, blankStartIndex + 1, blankEndIndex - blankStartIndex - 1); + + // 공백 및 기타 whitespace 처리 + numberStr = Regex.Replace(numberStr, @"\s+", " "); + int blankIndex = numberStr.LastIndexOf(' '); + if (blankIndex != -1) + { + numberStr = numberStr.Substring(blankIndex + 1); + } + + bool plural; + string numberStrLower = numberStr.ToLower(); + if (numberStrLower == "one" || numberStrLower == "a") + { + plural = false; + } + else + { + if (!int.TryParse(numberStr, out var number)) + { + plural = true; + } + else + { + plural = number != 1; + } + } + + sb.Remove(index, englishPluralStrTags.Length); + if (plural) + { + sb.Insert(index, 's'); + } + + index = LastIndexOf(sb, englishPluralStrTags); + } + } + + return ColorTagCheck(sb); + } + + private static bool HasEndConsonant(char word) + { + if (word < 0xAC00) return false; + return (word - 0xAC00) % 28 + 0x11a7 != 4519; + } + + private static bool TagCheck(StringBuilder sb, int tagStart, int tagEnd, char[] tag) + { + var cnt = tag.Length; + if (tagEnd - tagStart - 1 < tag.Length) return false; + for (var i = 0; i < cnt; ++i) + { + if (sb[i + tagStart + 1] != tag[i] && sb[i + tagStart + 1] != char.ToUpper(tag[i])) return false; + } + + return true; + } + + private static string ColorTagCheck(StringBuilder sb) + { + int bracketStart; + var currentSearchPosition = 0; + + while (currentSearchPosition < sb.Length && (bracketStart = IndexOf(sb, '[', currentSearchPosition)) != -1) + { + var bracketEnd = IndexOf(sb, ']', bracketStart); + if (bracketEnd == -1) + { + SLLog.Error($"Bracket Tagging Error [{sb}]"); + break; + } + + var colorCode = SLSystem.Data["SpecialColors"]["Default"]; + + var splitEnd = IndexOf(sb, '|', bracketStart); + if (splitEnd == -1 || splitEnd > bracketEnd) // 구분선이 없다면 + { + splitEnd = bracketStart; + } + else + { + colorCode = SLSystem.Data["SpecialColors"][sb.ToString(bracketStart + 1, splitEnd - bracketStart - 1)]; + } + + var formattedText = $"[{sb.ToString(splitEnd + 1, bracketEnd - splitEnd - 1)}]"; + + sb.Remove(bracketStart, bracketEnd - bracketStart + 1); + sb.Insert(bracketStart, formattedText); + + currentSearchPosition = bracketStart + formattedText.Length; + } + return sb.ToString(); + } + + public static List GetTags(string text, SLEntity context) + { + var list = new List(); + int bracketStart; + var currentSearchPosition = 0; + + text = GetString(text, context); + + while (currentSearchPosition < text.Length && (bracketStart = text.IndexOf('[', currentSearchPosition)) != -1) + { + var bracketEnd = text.IndexOf(']', bracketStart); + if (bracketEnd == -1) + { + SLLog.Error($"Bracket Tagging Error [{text}]"); + break; + } + + var originalText = text.Substring(bracketStart + 1, bracketEnd - bracketStart - 1); + + if (originalText.Contains('|')) // 태그붙음 + { + originalText = originalText.Substring(originalText.IndexOf('|') + 1); + } + + var tagID = Regex.Replace(originalText, @"[0-9\s!\""#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~×]", ""); // TODO: 추후에는 실제 태그 ID 변경 + + if (string.IsNullOrEmpty(tagID) == false) + { + var tag = SLSystem.Data["Tags"][tagID]; + if (tag["Desc"]) + { + list.Add(tagID); + } + } + + currentSearchPosition = bracketStart + bracketEnd - bracketStart + 1; + } + return list; + } + + private static int LastIndexOf(StringBuilder sb, string value) + { + if (value.Length == 0) return sb.Length; + for (int i = sb.Length - value.Length; i >= 0; i--) + { + bool found = true; + for (int j = 0; j < value.Length; j++) + { + if (sb[i + j] != value[j]) + { + found = false; + break; + } + } + if (found) return i; + } + return -1; + } + + private static int IndexOf(StringBuilder sb, char value, int startIndex = 0) + { + for (int i = startIndex; i < sb.Length; i++) + { + if (sb[i] == value) + return i; + } + return -1; + } + + private static int LastIndexOf(StringBuilder sb, char c, int startIndex) + { + for (int i = startIndex; i >= 0; i--) + { + if (sb[i] == c) return i; + } + return -1; + } + + private static string Substring(StringBuilder sb, int start, int length) + { + return sb.ToString(start, length); + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLString.cs.meta b/Packages/SLUnity/SLString.cs.meta new file mode 100644 index 000000000..1d943e436 --- /dev/null +++ b/Packages/SLUnity/SLString.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a0e37df2d608964cb496d02386afcc1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLTag.cs b/Packages/SLUnity/SLTag.cs new file mode 100644 index 000000000..f9d81e792 --- /dev/null +++ b/Packages/SLUnity/SLTag.cs @@ -0,0 +1,345 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Superlazy; +using UnityEngine; + +public abstract class SLTag +{ + private static Dictionary formats; + + public static void Init(IEnumerable formats = null) + { + if (SLTag.formats != null) return; + + if (formats == null) formats = Enumerable.Empty(); + + SLTag.formats = new Dictionary(); + + foreach (var format in formats) + { + if (SLTag.formats.ContainsKey(format.Tag)) + { + SLLog.Warn($"Options Duplicated{SLTag.formats[format.Tag]}, {format} : {format.Tag}"); + } + + SLTag.formats[format.Tag] = format; + } + } + + public static string Apply(SLEntity value, string tagType) + { + if (formats == null) return value.ToString(); + if (formats.ContainsKey(tagType)) + { + return formats[tagType].GetValue(value); + } + + return value.ToString(); + } + + public abstract string GetValue(SLEntity value); + + public abstract string Tag { get; } +} + +public class SLTagDefault : SLTag +{ + public override string Tag => string.Empty; + + public override string GetValue(SLEntity value) + { + return value; + } +} + +public class SLSecond : SLTag +{ + public override string Tag => "S"; + + public override string GetValue(SLEntity value) + { + return (Mathf.FloorToInt(value / 6.0f) * 0.1f).ToString(); + } +} + +public class SLRemainTime : SLTag +{ + public override string Tag => "RT"; + + public override string GetValue(SLEntity value) + { + var date = value.ToDateTime(); + + var delta = date - SLSystem.Now; + + if (delta.TotalDays >= 1) + { + return $"{delta.Days}"; + } + else if (delta.Hours >= 1) + { + return $"{delta.Hours}"; + } + else if (delta.Minutes >= 1) + { + return $"{delta.Minutes}"; + } + else + { + return $"{delta.Seconds}"; + } + } +} + +//} + +//public class SLMinute : SLStringFormat +//{ +// public override string Tag => "M"; + +// public override string GetValue(SLEntity value) +// { +// return SLMath.Ceiling(value / 60.0); +// } +//} + +//public class SLHour : SLStringFormat +//{ +// public override string Tag => "H"; + +// public override string GetValue(SLEntity value) +// { +// return SLMath.Ceiling(value / 60.0 / 60.0); +// } +//} + +//public class SLStringRoughAgoTime : SLStringFormat +//{ +// public override string Tag => "RAT"; + +// public override string GetValue(SLEntity value) +// { +// var entity = SLEntity.Empty; + +// if (value <= 0) +// { +// entity["Value"] = 0; +// return ""; +// } + +// var delta = SLSystem.Now - value.ToDateTime(); + +// var result = ""; + +// if (delta.TotalDays >= 1) +// { +// entity["Value"] = SLMath.Floor(delta.TotalDays); +// result = SLSystem.GetString("STR_DayAgo", entity); +// } +// else if (delta.Hours >= 1) +// { +// entity["Value"] = delta.Hours; +// result = SLSystem.GetString("STR_HourAgo", entity); +// } +// else if (delta.Minutes >= 1) +// { +// entity["Value"] = delta.Minutes; +// result = SLSystem.GetString("STR_MinuteAgo", entity); +// } +// else +// { +// entity["Value"] = delta.Seconds; +// result = SLSystem.GetString("STR_LessThanMinuteAgo", entity); +// } + +// return result; +// } +//} + +//public class SLStringRoughLeftTime : SLStringFormat +//{ +// public override string Tag => "RLT"; + +// public override float UpdateTick => 60.0f; + +// public override string GetValue(SLEntity value) +// { +// var entity = SLEntity.Empty; + +// if (value <= 0) +// { +// entity["Value"] = 0; +// return SLSystem.GetString("STR_MinuteLeft", SLEntity.Empty); +// } + +// var delta = value.ToDateTime() - SLSystem.Now; + +// var result = ""; + +// if (delta.TotalDays >= 1) +// { +// entity["Value"] = SLMath.Floor(delta.TotalDays); +// result = SLSystem.GetString("STR_DayLeft", entity); +// } +// else if (delta.Hours >= 1) +// { +// entity["Value"] = delta.Hours; +// result = SLSystem.GetString("STR_HourLeft", entity); +// } +// else if (delta.Minutes >= 1) +// { +// entity["Value"] = delta.Minutes; +// result = SLSystem.GetString("STR_MinuteLeft", entity); +// } +// else +// { +// entity["Value"] = delta.Seconds; +// result = SLSystem.GetString("STR_LessThanMinuteLeft", entity); +// } + +// return result; +// } +//} + +public class SLStringLocalDate : SLTag +{ + public override string Tag => "DATE"; + + public override string GetValue(SLEntity value) + { + return value.ToLocalDateTime().ToString("yyyy.MM.dd"); + } +} + +public class SLStringLocalTime : SLTag +{ + public override string Tag => "TIME"; + + public override string GetValue(SLEntity value) + { + return value.ToLocalDateTime().ToString("HH:mm"); + } +} + +public class SLStringLocalDateTime : SLTag +{ + public override string Tag => "LDT"; + + public override string GetValue(SLEntity value) + { + return value.ToLocalDateTime().ToString("yyyy.MM.dd HH:mm"); + } +} + +public class SLStringAbsoluteNumber : SLTag +{ + public override string Tag => "ABS"; + + public override string GetValue(SLEntity value) + { + return string.Format("{0:N0}", Math.Abs(value)); + } +} + +public class SLStringNaturalNumber : SLTag +{ + public override string Tag => "NN"; + + public override string GetValue(SLEntity value) + { + return string.Format("{0:N0}", (double)value); + } +} + +public class SLStringSignNumber : SLTag +{ + public override string Tag => "SN"; + + public override string GetValue(SLEntity value) + { + if (value >= 0) + { + return string.Format("+{0:N0}", Math.Abs(value)); + } + else + { + return string.Format("-{0:N0}", Math.Abs(value)); + } + } +} + +public class SLStringSignNumberPercent : SLTag +{ + public override string Tag => "SNP"; + + public override string GetValue(SLEntity value) + { + if (value >= 0) + { + return string.Format("+{0:N0}%", Math.Abs(value * 100.0)); + } + else + { + return string.Format("-{0:N0}%", Math.Abs(value * 100.0)); + } + } +} + +public class SLStringToRoman : SLTag +{ + public override string Tag => "RM"; + + public override string GetValue(SLEntity value) + { + return value.RomanNumString(); + } +} + +public static class SLRomanNumber +{ + public static string RomanNumString(this SLEntity val) + { + return ((int)val).RomanNumString(); + } + + public static string RomanNumString(this int value) + { + if (value >= 1000) return "M" + RomanNumString(value - 1000); + if (value >= 900) return "CM" + RomanNumString(value - 900); + if (value >= 500) return "D" + RomanNumString(value - 500); + if (value >= 400) return "CD" + RomanNumString(value - 400); + if (value >= 100) return "C" + RomanNumString(value - 100); + if (value >= 90) return "XC" + RomanNumString(value - 90); + if (value >= 50) return "L" + RomanNumString(value - 50); + if (value >= 40) return "XL" + RomanNumString(value - 40); + if (value >= 10) return "X" + RomanNumString(value - 10); + if (value >= 9) return "IX" + RomanNumString(value - 9); + if (value >= 5) return "V" + RomanNumString(value - 5); + if (value >= 4) return "IV" + RomanNumString(value - 4); + if (value >= 1) return "I" + RomanNumString(value - 1); + return string.Empty; + } +} + +public class SLRound1Value : SLTag +{ + public override string Tag => "R1"; + + public override string GetValue(SLEntity value) + { + return MathF.Round(value, 1).ToString("0.0"); + } +} + +// Option + +public class LanguageName : SLTag +{ + public override string Tag => "LANGUAGENAME"; + + public override string GetValue(SLEntity value) + { + return SLSystem.Data["Languages"][value]["Name"]; + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLTag.cs.meta b/Packages/SLUnity/SLTag.cs.meta new file mode 100644 index 000000000..150cd34b8 --- /dev/null +++ b/Packages/SLUnity/SLTag.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b8fe98f09de6ec4bbab6d80895e7724 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLUI.meta b/Packages/SLUnity/SLUI.meta new file mode 100644 index 000000000..00865da07 --- /dev/null +++ b/Packages/SLUnity/SLUI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e939ddad63a1cba41bf419ac88252083 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/SLUnity/SLUI/SLUI2DPosition.cs b/Packages/SLUnity/SLUI/SLUI2DPosition.cs new file mode 100644 index 000000000..5c23cc9ad --- /dev/null +++ b/Packages/SLUnity/SLUI/SLUI2DPosition.cs @@ -0,0 +1,55 @@ +using UnityEngine; + +namespace Superlazy.UI +{ + public class SLUI2DPosition : SLUIComponent + { + public string bind = "Position"; + public bool screenPos = false; + + private RectTransform t; + private Canvas canvas; + private RectTransform parent; + + protected override void Validate() + { + t = GetComponent(); + parent = t.parent as RectTransform; + canvas = GetComponentInParent(); + } + + protected override void Init() + { + } + + protected override void Enable() + { + SLGame.AddNotify(bindParent.BindPath.CombinePath(bind), OnChange); + } + + protected override void Disable() + { + SLGame.RemoveNotify(bindParent.BindPath.CombinePath(bind), OnChange); + } + + private void OnChange() + { + if (bindParent.Active == false) + return; + + if (screenPos) + { + var pos = SLGame.SessionGet(bindParent.BindPath).Get(bind).ToVector2(); + + if (RectTransformUtility.ScreenPointToLocalPointInRectangle(parent, pos, canvas.worldCamera, out var localPoint)) + { + t.anchoredPosition = localPoint; + } + } + else + { + t.anchoredPosition = SLGame.SessionGet(bindParent.BindPath).Get(bind).ToVector2(); + } + } + } +} \ No newline at end of file diff --git a/Packages/SLUnity/SLUI/SLUI2DPosition.cs.meta b/Packages/SLUnity/SLUI/SLUI2DPosition.cs.meta new file mode 100644 index 000000000..c59af16d2 --- /dev/null +++ b/Packages/SLUnity/SLUI/SLUI2DPosition.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b862e57d3f12cc94b88bdf98e9025af6 \ No newline at end of file diff --git a/Packages/SLUnity/SLUI/SLUIButton.cs b/Packages/SLUnity/SLUI/SLUIButton.cs new file mode 100644 index 000000000..55b25e4bf --- /dev/null +++ b/Packages/SLUnity/SLUI/SLUIButton.cs @@ -0,0 +1,351 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using TMPro; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace Superlazy.UI +{ + [RequireComponent(typeof(Button))] + public class SLUIButton : SLUIComponent, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, ISelectHandler, IDeselectHandler + { + public static Material grayMaterial; + public static Material grayTextMaterial; + public static DateTime globalClickedTime = DateTime.MinValue; + public static PointerEventData currentPoint; + + public string command; + public bool useGrayScale; + public bool focus; + public string focusBind; + public bool selectIsHover; + public bool fastClick; + public SLValueComparison comparison; + + public string clickSound = "SoundEffect/SE_UI_click"; + + [NonSerialized] + public Button button; + + private Graphic[] childImages; + private Color[] childImageColors; // TODO: SLUIColorSelect 대비해야함 + private TextMeshProUGUI[] childTexts; + private Color[] childTextColors; + private DateTime clickedTime = DateTime.MinValue; + + private enum ButtonState + { + Normal, + Highlighted, + Pressed, + Disabled + } + + private ButtonState currentButtonState; + + private bool isPointerInside; + private bool isPointerDown; + + protected override void Validate() + { + button = GetComponent