Browse Source

Refactor C# editor build support

Josh Engebretson 9 years ago
parent
commit
fdac02331b

+ 22 - 1
Script/AtomicEditor/hostExtensions/languageExtensions/CSharpLanguageExtension.ts

@@ -21,6 +21,7 @@
 //
 
 import * as EditorEvents from "../../editor/EditorEvents";
+import EditorUI = require("ui/EditorUI");
 
 /**
 * Resource extension that supports the web view typescript extension
@@ -40,6 +41,9 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
     /** Reference to the compileOnSaveMenuItem */
     private compileOnSaveMenuItem: Atomic.UIMenuItem;
 
+    //** A script object so we can take part in event handling
+    private eventObject = new Atomic.ScriptObject();
+
     /**
     * Determines if the file name/path provided is something we care about
     * @param  {string} path
@@ -154,12 +158,28 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
         };
 
         if (found) {
+
             this.isNETProject = true;
             this.configureNETProjectMenu();
+
+            this.eventObject.subscribeToEvent("NETBuildResult", (eventData:ToolCore.NETBuildResult) => {
+
+                if (!eventData.success) {
+
+                    let errorText = eventData.errorText;
+                    let index = errorText.lastIndexOf("Errors:");
+                    if (index != -1) {
+                        errorText = errorText.substr(index);
+                    }
+
+                    EditorUI.getModelOps().showError("NET Build Error", errorText);
+
+                }
+
+            });
         }
     }
 
-
     /**
     * Called when the project is unloaded
     */
@@ -168,6 +188,7 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
         this.serviceRegistry.uiServices.removePluginMenuItemSource("AtomicNET");
         this.menuCreated = false;
         this.isNETProject = false;
+        this.eventObject.unsubscribeFromAllEvents();
     }
 
     /*** UIService implementation ***/

+ 2 - 8
Script/AtomicEditor/ui/AnimationToolbar.ts

@@ -25,7 +25,6 @@ import EditorUI = require("ui/EditorUI");
 import HierarchyFrame = require("ui/frames/HierarchyFrame");
 import InspectorUtils = require("ui/frames/inspector/InspectorUtils");
 import ResourceOps = require("resources/ResourceOps");
-import ModalOps = require("ui/modal/ModalOps");
 
 class AnimationToolbar extends Atomic.UIWidget {
 
@@ -75,8 +74,6 @@ class AnimationToolbar extends Atomic.UIWidget {
 
         properties.addChild(this.animationPropertiesContainer);
 
-        this.modalOps = new ModalOps();
-
     }
 
     handleWidgetEvent(ev: Atomic.UIWidgetEvent): boolean {
@@ -112,7 +109,7 @@ class AnimationToolbar extends Atomic.UIWidget {
                     if (this.animationController.playExclusive(this.rightAnimEditfield.text, 0, true, Number(this.blendSpeed.text)))
                         this.animationController.setSpeed(this.rightAnimEditfield.text, Number(this.animationSpeed.text));
                     else
-                        this.modalOps.showError("Animation Toolbar Warning", "The animation cannot be played. Please make sure the animation you are trying to play exists in the AnimationController Component.");
+                        EditorUI.getModelOps().showError("Animation Toolbar Warning", "The animation cannot be played. Please make sure the animation you are trying to play exists in the AnimationController Component.");
 
                     return true;
                 }
@@ -192,10 +189,9 @@ class AnimationToolbar extends Atomic.UIWidget {
         });
     }
     showAnimationWarning() {
-        this.modalOps.showError("Animation Preview Warning", "The animation cannot be played. Please make sure the animation you are trying to play exists in the AnimationController Component.");
+        EditorUI.getModelOps().showError("Animation Preview Warning", "The animation cannot be played. Please make sure the animation you are trying to play exists in the AnimationController Component.");
     }
 
-    modalOps: ModalOps;
     //Animation Toolbar Widgets
     animationController: Atomic.AnimationController;
     animatedModel: Atomic.AnimatedModel;
@@ -222,5 +218,3 @@ class AnimationToolbar extends Atomic.UIWidget {
 }
 
 export = AnimationToolbar;
-
-

+ 2 - 5
Script/AtomicEditor/ui/Shortcuts.ts

@@ -39,12 +39,9 @@ class Shortcuts extends Atomic.ScriptObject {
 
     //this should be moved somewhere else...
     invokePlayOrStopPlayer(debug: boolean = false) {
+
         this.sendEvent(EditorEvents.SaveAllResources);
 
-        if ( ToolCore.netProjectSystem.solutionAvailable)   // are we a csharp project
-            if( ToolCore.netProjectSystem.buildAndRun() )   // do we need to rebuild?
-                return;  // if yes, return, the play event will be reissued after the rebuild
-      
         if (Atomic.editorMode.isPlayerEnabled()) {
             this.sendEvent("IPCPlayerExitRequest");
         } else {
@@ -221,7 +218,7 @@ class Shortcuts extends Atomic.ScriptObject {
     handleUIShortcut(ev: Atomic.UIShortcutEvent) {
 
         var cmdKey = this.cmdKeyDown();
-    
+
         if ( !cmdKey && ev.qualifiers > 0 ) // check the event, the qualifier may have been programmitically set
         {
             cmdKey = ( ev.qualifiers == Atomic.QUAL_CTRL );

+ 1 - 1
Script/Packages/ToolCore/ToolCore.json

@@ -11,7 +11,7 @@
 							 "TextureImporter", "SpriterImporter", "PEXImporter", "CSharpImporter", "NETAssemblyImporter",
 							 "LicenseSystem",
 						 	 "ProjectUserPrefs", "ProjectBuildSettings",
-							 "NETProjectSystem",
+							 "NETProjectSystem", "NETBuild",
 						 	 "BuildBase", "BuildSystem", "BuildMac", "BuildWeb", "BuildWindows", "BuildAndroid", "BuildIOS", "BuildLinux",
 						 	 "ProjectBuildSettings", "MacBuildSettings", "WindowsBuildSettings", "WebBuildSettings", "AndroidBuildSettings", "IOSBuildSettings", "LinuxBuildSettings"],
 	"typescript_decl" : {

+ 8 - 1
Script/TypeScript/AtomicWork.d.ts

@@ -270,7 +270,7 @@ declare module Atomic {
         resourceTypeName: string;
         dynamic: boolean;
         tooltip: string;
-        
+
     }
 
     export interface ShaderParameter {
@@ -432,6 +432,13 @@ declare module ToolCore {
 
     }
 
+    export interface NETBuildResult {
+
+        success: boolean;
+        build: NETBuild;
+        errorText: string;
+    }
+
     export var toolEnvironment: ToolEnvironment;
     export var toolSystem: ToolSystem;
     export var assetDatabase: AssetDatabase;

+ 1 - 1
Script/tsconfig.json

@@ -37,6 +37,7 @@
         "./AtomicEditor/resources/ProjectTemplates.ts",
         "./AtomicEditor/resources/ResourceOps.ts",
         "./AtomicEditor/resources/SearchBarFiltering.ts",
+        "./AtomicEditor/ui/AnimationToolbar.ts",
         "./AtomicEditor/ui/EditorStrings.ts",
         "./AtomicEditor/ui/EditorUI.ts",
         "./AtomicEditor/ui/frames/HierarchyFrame.ts",
@@ -71,7 +72,6 @@
         "./AtomicEditor/ui/frames/ResourceFrame.ts",
         "./AtomicEditor/ui/frames/WelcomeFrame.ts",
         "./AtomicEditor/ui/MainToolbar.ts",
-        "./AtomicEditor/ui/AnimationToolbar.ts",
         "./AtomicEditor/ui/modal/About.ts",
         "./AtomicEditor/ui/modal/build/BuildComplete.ts",
         "./AtomicEditor/ui/modal/build/BuildOutput.ts",

+ 54 - 1
Source/AtomicEditor/EditorMode/AEEditorMode.cpp

@@ -35,6 +35,9 @@
 #include <ToolCore/Project/Project.h>
 #include <ToolCore/Project/ProjectSettings.h>
 
+#include <ToolCore/NETTools/NETProjectSystem.h>
+#include <ToolCore/NETTools/NETBuildSystem.h>
+
 #include <AtomicJS/Javascript/JSIPCEvents.h>
 
 #include <Atomic/UI/SystemUI/DebugHud.h>
@@ -49,7 +52,9 @@ namespace AtomicEditor
 {
 
 EditorMode::EditorMode(Context* context) :
-    Object(context)
+    Object(context),
+    playerEnabled_(false),
+    debug_(false)
 {
 
 }
@@ -118,7 +123,55 @@ void EditorMode::HandleIPCJSError(StringHash eventType, VariantMap& eventData)
 
 }
 
+void EditorMode::HandleNETBuildResult(StringHash eventType, VariantMap& eventData)
+{
+
+    using namespace NETBuildResult;
+
+    if (eventData[P_SUCCESS].GetBool())
+    {
+        NETProjectSystem* netProjectSystem = GetSubsystem<NETProjectSystem>();
+
+        if (!netProjectSystem->GetSolutionAvailable() || netProjectSystem->GetProjectAssemblyDirty())
+        {
+            ATOMIC_LOGERROR("EditorMode::HandleNETBuildResult() - NETBuild was successful, however project still reported as dirty or missing");
+        }
+
+        PlayProjectInternal(additionalArgs_, debug_);
+    }
+
+    additionalArgs_.Clear();
+    debug_ = false;
+
+}
+
 bool EditorMode::PlayProject(String addArgs, bool debug)
+{
+    additionalArgs_ = addArgs;
+    debug_ = debug;
+
+    NETProjectSystem* netProjectSystem = GetSubsystem<NETProjectSystem>();
+
+    // If we're a net project, with a solution, and the project assembly is dirty build before playing
+    if (netProjectSystem && netProjectSystem->GetSolutionAvailable() && netProjectSystem->GetProjectAssemblyDirty())
+    {
+        NETBuild* build = netProjectSystem->BuildAtomicProject();
+
+        if (!build)
+        {
+            ATOMIC_LOGERROR("EditorMode::PlayProject() - Unable to instantiate C# build");
+            return false;
+        }
+
+        SubscribeToEvent(build, E_NETBUILDRESULT, ATOMIC_HANDLER(EditorMode, HandleNETBuildResult));
+
+        return true;
+    }
+
+    return PlayProjectInternal(addArgs, debug);
+}
+
+bool EditorMode::PlayProjectInternal(const String &addArgs, bool debug)
 {
     if (playerBroker_.NotNull())
         return false;

+ 7 - 1
Source/AtomicEditor/EditorMode/AEEditorMode.h

@@ -52,6 +52,8 @@ public:
 
 private:
 
+    bool PlayProjectInternal(const String& addArgs, bool debug);
+
     void HandleIPCWorkerStarted(StringHash eventType, VariantMap& eventData);
     void HandleIPCJSError(StringHash eventType, VariantMap& eventData);
     void HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData);
@@ -61,9 +63,13 @@ private:
     void HandleIPCPlayerPauseStepRequest(StringHash eventType, VariantMap& eventData);
     void HandleIPCPlayerExitRequest(StringHash eventType, VariantMap& eventData);
 
+    void HandleNETBuildResult(StringHash eventType, VariantMap& eventData);
+
     SharedPtr<IPCBroker> playerBroker_;
 
-    bool playerEnabled_ = false;
+    bool playerEnabled_;
+    String additionalArgs_;
+    bool debug_;
 
 };
 

+ 8 - 0
Source/ToolCore/NETTools/NETBuildSystem.cpp

@@ -44,6 +44,14 @@
 
 namespace ToolCore
 {
+    NETBuild::NETBuild(Context* context, const String& solutionPath) :
+        Object(context),
+        solutionPath_(solutionPath),
+        status_(NETBUILD_PENDING)
+    {
+
+    }
+
 
     NETBuild::NETBuild(Context* context, const String& solutionPath, const StringVector& platforms, const StringVector& configurations) :
         Object(context),

+ 1 - 0
Source/ToolCore/NETTools/NETBuildSystem.h

@@ -62,6 +62,7 @@ namespace ToolCore
     
     public:
 
+        NETBuild(Context* context, const String& solutionPath = String::EMPTY);
         NETBuild(Context* context, const String& solutionPath, const StringVector& platforms, const StringVector& configurations);
         virtual ~NETBuild() {}
 

+ 54 - 104
Source/ToolCore/NETTools/NETProjectSystem.cpp

@@ -29,10 +29,6 @@
 #include <Atomic/IO/FileSystem.h>
 #include <Atomic/Resource/ResourceEvents.h>
 
-#include <Atomic/UI/UIEvents.h>
-#include <Atomic/Input/InputEvents.h>
-#include <AtomicEditor/EditorMode/AEEditorEvents.h>
-
 #include "../ToolSystem.h"
 #include "../ToolEnvironment.h"
 #include "../Assets/AssetEvents.h"
@@ -192,24 +188,11 @@ namespace ToolCore
 
             ATOMIC_LOGERRORF("\n%s\n", errorText.CString());
             ATOMIC_LOGERRORF("NETBuild Error for project");
-            
-            String myerror; // too much error for the dialog! scrape off just the error summary
-            unsigned where = errorText.Find("Errors:", 0, true);
-            if ( where != String::NPOS)
-                myerror = errorText.Substring (where, errorText.Length() - where);
-            else myerror = errorText; // failed to find summary, send the whole text
-            
-            using namespace AtomicEditor;
-            VariantMap errorData;
-            errorData[EditorModal::P_TYPE] = EDITOR_MODALERROR;
-            errorData[EditorModal::P_TITLE] = String("NETBuild Errors");
-            errorData[EditorModal::P_MESSAGE] = myerror;
-            SendEvent(E_EDITORMODAL, errorData);
         }
 
     }
 
-    void NETProjectSystem::BuildAtomicProject()
+    NETBuild* NETProjectSystem::BuildAtomicProject()
     {
         FileSystem* fileSystem = GetSubsystem<FileSystem>();
 
@@ -218,7 +201,7 @@ namespace ToolCore
             if (!GenerateSolution())
             {
                 ATOMIC_LOGERRORF("NETProjectSystem::BuildAtomicProject - solutionPath does not exist: %s", solutionPath_.CString());
-                return;
+                return nullptr;
             }
         }
 
@@ -234,7 +217,10 @@ namespace ToolCore
                 build->SubscribeToEvent(E_NETBUILDRESULT, ATOMIC_HANDLER(NETProjectSystem, HandleNETBuildResult));
             }
 
+            return build;
         }
+
+        return nullptr;
     }
 
     bool NETProjectSystem::GenerateResourcePak()
@@ -375,8 +361,7 @@ namespace ToolCore
         if (!fileSystem->FileExists(solutionPath_))
             solutionDirty_ = true;
 
-        if (!fileSystem->FileExists(projectAssemblyPath_))
-            projectAssemblyDirty_ = true;
+        CheckProjectAssembly();
 
     }
 
@@ -438,100 +423,69 @@ namespace ToolCore
 
     }
 
-    /// handle the results of a recompile, and auto play the project if successful
-    void NETProjectSystem::HandleNETBuildPlay(StringHash eventType, VariantMap& eventData)
+    bool NETProjectSystem::GetProjectAssemblyDirty()
     {
-        using namespace NETBuildResult;
-        
-        if (eventData[P_SUCCESS].GetBool())
+        if (projectAssemblyDirty_)
+            return true;
+
+        CheckProjectAssembly();
+
+        return projectAssemblyDirty_;
+
+    }
+    
+    void NETProjectSystem::CheckProjectAssembly()
+    {
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        ToolSystem* tsystem = GetSubsystem<ToolSystem>();
+        Project* project = tsystem->GetProject();
+
+        if (!project || !projectAssemblyPath_.Length())
         {
-            ATOMIC_LOGINFOF("NETBuild Success for project, now playing.");
-            VariantMap shortcutData;  // encode a shortcut event to send a play
-            shortcutData[UIShortcut::P_KEY] = KEY_P;
-            shortcutData[UIShortcut::P_QUALIFIERS] = QUAL_CTRL;
-            SendEvent(E_UISHORTCUT, shortcutData);
+            ATOMIC_LOGERROR("NETProjectSystem::CheckProjectAssembly() - Called with no project loaded or an empty project assembly path");
+            projectAssemblyDirty_ = false;
+            return;
         }
-        else
+
+        if (projectAssemblyDirty_)
+            return;
+
+        // If we don't have a project or the project assembly is missing, we must rebuild
+        if (!fileSystem->FileExists(projectAssemblyPath_))
         {
-            const String& errorText = eventData[P_ERRORTEXT].GetString();
+            projectAssemblyDirty_ = true;
+            return;
+        }
 
-            ATOMIC_LOGERRORF("\n%s\n", errorText.CString());
-            ATOMIC_LOGERRORF("NETBuild Error for project, will not play.");
-           
-            String myerror; // too much error for the dialog! scrape off just the error summary
-            unsigned where = errorText.Find("Errors:", 0, true);
-            if ( where != String::NPOS)
-                myerror = errorText.Substring (where, errorText.Length() - where);
-            else myerror = errorText; // failed to find summary, send the whole text
-            
-            using namespace AtomicEditor;
-            VariantMap errorData;
-            errorData[EditorModal::P_TYPE] = EDITOR_MODALERROR;
-            errorData[EditorModal::P_TITLE] = String("NETBuild Error for project");
-            errorData[EditorModal::P_MESSAGE] = myerror;
-            SendEvent(E_EDITORMODAL, errorData);
+        StringVector results;
+
+        // timestamps for present assemblies, use the filesystem and not asset db as the later is cached
+        PODVector<unsigned> assemblyTimestamps;
+
+        fileSystem->ScanDir(results, project->GetResourcePath(), "*.dll", SCAN_FILES, true);
+
+        for (unsigned i = 0; i < results.Size(); i++)
+        {
+            assemblyTimestamps.Push(fileSystem->GetLastModifiedTime(project->GetResourcePath() + results[i]));
         }
 
-    }
+        fileSystem->ScanDir(results, project->GetResourcePath(), "*.cs", SCAN_FILES, true);
 
-    /// used to ensure the project can be run from the editor
-    bool NETProjectSystem::BuildAndRun()
-    {
-        bool shouldRebuild = CheckForRebuild();
-        if (shouldRebuild) 
+        for (unsigned i = 0; i < results.Size(); i++)
         {
-            FileSystem* fileSystem = GetSubsystem<FileSystem>();
-            if (!fileSystem->FileExists(solutionPath_))
+            unsigned timestamp = fileSystem->GetLastModifiedTime(project->GetResourcePath() + results[i]);
+
+            for (unsigned j = 0; j < assemblyTimestamps.Size(); j++)
             {
-                if (!GenerateSolution())
+                if (timestamp > assemblyTimestamps[j])
                 {
-                    ATOMIC_LOGERRORF("NETProjectSystem::BuildAtomicProject - solutionPath does not exist: %s", solutionPath_.CString());
-                    return false;
+                    projectAssemblyDirty_ = true;
+                    return;
                 }
             }
 
-            Project* project = GetSubsystem<ToolSystem>()->GetProject();
-            NETBuildSystem* buildSystem = GetSubsystem<NETBuildSystem>();
-            if (buildSystem)
-            {
-                NETBuild* build = buildSystem->BuildAtomicProject(project);
-                if (build)
-                {
-                    build->SubscribeToEvent(E_NETBUILDRESULT, ATOMIC_HANDLER(NETProjectSystem, HandleNETBuildPlay));
-                }
-            }       
         }
-        
-        return shouldRebuild;
-    }
-    
-    /// interrogate sources to see if any are dirty compared to the editor project.dll
-    bool NETProjectSystem::CheckForRebuild() 
-    {
-        FileSystem* fileSystem = GetSubsystem<FileSystem>();
-        AssetDatabase* db = GetSubsystem<AssetDatabase>();
-        Project* project = GetSubsystem<ToolSystem>()->GetProject();
-        unsigned dllTimestamp = 0;
-
-        String mydll = project->GetResourcePath() + project->GetProjectSettings()->GetName() + ".dll";
-        Asset* myasset = db->GetAssetByPath(mydll);
-        if (myasset)
-            dllTimestamp = myasset->GetFileTimestamp();  
-        else 
-            return true; // dll not there, needs to be built, or the sources dont compile, or some other error
- 
-        int nn=0;
-        Asset* filex = NULL;
-        StringVector results;
-        String tdir = AddTrailingSlash(project->GetResourcePath());
-        fileSystem->ScanDir(results, tdir, "*.cs", SCAN_FILES, true);
-        for (nn=0; nn<results.Size(); nn++)
-        {
-            filex = db->GetAssetByPath(tdir + results[nn]);
-            if (filex && filex->GetFileTimestamp() > dllTimestamp )
-                return true;  // some file is younger or dirtier, dll needs to be rebuilt
-         }
-        return false; // the dll is up to date, no need to recompile
+
     }
     
     void NETProjectSystem::Initialize()
@@ -648,12 +602,9 @@ namespace ToolCore
 
                 if (srcModifiedTime == fileSystem->GetLastModifiedTime(dstFile))
                 {
-                    ATOMIC_LOGDEBUGF("NETProjectSystem::CopyAtomicAssemblies - Skipping AtomicNET %s as %s exists and has same modified time", srcFile.CString(), dstFile.CString());
                     continue;
                 }
 
-                ATOMIC_LOGDEBUGF("NETProjectSystem::CopyAtomicAssemblies - %u %u", srcModifiedTime, fileSystem->GetLastModifiedTime(dstFile));
-
             }
 
             String dstPath = GetPath(dstFile);
@@ -674,7 +625,6 @@ namespace ToolCore
             if (srcModifiedTime)
                 fileSystem->SetLastModifiedTime(dstFile, srcModifiedTime);
 
-            ATOMIC_LOGDEBUGF(" NETProjectSystem::CopyAtomicAssemblies - Copied AtomicNET %s to %s", srcFile.CString(), dstPath.CString());
         }
 
         return true;

+ 8 - 7
Source/ToolCore/NETTools/NETProjectSystem.h

@@ -31,6 +31,7 @@ namespace ToolCore
 
     class Project;
     class Subprocess;
+    class NETBuild;
 
     // AtomicProject.dll state (this shouldn't be in resources too)
 
@@ -57,7 +58,7 @@ namespace ToolCore
 
         const String& GetSolutionPath() const { return solutionPath_; }
 
-        void BuildAtomicProject();
+        NETBuild* BuildAtomicProject();
 
         /// Open the solution, if opening a source file, better to call OpenSourceFile as will launch VS instance with source file loaded
         /// otherwise, no guarantee where source file will load when multiple VS instances running
@@ -68,15 +69,14 @@ namespace ToolCore
         bool GenerateSolution();
         bool GenerateResourcePak();
 
-        /// build csharp dll if sources are dirty and then run
-        bool BuildAndRun();
-        
+        /// Get whether the project assembly is dirty and needs to be rebuilt
+        bool GetProjectAssemblyDirty();
+
     private:
 
         void HandleUpdate(StringHash eventType, VariantMap& eventData);
 
         void HandleNETBuildResult(StringHash eventType, VariantMap& eventData);
-        void HandleNETBuildPlay(StringHash eventType, VariantMap& eventData);
 
         void HandleFileChanged(StringHash eventType, VariantMap& eventData);
         void HandleResourceAdded(StringHash eventType, VariantMap& eventData);
@@ -93,8 +93,9 @@ namespace ToolCore
 
         void Clear();
         void Initialize();
-        /// interrogate sources to see if any are younger than the editor dll
-        bool CheckForRebuild();
+
+        /// Checks the status of the project assembly, including if sources files are newer, missing, etc
+        void CheckProjectAssembly();
 
         String idePath_;