using System; using Random = UnityEngine.Random; using System.Collections.Generic; using System.Threading.Tasks; using System.Linq; using System.Reflection; using System.Text; using UnityEngine; using SynapticAIPro; using UnityEngine.UI; using UnityEngine.EventSystems; using TMPro; #if UNITY_EDITOR using UnityEditor; using UnityEditor.Rendering; #endif using System.IO; using Newtonsoft.Json; using UnityEngine.Profiling; using SynapticPro.GOAP; using SynapticPro.BehaviorTree; using Synaptic.Editor; #if ENABLE_INPUT_SYSTEM && INPUT_SYSTEM_PACKAGE using UnityEngine.InputSystem; #endif // VFX Graph Support - requires com.unity.visualeffectgraph package #if VFX_GRAPH_PACKAGE using UnityEngine.VFX; using UnityEditor.VFX; #endif namespace SynapticPro { public partial class NexusUnityExecutor { private GameObject lastCreatedObject; private List createdObjects = new List(); // Cached rendering pipeline detection private static string _cachedPipeline = null; // Scene snapshot cache for incremental updates private static Dictionary sceneSnapshots = new Dictionary(); private class SceneSnapshot { public DateTime timestamp; public HashSet gameObjectIds; public Dictionary gameObjectHashes; } // Log buffer for real-time log collection private static List logBuffer = new List(); private static bool isLogCallbackRegistered = false; private static readonly int maxLogBufferSize = 1000; // File read tracking - files must be read before editing (like Claude Code) private static HashSet readFiles = new HashSet(); private static Dictionary readFileTimestamps = new Dictionary(); private static readonly TimeSpan readFileCacheExpiry = TimeSpan.FromMinutes(30); // Cache expires after 30 minutes // Screenshot capture state (using EditorPrefs for persistence across domain reload) private static string PendingScreenshotPath { get => EditorPrefs.GetString("NexusExecutor_PendingScreenshotPath", null); set => EditorPrefs.SetString("NexusExecutor_PendingScreenshotPath", value ?? ""); } private static bool IsCapturingScreenshot { get => EditorPrefs.GetBool("NexusExecutor_IsCapturingScreenshot", false); set => EditorPrefs.SetBool("NexusExecutor_IsCapturingScreenshot", value); } private static bool WasPlayingBeforeCapture { get => EditorPrefs.GetBool("NexusExecutor_WasPlayingBeforeCapture", false); set => EditorPrefs.SetBool("NexusExecutor_WasPlayingBeforeCapture", value); } private static string ScreenshotCaptureResult { get => EditorPrefs.GetString("NexusExecutor_ScreenshotCaptureResult", null); set => EditorPrefs.SetString("NexusExecutor_ScreenshotCaptureResult", value ?? ""); } private static string PendingRegionParams { get => EditorPrefs.GetString("NexusExecutor_PendingRegionParams", null); set => EditorPrefs.SetString("NexusExecutor_PendingRegionParams", value ?? ""); } private static bool IsCapturingRegion { get => EditorPrefs.GetBool("NexusExecutor_IsCapturingRegion", false); set => EditorPrefs.SetBool("NexusExecutor_IsCapturingRegion", value); } private struct LogEntry { public string condition; public string stackTrace; public LogType type; public DateTime timestamp; } static NexusUnityExecutor() { // Register log callback if (!isLogCallbackRegistered) { Application.logMessageReceived += OnLogMessageReceived; isLogCallbackRegistered = true; SynLog.Info("[NexusConsole] Log callback registered for real-time log collection"); } #if UNITY_EDITOR // Re-register screenshot callback after domain reload EditorApplication.playModeStateChanged -= OnPlayModeStateChangedForScreenshot; EditorApplication.playModeStateChanged += OnPlayModeStateChangedForScreenshot; if (IsCapturingScreenshot || IsCapturingRegion) { var captureType = IsCapturingRegion ? "Region" : "Screenshot"; var capturePath = IsCapturingRegion ? "pending" : PendingScreenshotPath; SynLog.Info($"[NexusExecutor] {captureType} capture state restored after domain reload. Path: {capturePath}"); SynLog.Info($"[NexusExecutor] Current play mode state: {(EditorApplication.isPlaying ? "Playing" : "Not Playing")}"); // If we're already in play mode, we missed the EnteredPlayMode event // Start 120-frame wait for rendering to stabilize if (EditorApplication.isPlaying) { SynLog.Info($"[NexusExecutor] Already in Play mode, starting 120-frame wait (~2 seconds) for {captureType} capture..."); screenshotFrameCounter = 0; screenshotUpdateHandler = ScreenshotFrameUpdate; EditorApplication.update += screenshotUpdateHandler; } } #endif } private static void OnLogMessageReceived(string condition, string stackTrace, LogType type) { var entry = new LogEntry { condition = condition, stackTrace = stackTrace, type = type, timestamp = DateTime.Now }; logBuffer.Add(entry); // Buffer size limit if (logBuffer.Count > maxLogBufferSize) { logBuffer.RemoveRange(0, logBuffer.Count - maxLogBufferSize); } } public async Task ExecuteOperation(NexusUnityOperation operation) { try { switch (operation.type.ToUpper()) { case "CREATE_GAMEOBJECT": return CreateGameObject(operation.parameters); case "UPDATE_GAMEOBJECT": return UpdateGameObject(operation.parameters); case "DELETE_GAMEOBJECT": return DeleteGameObject(operation.parameters); case "INSTANTIATE_PREFAB": return InstantiatePrefab(operation.parameters); case "SET_TRANSFORM": return SetTransform(operation.parameters); case "ADD_COMPONENT": return AddComponent(operation.parameters); case "UPDATE_COMPONENT": return UpdateComponent(operation.parameters); case "SET_PROPERTY": return SetProperty(operation.parameters); case "CREATE_UI": return CreateUI(operation.parameters); case "SETUP_UI_CANVAS": return SetupUICanvas(operation.parameters); case "SET_UI_ANCHOR": return SetUIAnchor(operation.parameters); case "CREATE_SCRIPT": return await CreateScript(operation); case "MODIFY_SCRIPT": SynLog.Info($"[NexusExecutor] Executing MODIFY_SCRIPT with parameters: {JsonConvert.SerializeObject(operation.parameters)}"); return ModifyScript(operation.parameters); case "EDIT_SCRIPT_LINE": SynLog.Info($"[NexusExecutor] Executing EDIT_SCRIPT_LINE with parameters: {JsonConvert.SerializeObject(operation.parameters)}"); return EditScriptLine(operation.parameters); case "ADD_SCRIPT_METHOD": SynLog.Info($"[NexusExecutor] Executing ADD_SCRIPT_METHOD with parameters: {JsonConvert.SerializeObject(operation.parameters)}"); return AddScriptMethod(operation.parameters); case "UPDATE_SCRIPT_VARIABLE": SynLog.Info($"[NexusExecutor] Executing UPDATE_SCRIPT_VARIABLE with parameters: {JsonConvert.SerializeObject(operation.parameters)}"); return UpdateScriptVariable(operation.parameters); case "READ_SCRIPT": return ReadScript(operation.parameters); case "GREP_SCRIPTS": return GrepScripts(operation.parameters); case "READ_SCRIPT_RANGE": return ReadScriptRange(operation.parameters); case "SEARCH_CODE": return SearchCode(operation.parameters); case "LIST_SCRIPT_FILES": return ListScriptFiles(operation.parameters); case "ANALYZE_SCRIPT": return AnalyzeScript(operation.parameters); case "ANALYZE_PERFORMANCE": return AnalyzePerformance(operation.parameters); case "CHECK_BEST_PRACTICES": return CheckBestPractices(operation.parameters); case "MONITOR_RUNTIME_ERRORS": return MonitorRuntimeErrors(operation.parameters); case "AUTO_ATTACH_UI": return AutoAttachUI(operation.parameters); case "CREATE_PREFAB": return CreatePrefab(operation.parameters); case "SETUP_PHYSICS": return SetupPhysics(operation.parameters); case "CREATE_MATERIAL": return CreateMaterial(operation.parameters); case "SETUP_CAMERA": return SetupCamera(operation.parameters); // Cinemachine Operations case "CREATE_VIRTUAL_CAMERA": return NexusCinemachineHelper.CreateVirtualCamera(operation.parameters); case "CREATE_FREELOOK_CAMERA": return NexusCinemachineHelper.CreateFreeLookCamera(operation.parameters); case "SETUP_CINEMACHINE_BRAIN": return NexusCinemachineHelper.SetupCinemachineBrain(operation.parameters); case "UPDATE_VIRTUAL_CAMERA": return NexusCinemachineHelper.UpdateVirtualCamera(operation.parameters); case "CREATE_DOLLY_TRACK": return NexusCinemachineHelper.CreateDollyTrack(operation.parameters); case "ADD_COLLIDER_EXTENSION": return NexusCinemachineHelper.AddColliderExtension(operation.parameters); case "ADD_CONFINER_EXTENSION": return NexusCinemachineHelper.AddConfinerExtension(operation.parameters); case "CREATE_STATE_DRIVEN_CAMERA": return NexusCinemachineHelper.CreateStateDrivenCamera(operation.parameters); case "CREATE_CLEAR_SHOT_CAMERA": return NexusCinemachineHelper.CreateClearShotCamera(operation.parameters); case "CREATE_IMPULSE_SOURCE": return NexusCinemachineHelper.CreateImpulseSource(operation.parameters); case "ADD_IMPULSE_LISTENER": return NexusCinemachineHelper.AddImpulseListener(operation.parameters); case "CREATE_BLEND_LIST_CAMERA": return NexusCinemachineHelper.CreateBlendListCamera(operation.parameters); case "CREATE_TARGET_GROUP": return NexusCinemachineHelper.CreateTargetGroup(operation.parameters); case "ADD_TARGET_TO_GROUP": return NexusCinemachineHelper.AddTargetToGroup(operation.parameters); case "SET_CAMERA_PRIORITY": return NexusCinemachineHelper.SetCameraPriority(operation.parameters); case "SET_CAMERA_ENABLED": return NexusCinemachineHelper.SetCameraEnabled(operation.parameters); case "CREATE_MIXING_CAMERA": return NexusCinemachineHelper.CreateMixingCamera(operation.parameters); case "UPDATE_CAMERA_TARGET": return NexusCinemachineHelper.UpdateCameraTarget(operation.parameters); case "UPDATE_BRAIN_BLEND_SETTINGS": return NexusCinemachineHelper.UpdateBrainBlendSettings(operation.parameters); case "GET_ACTIVE_CAMERA_INFO": return NexusCinemachineHelper.GetActiveCameraInfo(operation.parameters); case "CREATE_PARTICLE_SYSTEM": return CreateParticleSystem(operation.parameters); case "SETUP_MATERIAL": return SetupMaterial(operation.parameters); case "SETUP_NAVMESH": return SetupNavMesh(operation.parameters); case "CREATE_AUDIO_MIXER": return CreateAudioMixer(operation.parameters); // New Audio tools case "CREATE_AUDIO_SOURCE": return CreateAudioSource(operation.parameters); case "SETUP_3D_AUDIO": return Setup3DAudio(operation.parameters); case "CREATE_AUDIO_CLIP": return CreateAudioClip(operation.parameters); case "SETUP_AUDIO_EFFECTS": return SetupAudioEffects(operation.parameters); case "CREATE_REVERB_ZONES": return CreateReverbZones(operation.parameters); case "SETUP_AUDIO_OCCLUSION": return SetupAudioOcclusion(operation.parameters); case "CREATE_ADAPTIVE_MUSIC": return CreateAdaptiveMusic(operation.parameters); case "SETUP_AUDIO_TRIGGERS": return SetupAudioTriggers(operation.parameters); case "CREATE_SOUND_POOLS": return CreateSoundPools(operation.parameters); case "CREATE_AUDIO_MIXING": return CreateAudioMixing(operation.parameters); case "SETUP_SPATIAL_AUDIO": return SetupSpatialAudio(operation.parameters); case "CREATE_AUDIO_VISUALIZATION": return CreateAudioVisualization(operation.parameters); // ===== Advanced Input Tools ===== case "SETUP_CUSTOM_INPUT": return SetupCustomInput(operation.parameters); case "CREATE_GESTURE_RECOGNITION": return CreateGestureRecognition(operation.parameters); case "SETUP_HAPTIC_FEEDBACK": return SetupHapticFeedback(operation.parameters); case "CREATE_INPUT_VALIDATION": return CreateInputValidation(operation.parameters); case "SETUP_ACCESSIBILITY_INPUT": return SetupAccessibilityInput(operation.parameters); case "CREATE_INPUT_RECORDING": return CreateInputRecording(operation.parameters); // ===== Touch & Gesture Tools ===== case "SETUP_MULTITOUCH": return SetupMultitouch(operation.parameters); case "CREATE_PINCH_ZOOM": return CreatePinchZoom(operation.parameters); case "SETUP_SWIPE_DETECTION": return SetupSwipeDetection(operation.parameters); case "CREATE_DRAG_DROP": return CreateDragDrop(operation.parameters); case "SETUP_TOUCH_EFFECTS": return SetupTouchEffects(operation.parameters); // ===== Visual Enhancement Tools ===== case "CREATE_PARTICLE_PRESET": return CreateParticlePreset(operation.parameters); case "CREATE_ADVANCED_MATERIAL": return CreateAdvancedMaterial(operation.parameters); case "SETUP_LIGHTING_PRESET": return SetupLightingPreset(operation.parameters); case "CREATE_VISUAL_EFFECT": return CreateVisualEffect(operation.parameters); case "SETUP_REFLECTION_PROBE": return SetupReflectionProbe(operation.parameters); case "CREATE_LIGHT_PROBE_GROUP": return CreateLightProbeGroup(operation.parameters); case "SETUP_VOLUMETRIC_FOG": return SetupVolumetricFog(operation.parameters); case "CREATE_DECAL": return CreateDecal(operation.parameters); case "CREATE_CAUSTICS": return CreateCausticsProjector(operation.parameters); case "CREATE_WATER": return CreateWaterSystem(operation.parameters); case "SETUP_COLOR_GRADING": return SetupColorGrading(operation.parameters); case "CREATE_LENS_FLARE": return CreateLensFlare(operation.parameters); // Screen Effects case "CREATE_SCREEN_SHAKE": return CreateScreenShake(operation.parameters); case "CREATE_SCREEN_FADE": return CreateScreenFade(operation.parameters); case "CREATE_VIGNETTE_EFFECT": return CreateVignetteEffect(operation.parameters); case "CREATE_CHROMATIC_ABERRATION": return CreateChromaticAberration(operation.parameters); // Shader Tools case "CREATE_SHADER_PROPERTY_ANIMATOR": return CreateShaderPropertyAnimator(operation.parameters); case "CREATE_MATERIAL_PROPERTY_BLOCK": return CreateMaterialPropertyBlock(operation.parameters); case "ANIMATE_SHADER_TEXTURE": return AnimateShaderTexture(operation.parameters); case "CREATE_SHADER_GRADIENT": return CreateShaderGradient(operation.parameters); // Camera Effects - Restored with Auto-Generated Shaders case "CREATE_BLOOM": return CreateBloomEffect(operation.parameters); case "CREATE_FILM_GRAIN": return CreateFilmGrainEffect(operation.parameters); case "CREATE_MOTION_BLUR": return CreateMotionBlurEffect(operation.parameters); case "CREATE_DEPTH_OF_FIELD": return CreateDepthOfFieldEffect(operation.parameters); case "CREATE_LENS_DISTORTION": return CreateLensDistortionEffect(operation.parameters); // ===== Phase 4: Advanced Rendering & VFX Systems ===== // Pipeline Settings case "SETUP_URP_SETTINGS": return SetupURPSettings(operation.parameters); case "SETUP_HDRP_SETTINGS": return SetupHDRPSettings(operation.parameters); case "SETUP_POST_PROCESSING": return SetupPostProcessing(operation.parameters); // VFX Systems case "CREATE_VFX_GRAPH": return CreateVFXGraph(operation.parameters); case "CREATE_SHADER_GRAPH": return CreateShaderGraph(operation.parameters); // External Shader Editing case "READ_SHADER": return ReadShader(operation.parameters); case "MODIFY_SHADER": return ModifyShader(operation.parameters); case "ANALYZE_SHADER": return AnalyzeShader(operation.parameters); case "READ_SHADER_GRAPH": return ReadShaderGraph(operation.parameters); case "SETUP_LIGHTING_SCENARIOS": return SetupLightingScenarios(operation.parameters); // Weather System case "CREATE_RAIN_EFFECT": return CreateRainEffect(operation.parameters); case "CREATE_SNOW_EFFECT": return CreateSnowEffect(operation.parameters); case "CREATE_WIND_EFFECT": return CreateWindEffect(operation.parameters); case "CREATE_LIGHTNING_EFFECT": return CreateLightningEffect(operation.parameters); case "CREATE_THUNDERSTORM": return CreateThunderstorm(operation.parameters); // Unified Weather System case "CREATE_WEATHER_SYSTEM": return CreateWeatherSystem(operation.parameters); case "SET_WEATHER_PRESET": return SetWeatherPreset(operation.parameters); // Time of Day System case "CREATE_TIME_OF_DAY": return CreateTimeOfDay(operation.parameters); case "SET_TIME_OF_DAY": return SetTimeOfDay(operation.parameters); case "CREATE_DAY_NIGHT_PRESET": return CreateDayNightPreset(operation.parameters); case "CREATE_SKYBOX_BLEND": return CreateSkyboxBlend(operation.parameters); case "CREATE_SKYBOX_FROM_IMAGE": return CreateSkyboxFromImage(operation.parameters); case "CREATE_TIME_EVENT": return CreateTimeEvent(operation.parameters); case "UNDO": case "UNDO_OPERATION": return UndoOperation(); case "REDO": case "REDO_OPERATION": return RedoOperation(); case "GET_HISTORY": case "GET_OPERATION_HISTORY": return GetOperationHistory(); case "CREATE_CHECKPOINT": return CreateCheckpoint(operation.parameters); case "RESTORE_CHECKPOINT": return RestoreCheckpoint(operation.parameters); // Real-time event monitoring case "MONITOR_PLAY_STATE": return StartPlayStateMonitoring(operation.parameters); case "MONITOR_FILE_CHANGES": return StartFileChangeMonitoring(operation.parameters); case "MONITOR_COMPILE": return StartCompileMonitoring(operation.parameters); case "SUBSCRIBE_EVENTS": return SubscribeToEvents(operation.parameters); case "GET_EVENTS": return GetRecentEvents(operation.parameters); case "GET_MONITORING_STATUS": return GetMonitoringStatus(); // Project settings case "GET_BUILD_SETTINGS": return NexusProjectSettings.GetBuildSettings(); case "GET_PLAYER_SETTINGS": return NexusProjectSettings.GetPlayerSettings(); case "GET_QUALITY_SETTINGS": return NexusProjectSettings.GetQualitySettings(); case "GET_INPUT_SETTINGS": return NexusProjectSettings.GetInputSettings(); case "GET_PHYSICS_SETTINGS": return NexusProjectSettings.GetPhysicsSettings(); case "GET_PROJECT_SUMMARY": var projectSummary = NexusProjectSettings.GetProjectSettingsSummary(); SynLog.Info($"[NexusExecutor] GET_PROJECT_SUMMARY response length: {projectSummary.Length}"); return projectSummary; case "BATCH_CREATE": return await BatchCreate(operation); // === Real-time execution state monitoring === case "GET_RUNTIME_STATUS": return NexusRuntimeMonitor.GetRuntimeStatus(operation.parameters); case "GET_PERFORMANCE_METRICS": return NexusRuntimeMonitor.GetPerformanceMetrics(operation.parameters); case "GET_MEMORY_USAGE": return NexusRuntimeMonitor.GetMemoryUsage(operation.parameters); case "GET_ERROR_STATUS": return NexusRuntimeMonitor.GetErrorStatus(operation.parameters); case "GET_BUILD_STATUS": return NexusRuntimeMonitor.GetBuildStatus(operation.parameters); // === Detailed asset information retrieval === case "GET_TEXTURE_DETAILS": return NexusAssetAnalyzer.GetTextureDetails(operation.parameters); case "GET_MESH_DETAILS": return NexusAssetAnalyzer.GetMeshDetails(operation.parameters); case "GET_AUDIO_DETAILS": return NexusAssetAnalyzer.GetAudioDetails(operation.parameters); case "GET_ANIMATION_DETAILS": return NexusAssetAnalyzer.GetAnimationDetails(operation.parameters); case "GET_MATERIAL_DETAILS": return NexusAssetAnalyzer.GetMaterialDetails(operation.parameters); case "GET_ASSET_FILE_INFO": return NexusAssetAnalyzer.GetAssetFileInfo(operation.parameters); case "ANALYZE_ASSET_USAGE": return NexusAssetAnalyzer.AnalyzeAssetUsage(operation.parameters); case "GET_ASSET_IMPORT_SETTINGS": return GetAssetImportSettings(operation.parameters); case "PLACE_OBJECTS": return PlaceObjects(operation.parameters); case "GET_GAMEOBJECT_DETAILS": return GetGameObjectDetails(operation.parameters); case "GET_SCENE_INFO": return GetSceneInfo(operation.parameters); case "GET_SCENE_SUMMARY": return GetSceneSummary(operation.parameters); case "GET_GAMEOBJECTS_LIST": return GetGameObjectsList(operation.parameters); case "GET_GAMEOBJECT_DETAIL": return GetGameObjectDetail(operation.parameters); case "GET_SCENE_CHANGES_SINCE": return GetSceneChangesSince(operation.parameters); case "CAPTURE_GAME_VIEW": return CaptureGameView(operation.parameters); case "CAPTURE_SCENE_VIEW": return CaptureSceneView(operation.parameters); case "CAPTURE_REGION": return CaptureRegion(operation.parameters); case "CAPTURE_GRID": return CaptureGrid(operation.parameters); case "CAPTURE_UI_ELEMENT": return CaptureUIElement(operation.parameters); case "GET_SCREENSHOT_RESULT": return GetScreenshotResult(); case "FORCE_REFRESH_ASSETS": return ForceRefreshAssets(operation.parameters); case "INVOKE_CONTEXT_MENU": return InvokeContextMenu(operation.parameters); case "EXECUTE_MENU_ITEM": return ExecuteMenuItem(operation.parameters); case "RUN_CSHARP": return NexusCSharpEval.Run(operation.parameters); case "GET_INSPECTOR_INFO": return GetInspectorInfo(operation.parameters); case "GET_SELECTED_OBJECT_INFO": return GetSelectedObjectInfo(operation.parameters); case "GET_COMPONENT_DETAILS": return GetComponentDetails(operation.parameters); case "CREATE_TERRAIN": return CreateTerrain(operation.parameters); case "MODIFY_TERRAIN": return ModifyTerrain(operation.parameters); case "GET_CAMERA_INFO": return GetCameraInfo(operation.parameters); case "GET_TERRAIN_INFO": return GetTerrainInfo(operation.parameters); case "GET_LIGHTING_INFO": return GetLightingInfo(operation.parameters); case "GET_MATERIAL_INFO": return GetMaterialInfo(operation.parameters); case "GET_UI_INFO": return GetUIInfo(operation.parameters); case "GET_PHYSICS_INFO": return GetPhysicsInfo(operation.parameters); case "LIST_ASSETS": return ListAssets(operation.parameters); case "CHECK_FOLDER": return CheckFolder(operation.parameters); case "CREATE_FOLDER": return CreateFolder(operation.parameters); case "LIST_FOLDERS": return ListFolders(operation.parameters); case "DUPLICATE_GAMEOBJECT": return DuplicateGameObject(operation.parameters); case "FIND_BY_COMPONENT": return FindGameObjectsByComponent(operation.parameters); case "CLEANUP_EMPTY_OBJECTS": return CleanupEmptyObjects(operation.parameters); case "GET_PROJECT_STATS": return GetProjectStats(operation.parameters); case "MANAGE_PACKAGE": return ManagePackage(operation.parameters); case "MANAGE_SCENE": return ManageScene(operation.parameters); case "LOAD_SCENE": return LoadScene(operation.parameters); case "UNLOAD_SCENE": return UnloadScene(operation.parameters); case "SET_ACTIVE_SCENE": return SetActiveScene(operation.parameters); case "LIST_ALL_SCENES": return ListAllScenes(operation.parameters); case "ADD_SCENE_TO_BUILD": return AddSceneToBuild(operation.parameters); case "SEARCH_PREFABS_BY_COMPONENT": return SearchPrefabsByComponent(operation.parameters); case "FIND_MATERIAL_USAGE": return FindMaterialUsage(operation.parameters); case "FIND_TEXTURE_USAGE": return FindTextureUsage(operation.parameters); case "GET_ASSET_DEPENDENCIES": return GetAssetDependencies(operation.parameters); case "FIND_MISSING_REFERENCES": return FindMissingReferences(operation.parameters); case "CREATE_ANIMATION": return CreateAnimation(operation.parameters); case "SETUP_LIGHTING": return SetupLighting(operation.parameters); case "CONSOLE_OPERATION": return ConsoleOperation(operation.parameters); case "ANALYZE_CONSOLE_LOGS": return AnalyzeConsoleLogs(operation.parameters); // === Debug & Test tools === case "CONTROL_GAME_SPEED": return ControlGameSpeed(operation.parameters); case "PROFILE_PERFORMANCE": return ProfilePerformance(operation.parameters); case "DEBUG_DRAW": return DebugDraw(operation.parameters); case "RUN_UNITY_TESTS": return RunUnityTests(operation.parameters); case "MANAGE_BREAKPOINTS": return ManageBreakpoints(operation.parameters); // === Animation tools === case "CREATE_ANIMATOR_CONTROLLER": return CreateAnimatorController(operation.parameters); case "ADD_ANIMATION_STATE": return AddAnimationState(operation.parameters); case "CREATE_ANIMATION_CLIP": return CreateAnimationClip(operation.parameters); case "SETUP_BLEND_TREE": return SetupBlendTree(operation.parameters); case "ADD_ANIMATION_TRANSITION": return AddAnimationTransition(operation.parameters); case "SETUP_ANIMATION_LAYER": return SetupAnimationLayer(operation.parameters); case "CREATE_ANIMATION_EVENT": return CreateAnimationEvent(operation.parameters); case "SETUP_AVATAR": return SetupAvatar(operation.parameters); // === Advanced Animation Management === case "IMPORT_MIXAMO_ANIMATION": return NexusAnimationHelper.ImportMixamoAnimation(operation.parameters); case "ORGANIZE_ANIMATION_ASSETS": return NexusAnimationHelper.OrganizeAnimationAssets(operation.parameters); case "SETUP_CHARACTER_IK": return NexusAnimationHelper.SetupCharacterIK(operation.parameters); case "CREATE_ANIMATION_LAYER_MASK": return NexusAnimationHelper.CreateAnimationLayerMask(operation.parameters); case "SETUP_ADVANCED_BLEND_TREE": return NexusAnimationHelper.SetupAdvancedBlendTree(operation.parameters); case "RETARGET_ANIMATION": return NexusAnimationHelper.RetargetAnimation(operation.parameters); case "CREATE_TRANSITION_PRESET": return NexusAnimationHelper.CreateTransitionPreset(operation.parameters); case "ANALYZE_ANIMATION_PERFORMANCE": return NexusAnimationHelper.AnalyzeAnimationPerformance(operation.parameters); case "CREATE_TIMELINE": return CreateTimeline(operation.parameters); case "BAKE_ANIMATION": return BakeAnimation(operation.parameters); // === UI detailed construction tools === case "SETUP_UI_ANCHORS": return SetupUIAnchors(operation.parameters); case "CREATE_RESPONSIVE_UI": return CreateResponsiveUI(operation.parameters); case "SETUP_UI_ANIMATION": return SetupUIAnimation(operation.parameters); case "CREATE_UI_GRID": return CreateUIGrid(operation.parameters); case "SETUP_SCROLL_VIEW": return SetupScrollView(operation.parameters); case "CREATE_UI_NOTIFICATION": return CreateUINotification(operation.parameters); case "SETUP_UI_NAVIGATION": return SetupUINavigation(operation.parameters); case "CREATE_UI_DIALOG": return CreateUIDialog(operation.parameters); case "OPTIMIZE_UI_CANVAS": return OptimizeUICanvas(operation.parameters); case "SETUP_SAFE_AREA": return SetupSafeArea(operation.parameters); case "APPLY_UI_THEME": return ApplyUITheme(ConvertParameters(operation.parameters)); case "SET_UI_COLORS": return SetUIColors(ConvertParameters(operation.parameters)); case "STYLE_UI_ELEMENTS": return StyleUIElements(ConvertParameters(operation.parameters)); case "ADD_UI_EFFECTS": return AddUIEffects(ConvertParameters(operation.parameters)); case "SET_TYPOGRAPHY": return SetTypography(ConvertParameters(operation.parameters)); case "EXECUTE_BATCH": return await ExecuteBatch(operation.parameters); case "BATCH_RENAME": return BatchRename(operation.parameters); case "BATCH_IMPORT_SETTINGS": return BatchImportSettings(operation.parameters); case "BATCH_PREFAB_UPDATE": return BatchPrefabUpdate(operation.parameters); case "BATCH_MATERIAL_APPLY": return BatchMaterialApply(operation.parameters); case "BATCH_PREFAB_CREATE": return BatchPrefabCreate(operation.parameters); case "UNITY_SEARCH": case "SEARCH_OBJECTS": return SearchObjects(operation.parameters); case "SEND_CHAT_RESPONSE": return SendChatResponse(operation.parameters); case "CHECK_MESSAGES": return CheckMessages(operation.parameters); case "SEND_REALTIME_RESPONSE": return SendRealtimeResponse(operation.parameters); case "CHECK_ACTIVE_SESSIONS": return CheckActiveSessions(operation.parameters); case "GROUP_GAMEOBJECTS": return GroupGameObjects(operation.parameters); case "RENAME_ASSET": return RenameAsset(operation.parameters); case "MOVE_ASSET": return MoveAsset(operation.parameters); case "DELETE_ASSET": return DeleteAsset(operation.parameters); case "PAUSE_SCENE": return PauseScene(operation.parameters); case "OPTIMIZE_TEXTURES_BATCH": return OptimizeTexturesBatch(operation.parameters); case "ANALYZE_DRAW_CALLS": return AnalyzeDrawCalls(operation.parameters); case "CREATE_PROJECT_SNAPSHOT": return CreateProjectSnapshot(operation.parameters); case "ANALYZE_DEPENDENCIES": return AnalyzeDependencies(operation.parameters); case "EXPORT_PROJECT_STRUCTURE": return ExportProjectStructure(operation.parameters); case "EXPORT_PACKAGE": return ExportPackage(operation.parameters); case "VALIDATE_NAMING_CONVENTIONS": return ValidateNamingConventions(operation.parameters); case "EXTRACT_ALL_TEXT": return ExtractAllText(operation.parameters); case "FIND_UNUSED_ASSETS": return FindUnusedAssets(operation.parameters); case "ESTIMATE_BUILD_SIZE": return EstimateBuildSize(operation.parameters); case "PERFORMANCE_REPORT": return PerformanceReport(operation.parameters); case "AUTO_ORGANIZE_FOLDERS": return AutoOrganizeFolders(operation.parameters); case "GENERATE_LOD": return GenerateLOD(operation.parameters); case "AUTO_ATLAS_TEXTURES": return AutoAtlasTextures(operation.parameters); // ===== Package management ===== case "LIST_PACKAGES": return ListPackages(operation.parameters); case "INSTALL_PACKAGE": return InstallPackage(operation.parameters); case "REMOVE_PACKAGE": return RemovePackage(operation.parameters); case "CHECK_PACKAGE": return CheckPackage(operation.parameters); // ===== Game development specific features ===== case "CREATE_GAME_CONTROLLER": return CreateGameController(operation.parameters); case "SETUP_INPUT_SYSTEM": return SetupInputSystem(operation.parameters); case "CREATE_STATE_MACHINE": return CreateStateMachine(operation.parameters); case "SETUP_INVENTORY_SYSTEM": return SetupInventorySystem(operation.parameters); // ===== Prototyping features ===== case "CREATE_GAME_TEMPLATE": return CreateGameTemplate(operation.parameters); case "QUICK_PROTOTYPE": return QuickPrototype(operation.parameters); // AI & Machine Learning related case "SETUP_ML_AGENT": return SetupMLAgent(operation.parameters); case "CREATE_NEURAL_NETWORK": return CreateNeuralNetwork(operation.parameters); case "SETUP_BEHAVIOR_TREE": return SetupBehaviorTree(operation.parameters); case "CREATE_AI_PATHFINDING": return CreateAIPathfinding(operation.parameters); // ===== GOAP AI system ===== case "CREATE_GOAP_AGENT": return CreateGoapAgent(operation.parameters); case "DEFINE_GOAP_GOAL": return DefineGoapGoal(operation.parameters); case "CREATE_GOAP_ACTION": return CreateGoapAction(operation.parameters); case "DEFINE_BEHAVIOR_LANGUAGE": return DefineBehaviorLanguage(operation.parameters); case "GENERATE_GOAP_ACTION_SET": return GenerateGoapActionSet(operation.parameters); case "SETUP_GOAP_WORLD_STATE": return SetupGoapWorldState(operation.parameters); case "CREATE_GOAP_TEMPLATE": return CreateGoapTemplate(operation.parameters); case "DEBUG_GOAP_DECISIONS": return DebugGoapDecisions(operation.parameters); case "OPTIMIZE_GOAP_PERFORMANCE": return OptimizeGoapPerformance(operation.parameters); // ===== Behavior Tree system ===== case "CREATE_BT_AGENT": return CreateBTAgent(operation.parameters); case "ADD_BT_NODE": return AddBTNode(operation.parameters); case "CREATE_BT_FROM_DESCRIPTION": return CreateBTFromDescription(operation.parameters); case "START_BT": return StartBT(operation.parameters); case "STOP_BT": return StopBT(operation.parameters); case "DEBUG_BT": return DebugBT(operation.parameters); // === Synaptic Pro Material Tools === case "CREATE_WATER_MATERIAL": return CreateWaterMaterial(operation.parameters); case "CREATE_TOON_MATERIAL": return CreateToonMaterial(operation.parameters); case "CREATE_HAIR_MATERIAL": return CreateHairMaterial(operation.parameters); case "CREATE_EYE_MATERIAL": return CreateEyeMaterial(operation.parameters); case "CREATE_SKY_MATERIAL": return CreateSkyMaterial(operation.parameters); case "CREATE_DISSOLVE_MATERIAL": return CreateDissolveMaterial(operation.parameters); case "CREATE_SHIELD_MATERIAL": return CreateShieldMaterial(operation.parameters); case "CREATE_GRASS_MATERIAL": return CreateGrassMaterial(operation.parameters); case "SET_MATERIAL_PROPERTY": return SetMaterialProperty(operation.parameters); case "GET_MATERIAL_PROPERTIES": return GetMaterialProperties(operation.parameters); case "CREATE_HDRP_WATER": return CreateHDRPWater(operation.parameters); case "SET_HDRP_WATER_PROPERTY": return SetHDRPWaterProperty(operation.parameters); case "SET_VFX_PROPERTY": return SetVFXProperty(operation.parameters); case "GET_VFX_PROPERTIES": return GetVFXProperties(operation.parameters); case "TRIGGER_VFX_EVENT": return TriggerVFXEvent(operation.parameters); // === VFX Graph Builder API === case "VFX_CREATE": return VFXCreate(operation.parameters); case "VFX_ADD_CONTEXT": return VFXAddContext(operation.parameters); case "VFX_ADD_BLOCK": return VFXAddBlock(operation.parameters); case "VFX_ADD_OPERATOR": return VFXAddOperator(operation.parameters); case "VFX_LINK_CONTEXTS": return VFXLinkContexts(operation.parameters); case "VFX_GET_STRUCTURE": return VFXGetStructure(operation.parameters); case "VFX_COMPILE": return VFXCompile(operation.parameters); case "VFX_GET_AVAILABLE_TYPES": return VFXGetAvailableTypes(operation.parameters); case "VFX_ADD_PARAMETER": return VFXAddParameter(operation.parameters); case "VFX_CONNECT_SLOTS": return VFXConnectSlots(operation.parameters); case "VFX_SET_ATTRIBUTE": return VFXSetAttribute(operation.parameters); case "VFX_CREATE_PRESET": return VFXCreatePreset(operation.parameters); case "VFX_CONFIGURE_OUTPUT": return VFXConfigureOutput(operation.parameters); case "VFX_SET_COLOR_GRADIENT": return VFXSetColorGradient(operation.parameters); // === VFX Graph Asset Editing === case "READ_VFX_GRAPH": return ReadVFXGraph(operation.parameters); case "MODIFY_VFX_GRAPH": return ModifyVFXGraph(operation.parameters); case "ANALYZE_VFX_GRAPH": return AnalyzeVFXGraph(operation.parameters); case "VFX_SET_OUTPUT": return VFXSetOutput(operation.parameters); case "VFX_SET_BLOCK_VALUE": return VFXSetBlockValue(operation.parameters); case "VFX_SET_SPAWN_RATE": return VFXSetSpawnRate(operation.parameters); case "VFX_LIST_BLOCKS": return VFXListBlocks(operation.parameters); case "VFX_REMOVE_BLOCK": return VFXRemoveBlock(operation.parameters); case "VFX_GET_BLOCK_INFO": return VFXGetBlockInfo(operation.parameters); // === Particle System Asset Editing === case "READ_PARTICLE_SYSTEM": return ReadParticleSystem(operation.parameters); case "MODIFY_PARTICLE_SYSTEM": return ModifyParticleSystem(operation.parameters); case "FIX_URP_PARTICLE_SHADERS": return FixURPParticleShaders(operation.parameters); case "FIX_PINK_MATERIALS": return FixPinkMaterials(operation.parameters); case "CREATE_OCEAN_SYSTEM": return CreateOceanSystem(operation.parameters); case "ADD_BUOYANCY": return AddBuoyancy(operation.parameters); // === Synaptic Pro Texture Tools === case "GENERATE_SDF_TEXTURE": return GenerateSDFTexture(operation.parameters); case "GENERATE_RAMP_TEXTURE": return GenerateRampTexture(operation.parameters); case "ADD_DISSOLVE_CONTROLLER": return AddDissolveController(operation.parameters); case "ADD_SHIELD_CONTROLLER": return AddShieldController(operation.parameters); case "ADD_GRASS_RENDERER": return AddGrassRenderer(operation.parameters); case "TRIGGER_DISSOLVE": return TriggerDissolve(operation.parameters); case "TRIGGER_SHIELD_HIT": return TriggerShieldHit(operation.parameters); case "GENERATE_CLOUD_NOISE": return GenerateCloudNoiseTexture(operation.parameters); // Dynamic Meta-Tools case "DYNAMIC_INSPECT": return DynamicInspect(operation.parameters); case "DYNAMIC_MODIFY": return DynamicModify(operation.parameters); case "DYNAMIC_CREATE": return DynamicCreate(operation.parameters); default: return $"Unknown operation: {operation.type}"; } } catch (Exception e) { return CreateErrorResponse("ExecuteOperation", e, operation.parameters); } } private string CreateGameObject(Dictionary parameters) { var name = parameters.GetValueOrDefault("name", "GameObject"); string result = ""; // Record operation to history var historyParams = new Dictionary(); foreach (var kvp in parameters) { historyParams[kvp.Key] = kvp.Value; } NexusOperationHistory.Instance.RecordOperation( "CREATE_GAMEOBJECT", $"Create GameObject: {name}", historyParams, () => { GameObject go; var type = parameters.GetValueOrDefault("type", "empty").ToLower(); // Parse color if specified Color? primitiveColor = null; if (parameters.TryGetValue("color", out var colorStr)) { primitiveColor = ParseColor(colorStr); } // Set appropriate mesh for primitive types switch (type) { case "cube": go = CreatePrimitiveWithMaterial(PrimitiveType.Cube, primitiveColor); go.name = name; break; case "sphere": go = CreatePrimitiveWithMaterial(PrimitiveType.Sphere, primitiveColor); go.name = name; break; case "cylinder": go = CreatePrimitiveWithMaterial(PrimitiveType.Cylinder, primitiveColor); go.name = name; break; case "plane": go = CreatePrimitiveWithMaterial(PrimitiveType.Plane, primitiveColor); go.name = name; break; case "capsule": go = CreatePrimitiveWithMaterial(PrimitiveType.Capsule, primitiveColor); go.name = name; break; case "quad": go = CreatePrimitiveWithMaterial(PrimitiveType.Quad, primitiveColor); go.name = name; break; default: go = new GameObject(name); break; } // Register to UNDO UnityEditor.Undo.RegisterCreatedObjectUndo(go, $"Create {name}"); // Position if (parameters.TryGetValue("position", out var pos)) { go.transform.position = ParseVector3(pos); } // Rotation if (parameters.TryGetValue("rotation", out var rot)) { go.transform.rotation = Quaternion.Euler(ParseVector3(rot)); } // Scale if (parameters.TryGetValue("scale", out var scale)) { go.transform.localScale = ParseVector3(scale); } // Parent if (parameters.TryGetValue("parent", out var parentName)) { var parent = GameObject.Find(parentName); if (parent != null) { go.transform.SetParent(parent.transform); } } lastCreatedObject = go; createdObjects.Add(go); Selection.activeGameObject = go; EditorGUIUtility.PingObject(go); // Include detailed information of creation result var components = go.GetComponents().Select(c => c.GetType().Name).ToArray(); result = JsonConvert.SerializeObject(new { success = true, message = $"Created GameObject: {name}", name = go.name, type = type, components = components, hasMesh = go.GetComponent() != null, hasRenderer = go.GetComponent() != null }); } ); return result; } private string UpdateGameObject(Dictionary parameters) { try { var gameObject = GetTargetGameObject(parameters); if (gameObject == null) { return JsonConvert.SerializeObject(new { success = false, error = "GameObject not found" }); } var changes = new List(); // Register to UNDO UnityEditor.Undo.RecordObject(gameObject, "Update GameObject"); // Rename - use "newName" parameter (not "name" which is used for target identification) if (parameters.ContainsKey("newName")) { gameObject.name = parameters["newName"]; changes.Add($"Name changed to: {parameters["newName"]}"); } // Change tag if (parameters.ContainsKey("tag")) { try { gameObject.tag = parameters["tag"]; changes.Add($"Tag changed to: {parameters["tag"]}"); } catch { changes.Add($"Warning: Tag '{parameters["tag"]}' not found"); } } // Change layer if (parameters.ContainsKey("layer")) { var layer = int.Parse(parameters["layer"]); gameObject.layer = layer; changes.Add($"Layer changed to: {LayerMask.LayerToName(layer)} ({layer})"); } // Active state (supports isActive or active parameter) if (parameters.ContainsKey("isActive") || parameters.ContainsKey("active")) { var activeParam = parameters.ContainsKey("isActive") ? parameters["isActive"] : parameters["active"]; var isActive = activeParam.ToLower() == "true" || activeParam == "1"; gameObject.SetActive(isActive); changes.Add($"Active state set to: {isActive}"); } // Static state if (parameters.ContainsKey("isStatic")) { var isStatic = parameters["isStatic"] == "true"; gameObject.isStatic = isStatic; changes.Add($"Static state set to: {isStatic}"); } EditorUtility.SetDirty(gameObject); return JsonConvert.SerializeObject(new { success = true, message = $"Updated GameObject '{gameObject.name}'", changes = changes, gameObject = new { name = gameObject.name, tag = gameObject.tag, layer = LayerMask.LayerToName(gameObject.layer), active = gameObject.activeSelf, isStatic = gameObject.isStatic, path = GetFullPath(gameObject) } }, Formatting.Indented); } catch (Exception e) { return JsonConvert.SerializeObject(new { success = false, error = e.Message }); } } private string DeleteGameObject(Dictionary parameters) { try { var gameObject = GetTargetGameObject(parameters); if (gameObject == null) { var targetName = parameters.GetValueOrDefault("target") ?? parameters.GetValueOrDefault("name") ?? parameters.GetValueOrDefault("object") ?? "unknown"; return JsonConvert.SerializeObject(new { success = false, error = $"GameObject '{targetName}' not found or already deleted" }); } // Check if object has already been deleted if (gameObject == null || !gameObject) { return JsonConvert.SerializeObject(new { success = false, error = "GameObject is already destroyed" }); } // Record number of child objects int childCount = gameObject.transform.childCount; string path = GetFullPath(gameObject); string objectName = gameObject.name; // Save name before deletion SynLog.Info($"[DeleteGameObject] Deleting object: {objectName} at path: {path}"); // Cleanup if (lastCreatedObject == gameObject) { lastCreatedObject = null; } createdObjects.Remove(gameObject); try { // Register to UNDO before deletion UnityEditor.Undo.DestroyObjectImmediate(gameObject); SynLog.Info($"[DeleteGameObject] Successfully deleted: {objectName}"); } catch (System.Exception ex) { Debug.LogError($"[DeleteGameObject] Failed to delete {objectName}: {ex.Message}"); return JsonConvert.SerializeObject(new { success = false, error = $"Failed to delete object: {ex.Message}" }); } return JsonConvert.SerializeObject(new { success = true, message = $"Deleted GameObject '{objectName}'", deletedPath = path, childrenDeleted = childCount }); } catch (Exception e) { return JsonConvert.SerializeObject(new { success = false, error = e.Message }); } } private string InstantiatePrefab(Dictionary parameters) { try { var assetPath = parameters.GetValueOrDefault("assetPath"); if (string.IsNullOrEmpty(assetPath)) { return JsonConvert.SerializeObject(new { success = false, error = "assetPath is required" }); } // Ensure path starts with Assets/ if (!assetPath.StartsWith("Assets/")) { assetPath = "Assets/" + assetPath; } // Load the asset var prefabAsset = AssetDatabase.LoadAssetAtPath(assetPath); if (prefabAsset == null) { return JsonConvert.SerializeObject(new { success = false, error = $"Asset not found at path: {assetPath}", hint = "Make sure the path is correct and the asset exists. Example: Assets/Prefabs/Player.prefab" }); } // Instantiate the prefab var instance = PrefabUtility.InstantiatePrefab(prefabAsset) as GameObject; if (instance == null) { return JsonConvert.SerializeObject(new { success = false, error = $"Failed to instantiate prefab from: {assetPath}" }); } // Set name if provided var name = parameters.GetValueOrDefault("name"); if (!string.IsNullOrEmpty(name)) { instance.name = name; } // Set position if provided if (parameters.TryGetValue("position", out var posStr)) { try { var posJson = JsonConvert.DeserializeObject>(posStr); instance.transform.position = new Vector3( posJson.GetValueOrDefault("x", 0), posJson.GetValueOrDefault("y", 0), posJson.GetValueOrDefault("z", 0) ); } catch { } } // Set rotation if provided if (parameters.TryGetValue("rotation", out var rotStr)) { try { var rotJson = JsonConvert.DeserializeObject>(rotStr); instance.transform.rotation = Quaternion.Euler( rotJson.GetValueOrDefault("x", 0), rotJson.GetValueOrDefault("y", 0), rotJson.GetValueOrDefault("z", 0) ); } catch { } } // Set scale if provided if (parameters.TryGetValue("scale", out var scaleStr)) { try { var scaleJson = JsonConvert.DeserializeObject>(scaleStr); instance.transform.localScale = new Vector3( scaleJson.GetValueOrDefault("x", 1), scaleJson.GetValueOrDefault("y", 1), scaleJson.GetValueOrDefault("z", 1) ); } catch { } } // Set parent if provided var parentName = parameters.GetValueOrDefault("parent"); if (!string.IsNullOrEmpty(parentName)) { var parent = GameObject.Find(parentName); if (parent != null) { instance.transform.SetParent(parent.transform, true); } } // Register for undo UnityEditor.Undo.RegisterCreatedObjectUndo(instance, "Instantiate Prefab"); // Track the created object lastCreatedObject = instance; createdObjects.Add(instance); return JsonConvert.SerializeObject(new { success = true, message = $"Instantiated prefab from '{assetPath}'", gameObject = instance.name, position = new { x = instance.transform.position.x, y = instance.transform.position.y, z = instance.transform.position.z }, assetPath = assetPath }); } catch (Exception e) { return JsonConvert.SerializeObject(new { success = false, error = e.Message }); } } private string SetTransform(Dictionary parameters) { try { var gameObject = GetTargetGameObject(parameters); if (gameObject == null) { string targetName = parameters.GetValueOrDefault("target") ?? parameters.GetValueOrDefault("gameObject") ?? parameters.GetValueOrDefault("object"); return JsonConvert.SerializeObject(new { success = false, error = $"GameObject '{targetName}' not found" }); } var changes = new List(); var transform = gameObject.transform; // Register Transform changes to UNDO UnityEditor.Undo.RecordObject(transform, "Set Transform"); // Position if (parameters.ContainsKey("position")) { transform.position = ParseVector3(parameters["position"]); changes.Add($"Position set to: {transform.position}"); } // Rotation if (parameters.ContainsKey("rotation")) { transform.eulerAngles = ParseVector3(parameters["rotation"]); changes.Add($"Rotation set to: {transform.eulerAngles}"); } // Scale if (parameters.ContainsKey("scale")) { transform.localScale = ParseVector3(parameters["scale"]); changes.Add($"Scale set to: {transform.localScale}"); } // Local coordinate system if (parameters.ContainsKey("localPosition")) { transform.localPosition = ParseVector3(parameters["localPosition"]); changes.Add($"Local position set to: {transform.localPosition}"); } if (parameters.ContainsKey("localRotation")) { transform.localEulerAngles = ParseVector3(parameters["localRotation"]); changes.Add($"Local rotation set to: {transform.localEulerAngles}"); } // Set parent if (parameters.ContainsKey("parent")) { if (string.IsNullOrEmpty(parameters["parent"]) || parameters["parent"] == "null") { transform.SetParent(null); changes.Add("Parent removed"); } else { var parent = GameObject.Find(parameters["parent"]); if (parent != null) { transform.SetParent(parent.transform); changes.Add($"Parent set to: {parent.name}"); } } } // Whether to keep world position if (parameters.ContainsKey("worldPositionStays") && parameters.ContainsKey("parent")) { var worldPositionStays = parameters["worldPositionStays"] == "true"; var parent = GameObject.Find(parameters["parent"]); if (parent != null) { transform.SetParent(parent.transform, worldPositionStays); changes.Add($"World position stays: {worldPositionStays}"); } } EditorUtility.SetDirty(gameObject); return JsonConvert.SerializeObject(new { success = true, message = $"Transform updated for '{gameObject.name}'", changes = changes, transform = new { position = new { x = transform.position.x, y = transform.position.y, z = transform.position.z }, rotation = new { x = transform.eulerAngles.x, y = transform.eulerAngles.y, z = transform.eulerAngles.z }, scale = new { x = transform.localScale.x, y = transform.localScale.y, z = transform.localScale.z }, localPosition = new { x = transform.localPosition.x, y = transform.localPosition.y, z = transform.localPosition.z }, localRotation = new { x = transform.localEulerAngles.x, y = transform.localEulerAngles.y, z = transform.localEulerAngles.z }, parent = transform.parent != null ? transform.parent.name : "None" } }, Formatting.Indented); } catch (Exception e) { return JsonConvert.SerializeObject(new { success = false, error = e.Message }); } } private string UpdateComponent(Dictionary parameters) { try { SynLog.Info($"[UpdateComponent] Called with {parameters.Count} parameters:"); foreach (var kvp in parameters) { SynLog.Info($"[UpdateComponent] - {kvp.Key}: {kvp.Value}"); } var component = parameters.GetValueOrDefault("component", ""); if (string.IsNullOrEmpty(component)) { return JsonConvert.SerializeObject(new { success = false, error = "component parameter is required", receivedParameters = parameters.Keys.ToArray() }); } var gameObject = GetTargetGameObject(parameters); SynLog.Info($"[UpdateComponent] Found GameObject: {gameObject?.name ?? "null"}"); if (gameObject == null) { var availableObjects = GameObject.FindObjectsOfType().Take(10).Select(o => o.name); return JsonConvert.SerializeObject(new { success = false, error = "GameObject not found", availableObjects = availableObjects.ToArray() }); } var componentType = GetComponentType(component); SynLog.Info($"[UpdateComponent] Component type: {componentType?.Name ?? "null"}"); if (componentType == null) { return JsonConvert.SerializeObject(new { success = false, error = $"Component type '{component}' not found", suggestedComponents = new[] { "Transform", "Rigidbody", "Collider", "Renderer", "Light", "Camera" } }); } var comp = gameObject.GetComponent(componentType); SynLog.Info($"[UpdateComponent] Found component: {comp != null}"); if (comp == null) { var availableComponents = gameObject.GetComponents().Select(c => c.GetType().Name); return JsonConvert.SerializeObject(new { success = false, error = $"Component '{component}' not found on '{gameObject.name}'", availableComponents = availableComponents.ToArray() }); } var changes = new List(); var properties = new Dictionary(); // Register to UNDO UnityEditor.Undo.RecordObject(comp, "Update Component"); // Process property parameters (properties object or direct parameters) var propertyParams = new List>(); var excludedKeys = new[] { "target", "component", "gameObject", "object", "targetObject", "name", "objectName", "targetName", "source", "sourceName", "properties", "operationId" }; // If properties parameter exists if (parameters.ContainsKey("properties")) { try { var propertiesJson = parameters["properties"]; SynLog.Info($"[UpdateComponent] Raw properties parameter: {propertiesJson}"); // Unescape if escaped JSON string if (propertiesJson.StartsWith("{\\\"") || propertiesJson.StartsWith("[\\\"")) { // Unescape escaped JSON string propertiesJson = System.Text.RegularExpressions.Regex.Unescape(propertiesJson); SynLog.Info($"[UpdateComponent] Unescaped JSON: {propertiesJson}"); } Dictionary propertiesDict; // Attempt to parse as JSON string try { propertiesDict = JsonConvert.DeserializeObject>(propertiesJson); } catch { // If JSON parsing fails, attempt to parse as key=value format SynLog.Warn($"[UpdateComponent] JSON parsing failed, attempting key=value parsing"); propertiesDict = ParseKeyValueString(propertiesJson); } foreach (var kvp in propertiesDict) { var valueStr = kvp.Value?.ToString() ?? ""; propertyParams.Add(new KeyValuePair(kvp.Key, valueStr)); SynLog.Info($"[UpdateComponent] Added property: {kvp.Key} = {valueStr}"); } SynLog.Info($"[UpdateComponent] Successfully parsed {propertyParams.Count} properties from JSON"); } catch (Exception ex) { Debug.LogError($"[UpdateComponent] Failed to parse properties: {ex.Message}"); Debug.LogError($"[UpdateComponent] Raw properties value: {parameters["properties"]}"); } } // Add direct parameters as well var directParams = parameters.Where(p => !excludedKeys.Contains(p.Key)).ToList(); propertyParams.AddRange(directParams); SynLog.Info($"[UpdateComponent] Total property parameters to update: {propertyParams.Count}"); foreach (var param in propertyParams) { SynLog.Info($"[UpdateComponent] - Will update: {param.Key} = {param.Value}"); } if (propertyParams.Count == 0) { return JsonConvert.SerializeObject(new { success = false, error = "No property parameters found to update", excludedKeys = excludedKeys, allParameters = parameters.Keys.ToArray(), hint = "Use 'properties' parameter with JSON object or pass properties directly" }); } foreach (var kvp in propertyParams) { try { SynLog.Info($"[UpdateComponent] Setting property {kvp.Key} to {kvp.Value}"); SetComponentProperty(comp, kvp.Key, kvp.Value); changes.Add($"{kvp.Key} = {kvp.Value}"); // Get value after update (prevent circular references like Vector3) var propInfo = componentType.GetProperty(kvp.Key); if (propInfo != null && propInfo.CanRead) { var value = propInfo.GetValue(comp); properties[kvp.Key] = ConvertValueForSerialization(value); } else { var fieldInfo = componentType.GetField(kvp.Key); if (fieldInfo != null) { var value = fieldInfo.GetValue(comp); properties[kvp.Key] = ConvertValueForSerialization(value); } } SynLog.Info($"[UpdateComponent] Successfully set {kvp.Key}"); } catch (Exception ex) { Debug.LogError($"[UpdateComponent] Failed to set {kvp.Key}: {ex.Message}"); changes.Add($"Failed to set {kvp.Key}: {ex.Message}"); } } EditorUtility.SetDirty(comp); SynLog.Info($"[UpdateComponent] Completed with {changes.Count} changes"); // Check for errors even on success var failedChanges = changes.Where(c => c.StartsWith("Failed")).ToList(); var successChanges = changes.Where(c => !c.StartsWith("Failed")).ToList(); // Provide useful information even on partial success var isFullSuccess = failedChanges.Count == 0; var hasAnySuccess = successChanges.Count > 0; return JsonConvert.SerializeObject(new { success = isFullSuccess || hasAnySuccess, // Treat partial success as success fullSuccess = isFullSuccess, partialSuccess = hasAnySuccess && !isFullSuccess, message = isFullSuccess ? $"Successfully updated {component} on '{gameObject.name}'" : hasAnySuccess ? $"Partially updated {component} on '{gameObject.name}' - {successChanges.Count} successful, {failedChanges.Count} failed" : $"Failed to update {component} on '{gameObject.name}'", successfulChanges = successChanges, failedChanges = failedChanges, totalChanges = changes.Count, successCount = successChanges.Count, failureCount = failedChanges.Count, properties = properties, componentType = componentType.Name, targetObject = gameObject.name, availableProperties = componentType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .Where(p => p.CanWrite) .Select(p => p.Name) .Take(10) // Only first 10 .ToArray() }, Formatting.Indented); } catch (Exception e) { Debug.LogError($"[UpdateComponent] Fatal error: {e.Message}"); Debug.LogError($"[UpdateComponent] Stack trace: {e.StackTrace}"); return JsonConvert.SerializeObject(new { success = false, error = e.Message, errorType = e.GetType().Name, stackTrace = e.StackTrace, parameters = parameters.Keys.ToArray(), debugInfo = "Check Unity Console for detailed debug logs" }, Formatting.Indented); } } private string AddComponent(Dictionary parameters) { var componentType = parameters.GetValueOrDefault("componentType") ?? parameters.GetValueOrDefault("component") ?? parameters.GetValueOrDefault("type"); GameObject target = GetTargetGameObject(parameters); if (target == null) { string targetName = parameters.GetValueOrDefault("target") ?? parameters.GetValueOrDefault("gameObject") ?? parameters.GetValueOrDefault("object"); return $"Target object not found: {targetName}"; } // Try to find the component type Type type = GetComponentType(componentType); if (type == null) { return $"Component type not found: {componentType}"; } // Register to UNDO before adding component var component = UnityEditor.Undo.AddComponent(target, type); // Set component properties if provided (exclude system parameters) var excludedKeys = new[] { "target", "type", "componentType", "component", "gameObject", "object", "targetObject", "name", "objectName", "targetName", "source", "sourceName", "operationId" }; var propertyParams = parameters.Where(p => !excludedKeys.Contains(p.Key)).ToList(); SynLog.Info($"[AddComponent] Property parameters to set: {propertyParams.Count}"); foreach (var param in propertyParams) { SynLog.Info($"[AddComponent] - Will set: {param.Key} = {param.Value}"); } foreach (var kvp in propertyParams) { try { SetComponentProperty(component, kvp.Key, kvp.Value); SynLog.Info($"[AddComponent] Successfully set property {kvp.Key}"); } catch (Exception ex) { Debug.LogError($"[AddComponent] Failed to set property {kvp.Key}: {ex.Message}"); } } return $"Added {componentType} to {target.name}"; } private string SetProperty(Dictionary parameters) { var componentType = parameters.GetValueOrDefault("component"); var property = parameters.GetValueOrDefault("property"); var value = parameters.GetValueOrDefault("value"); // Validate required parameters if (string.IsNullOrEmpty(property)) { return "Error: 'property' parameter is required"; } var target = GetTargetGameObject(parameters); if (target == null) { string targetName = parameters.GetValueOrDefault("target") ?? parameters.GetValueOrDefault("gameObject") ?? parameters.GetValueOrDefault("object"); return $"Object not found: {targetName}"; } Component component = null; if (!string.IsNullOrEmpty(componentType)) { var type = GetComponentType(componentType); component = target.GetComponent(type); } else { component = target.transform; } if (component == null) return $"Component not found: {componentType}"; // Register to UNDO UnityEditor.Undo.RecordObject(component, "Set Property"); SetComponentProperty(component, property, value); return $"Set {property} = {value} on {target.name}"; } private string CreateUI(Dictionary parameters) { var uiType = parameters.GetValueOrDefault("type", "button"); var name = parameters.GetValueOrDefault("name", uiType); // Ensure Canvas exists var canvas = GameObject.FindObjectOfType(); if (canvas == null) { var canvasGO = new GameObject("Canvas"); canvas = canvasGO.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvasGO.AddComponent(); canvasGO.AddComponent(); // Add EventSystem if (GameObject.FindObjectOfType() == null) { var eventSystem = new GameObject("EventSystem"); eventSystem.AddComponent(); eventSystem.AddComponent(); } } GameObject uiElement = null; switch (uiType.ToLower()) { case "button": uiElement = CreateButton(name, parameters); break; case "text": uiElement = CreateText(name, parameters); break; case "inputfield": uiElement = CreateInputField(name, parameters); break; case "panel": uiElement = CreatePanel(name, parameters); break; case "image": uiElement = CreateImage(name, parameters); break; case "slider": uiElement = CreateSlider(name, parameters); break; case "toggle": uiElement = CreateToggle(name, parameters); break; case "dropdown": uiElement = CreateDropdown(name, parameters); break; } if (uiElement != null) { // Register to UNDO UnityEditor.Undo.RegisterCreatedObjectUndo(uiElement, $"Create UI {uiType}"); uiElement.transform.SetParent(canvas.transform, false); // Position if (parameters.TryGetValue("position", out var pos)) { var rt = uiElement.GetComponent(); rt.anchoredPosition = ParseVector2(pos); } // Size if (parameters.TryGetValue("size", out var size)) { var rt = uiElement.GetComponent(); rt.sizeDelta = ParseVector2(size); } lastCreatedObject = uiElement; createdObjects.Add(uiElement); return $"Created UI {uiType}: {name}"; } return $"Unknown UI type: {uiType}"; } /// /// Detailed UI canvas setup /// private string SetupUICanvas(Dictionary parameters) { try { var canvasName = parameters.GetValueOrDefault("canvasName", "Canvas"); var renderMode = parameters.GetValueOrDefault("renderMode", "overlay"); var sortingOrder = int.Parse(parameters.GetValueOrDefault("sortingOrder", "0")); var pixelPerfect = bool.Parse(parameters.GetValueOrDefault("pixelPerfect", "false")); // Find existing Canvas or create new Canvas canvas = null; GameObject canvasGO = GameObject.Find(canvasName); if (canvasGO != null) { canvas = canvasGO.GetComponent(); } if (canvas == null) { canvasGO = new GameObject(canvasName); canvas = canvasGO.AddComponent(); canvasGO.AddComponent(); canvasGO.AddComponent(); // Register Undo when creating new UnityEditor.Undo.RegisterCreatedObjectUndo(canvasGO, "Create UI Canvas"); } else { // Record Undo when editing existing Canvas UnityEditor.Undo.RecordObject(canvas, "Setup UI Canvas"); UnityEditor.Undo.RecordObject(canvasGO.transform, "Setup UI Canvas Transform"); } // RenderMode settings switch (renderMode.ToLower()) { case "overlay": case "screenspace-overlay": canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = sortingOrder; canvas.pixelPerfect = pixelPerfect; break; case "camera": case "screenspace-camera": canvas.renderMode = RenderMode.ScreenSpaceCamera; // Camera settings var cameraName = parameters.GetValueOrDefault("camera", "Main Camera"); Camera uiCamera = null; if (cameraName == "Main Camera") { uiCamera = Camera.main; } else if (cameraName == "new") { // Create dedicated UI camera var uiCameraGO = new GameObject("UI Camera"); uiCamera = uiCameraGO.AddComponent(); UnityEditor.Undo.RegisterCreatedObjectUndo(uiCameraGO, "Create UI Camera"); uiCamera.clearFlags = CameraClearFlags.Depth; uiCamera.cullingMask = LayerMask.GetMask("UI"); uiCamera.orthographic = true; uiCamera.depth = 1; // Render above Main Camera } else { var cameraGO = GameObject.Find(cameraName); if (cameraGO != null) uiCamera = cameraGO.GetComponent(); } if (uiCamera != null) { canvas.worldCamera = uiCamera; } canvas.planeDistance = float.Parse(parameters.GetValueOrDefault("planeDistance", "100")); canvas.sortingOrder = sortingOrder; canvas.pixelPerfect = pixelPerfect; break; case "world": case "worldspace": canvas.renderMode = RenderMode.WorldSpace; // World Space settings var position = parameters.GetValueOrDefault("position", "0,0,0"); var rotation = parameters.GetValueOrDefault("rotation", "0,0,0"); var scale = parameters.GetValueOrDefault("scale", "0.01,0.01,0.01"); canvasGO.transform.position = ParseVector3(position); canvasGO.transform.rotation = Quaternion.Euler(ParseVector3(rotation)); canvasGO.transform.localScale = ParseVector3(scale); // RectTransform size settings var rectTransform = canvasGO.GetComponent(); if (parameters.TryGetValue("sizeDelta", out var sizeDelta)) { rectTransform.sizeDelta = ParseVector2(sizeDelta); } else { rectTransform.sizeDelta = new Vector2(1920, 1080); // Default size } break; } // Canvas Scaler settings var canvasScaler = canvasGO.GetComponent(); if (canvasScaler != null && canvas.renderMode != RenderMode.WorldSpace) { var scaleMode = parameters.GetValueOrDefault("scaleMode", "scale-with-screen"); switch (scaleMode.ToLower()) { case "constant-pixel": canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ConstantPixelSize; canvasScaler.scaleFactor = float.Parse(parameters.GetValueOrDefault("scaleFactor", "1")); break; case "scale-with-screen": canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; canvasScaler.referenceResolution = ParseVector2(parameters.GetValueOrDefault("referenceResolution", "1920,1080")); canvasScaler.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; canvasScaler.matchWidthOrHeight = float.Parse(parameters.GetValueOrDefault("match", "0.5")); break; case "constant-physical": canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ConstantPhysicalSize; canvasScaler.physicalUnit = CanvasScaler.Unit.Points; canvasScaler.referencePixelsPerUnit = float.Parse(parameters.GetValueOrDefault("pixelsPerUnit", "100")); break; } } // Check and create EventSystem if (GameObject.FindObjectOfType() == null) { var eventSystem = new GameObject("EventSystem"); eventSystem.AddComponent(); eventSystem.AddComponent(); } return JsonConvert.SerializeObject(new { success = true, message = $"Canvas '{canvasName}' configured successfully", canvasName = canvasName, renderMode = canvas.renderMode.ToString(), settings = new { sortingOrder = canvas.sortingOrder, pixelPerfect = canvas.pixelPerfect, worldCamera = canvas.worldCamera?.name, planeDistance = canvas.planeDistance, position = canvasGO.transform.position, rotation = canvasGO.transform.rotation.eulerAngles, scale = canvasGO.transform.localScale } }, Formatting.Indented); } catch (Exception e) { return CreateErrorResponse($"Error setting up UI Canvas: {e.Message}"); } } /// /// Set UI anchor /// private string SetUIAnchor(Dictionary parameters) { try { var targetName = parameters.GetValueOrDefault("target", ""); var preset = parameters.GetValueOrDefault("preset", ""); if (string.IsNullOrEmpty(targetName)) { return CreateErrorResponse("Target UI element name must be provided"); } GameObject target = GameObject.Find(targetName); if (target == null) { return CreateErrorResponse($"GameObject '{targetName}' not found"); } RectTransform rectTransform = target.GetComponent(); if (rectTransform == null) { return CreateErrorResponse($"GameObject '{targetName}' does not have RectTransform component"); } // Record Undo UnityEditor.Undo.RecordObject(rectTransform, "Set UI Anchor"); // For custom values if (string.IsNullOrEmpty(preset) || preset.ToLower() == "custom") { // anchorMin if (parameters.TryGetValue("anchorMin", out var anchorMin)) { rectTransform.anchorMin = ParseVector2(anchorMin); } // anchorMax if (parameters.TryGetValue("anchorMax", out var anchorMax)) { rectTransform.anchorMax = ParseVector2(anchorMax); } // pivot if (parameters.TryGetValue("pivot", out var pivot)) { rectTransform.pivot = ParseVector2(pivot); } // anchoredPosition if (parameters.TryGetValue("anchoredPosition", out var anchoredPos)) { rectTransform.anchoredPosition = ParseVector2(anchoredPos); } // sizeDelta if (parameters.TryGetValue("sizeDelta", out var sizeDelta)) { rectTransform.sizeDelta = ParseVector2(sizeDelta); } } else { // Apply preset ApplyAnchorPreset(rectTransform, preset, parameters); } return JsonConvert.SerializeObject(new { success = true, message = $"UI anchor set for {targetName}", target = targetName, preset = string.IsNullOrEmpty(preset) ? "custom" : preset, anchorMin = new { x = rectTransform.anchorMin.x, y = rectTransform.anchorMin.y }, anchorMax = new { x = rectTransform.anchorMax.x, y = rectTransform.anchorMax.y }, pivot = new { x = rectTransform.pivot.x, y = rectTransform.pivot.y }, anchoredPosition = new { x = rectTransform.anchoredPosition.x, y = rectTransform.anchoredPosition.y }, sizeDelta = new { x = rectTransform.sizeDelta.x, y = rectTransform.sizeDelta.y } }, Formatting.Indented); } catch (Exception e) { return CreateErrorResponse($"Error setting UI anchor: {e.Message}"); } } /// /// Apply anchor preset /// private void ApplyAnchorPreset(RectTransform rectTransform, string preset, Dictionary parameters) { bool keepPosition = bool.Parse(parameters.GetValueOrDefault("keepPosition", "false")); bool keepSize = bool.Parse(parameters.GetValueOrDefault("keepSize", "false")); Vector2 currentPos = rectTransform.anchoredPosition; Vector2 currentSize = rectTransform.sizeDelta; switch (preset.ToLower()) { // Center case "center": case "middle-center": rectTransform.anchorMin = new Vector2(0.5f, 0.5f); rectTransform.anchorMax = new Vector2(0.5f, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); break; // Top case "top-left": rectTransform.anchorMin = new Vector2(0, 1); rectTransform.anchorMax = new Vector2(0, 1); rectTransform.pivot = new Vector2(0, 1); break; case "top-center": rectTransform.anchorMin = new Vector2(0.5f, 1); rectTransform.anchorMax = new Vector2(0.5f, 1); rectTransform.pivot = new Vector2(0.5f, 1); break; case "top-right": rectTransform.anchorMin = new Vector2(1, 1); rectTransform.anchorMax = new Vector2(1, 1); rectTransform.pivot = new Vector2(1, 1); break; // Middle case "middle-left": rectTransform.anchorMin = new Vector2(0, 0.5f); rectTransform.anchorMax = new Vector2(0, 0.5f); rectTransform.pivot = new Vector2(0, 0.5f); break; case "middle-right": rectTransform.anchorMin = new Vector2(1, 0.5f); rectTransform.anchorMax = new Vector2(1, 0.5f); rectTransform.pivot = new Vector2(1, 0.5f); break; // Bottom case "bottom-left": rectTransform.anchorMin = new Vector2(0, 0); rectTransform.anchorMax = new Vector2(0, 0); rectTransform.pivot = new Vector2(0, 0); break; case "bottom-center": rectTransform.anchorMin = new Vector2(0.5f, 0); rectTransform.anchorMax = new Vector2(0.5f, 0); rectTransform.pivot = new Vector2(0.5f, 0); break; case "bottom-right": rectTransform.anchorMin = new Vector2(1, 0); rectTransform.anchorMax = new Vector2(1, 0); rectTransform.pivot = new Vector2(1, 0); break; // Stretch case "stretch-horizontal": rectTransform.anchorMin = new Vector2(0, 0.5f); rectTransform.anchorMax = new Vector2(1, 0.5f); rectTransform.pivot = new Vector2(0.5f, 0.5f); break; case "stretch-vertical": rectTransform.anchorMin = new Vector2(0.5f, 0); rectTransform.anchorMax = new Vector2(0.5f, 1); rectTransform.pivot = new Vector2(0.5f, 0.5f); break; case "stretch-all": case "fill": rectTransform.anchorMin = new Vector2(0, 0); rectTransform.anchorMax = new Vector2(1, 1); rectTransform.pivot = new Vector2(0.5f, 0.5f); // Set offset for stretch if (parameters.TryGetValue("offset", out var offsetStr)) { float offset = float.Parse(offsetStr); rectTransform.offsetMin = new Vector2(offset, offset); rectTransform.offsetMax = new Vector2(-offset, -offset); } else { rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; } break; // Special presets case "top-stretch": rectTransform.anchorMin = new Vector2(0, 1); rectTransform.anchorMax = new Vector2(1, 1); rectTransform.pivot = new Vector2(0.5f, 1); break; case "bottom-stretch": rectTransform.anchorMin = new Vector2(0, 0); rectTransform.anchorMax = new Vector2(1, 0); rectTransform.pivot = new Vector2(0.5f, 0); break; case "left-stretch": rectTransform.anchorMin = new Vector2(0, 0); rectTransform.anchorMax = new Vector2(0, 1); rectTransform.pivot = new Vector2(0, 0.5f); break; case "right-stretch": rectTransform.anchorMin = new Vector2(1, 0); rectTransform.anchorMax = new Vector2(1, 1); rectTransform.pivot = new Vector2(1, 0.5f); break; } // Keep position and size if (keepPosition && preset.ToLower() != "stretch-all" && preset.ToLower() != "fill") { rectTransform.anchoredPosition = currentPos; } if (keepSize && preset.ToLower() != "stretch-all" && preset.ToLower() != "fill") { rectTransform.sizeDelta = currentSize; } } private GameObject CreateButton(string name, Dictionary parameters) { var button = new GameObject(name); var rt = button.AddComponent(); rt.sizeDelta = new Vector2(160, 40); var image = button.AddComponent(); image.color = new Color(0.9f, 0.9f, 0.9f); var btn = button.AddComponent