Browse Source

Merge pull request #1006 from AtomicGameEngine/JME-ATOMICNET-ANDROIDNATIVE

Android C# support for redistributable Atomic Editor binary builds
JoshEngebretson 9 years ago
parent
commit
0d3ef23083

+ 25 - 25
Build/Scripts/BuildAndroid.js

@@ -8,40 +8,40 @@ var buildDir = host.artifactsRoot + "Build/Android/";
 
 namespace('build', function() {
 
-  task('android_player', ["build:atomiceditor"], {
-    async: true
-  }, function() {
+    task('android_native', {
+        async: true
+    }, function() {
 
-    // Clean build
-    common.cleanCreateDir(buildDir);
+        // Clean build
+        common.cleanCreateDir(buildDir);
 
-    process.chdir(buildDir);
+        process.chdir(buildDir);
 
-    var cmds = [];
+        var cmds = [];
 
-    if (os.platform() == "win32") {
-      cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAndroid.bat");
-    }
-    else {
-      cmds.push("cmake -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=../../../Build/CMake/Toolchains/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release ../../../");
-      cmds.push("make -j4");
-    }
+        if (os.platform() == "win32") {
+            cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAndroid.bat");
+        }
+        else {
+            cmds.push("cmake -G \"Unix Makefiles\" -DCMAKE_TOOLCHAIN_FILE=../../../Build/CMake/Toolchains/android.toolchain.cmake -DCMAKE_BUILD_TYPE=Release ../../../");
+            cmds.push("make -j4");
+        }
 
-    jake.exec(cmds, function() {
+        jake.exec(cmds, function() {
 
-      var editorAppFolder = host.artifactsRoot + (os.platform() == "win32" ? "AtomicEditor/" : "AtomicEditor/AtomicEditor.app/");
+            var editorAppFolder = host.artifactsRoot + (os.platform() == "win32" ? "AtomicEditor/" : "AtomicEditor/AtomicEditor.app/");
 
-      // Install Deployment
-      fs.copySync(buildDir + "Source/AtomicPlayer/Application/libAtomicPlayer.so",
-        editorAppFolder + "Resources/ToolData/Deployment/Android/libs/armeabi-v7a/libAtomicPlayer.so");
+            // Install Deployment
+            fs.copySync(buildDir + "Source/AtomicPlayer/Application/libAtomicPlayer.so",
+            editorAppFolder + "Contents/Resources/ToolData/Deployment/Android/libs/armeabi-v7a/libAtomicPlayer.so");
 
-      complete();
+            complete();
 
-    }, {
-      printStdout: true,
-      breakOnError : false
-    });
+        }, {
+            printStdout: true,
+            breakOnError : false
+        });
 
-  });
+    });
 
 }); // end of build namespace

+ 87 - 67
Build/Scripts/BuildMac.js

@@ -6,108 +6,128 @@ var atomicRoot = host.atomicRoot;
 
 var buildDir = host.artifactsRoot + "Build/Mac/";
 var editorAppFolder = host.artifactsRoot + "/AtomicEditor/AtomicEditor.app/";
+var resourceDest = editorAppFolder + "/Contents/Resources/"
 
 namespace('build', function() {
 
-// Builds a standalone Atomic Editor, which can be distributed out of build tree
-task('atomiceditor', {
-  async: true
-}, function() {
+    // Builds a standalone Atomic Editor, which can be distributed out of build tree
+    task('atomiceditor', {
+        async: true
+    }, function(android) {
 
-  // Clean build
-  var cleanBuild = true;
-  if (cleanBuild) {
-    common.cleanCreateDir(buildDir);
-    common.cleanCreateDir(editorAppFolder);
-    common.cleanCreateDir(host.getGenScriptRootDir("MACOSX"));
-  }
+        android = android == "android" ? true : false;
 
-  var buildAtomicNET = spawnSync("which", ["xbuild"]).status == 1 ? false : true;
+        // Clean build
+        var cleanBuild = true;
+        if (cleanBuild) {
+            common.cleanCreateDir(host.artifactsRoot + "AtomicNET/");
+            common.cleanCreateDir(buildDir);
+            common.cleanCreateDir(editorAppFolder);
+            common.cleanCreateDir(host.getGenScriptRootDir());
+        }
 
-  process.chdir(buildDir);
+        var buildAtomicNET = spawnSync("which", ["xbuild"]).status == 1 ? false : true;
 
-  var cmds = [];
+        process.chdir(buildDir);
 
-  cmds.push("cmake ../../../ -DATOMIC_DEV_BUILD=0 -G Xcode");
-  cmds.push("xcodebuild -target AtomicEditor -target AtomicPlayer -target AtomicNETNative -configuration Release -parallelizeTargets -jobs 4")
+        var cmds = [];
 
-  if (buildAtomicNET)
-    cmds.push(host.atomicTool + " net compile " + atomicRoot + "Script/AtomicNET/AtomicNETProject.json MACOSX Release");
+        cmds.push("cmake ../../../ -DATOMIC_DEV_BUILD=0 -G Xcode");
+        cmds.push("xcodebuild -target AtomicEditor -target AtomicPlayer -target AtomicNETNative -configuration Release -parallelizeTargets -jobs 4")
 
-  jake.exec(cmds, function() {
+        if (buildAtomicNET)
+            cmds.push(host.atomicTool + " net compile " + atomicRoot + "Script/AtomicNET/AtomicNETProject.json " + (android ? "ANDROID" : "WINDOWS") + " Release");
 
-    fs.copySync(buildDir + "Source/AtomicEditor/Release/AtomicEditor.app", editorAppFolder);
+        function copyAtomicNET() {
 
-    var resourceDest = editorAppFolder + "/Contents/Resources/"
+            if (!buildAtomicNET)
+                return;
 
-    // We need some resources to run
-    fs.copySync(atomicRoot + "Resources/CoreData",
-      resourceDest + "CoreData");
+            fs.copySync(atomicRoot + "Artifacts/AtomicNET/Release",
+            resourceDest + "ToolData/AtomicNET/Release");
 
-    fs.copySync(atomicRoot + "Resources/PlayerData",
-      resourceDest + "PlayerData");
+            fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json",
+            resourceDest + "ToolData/AtomicNET/Build/Projects/AtomicProject.json");
 
-    fs.copySync(atomicRoot + "Data/AtomicEditor",
-      resourceDest + "ToolData");
+        }
 
-    fs.copySync(atomicRoot + "Resources/EditorData",
-      resourceDest + "EditorData");
 
-    fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts",
-      resourceDest + "EditorData/AtomicEditor/EditorScripts");
+        jake.exec(cmds, function() {
 
-    // copy the mac player binary to deployment
-    var playerBinary =  buildDir +  "Source/AtomicPlayer/Application/Release/AtomicPlayer.app/Contents/MacOS/AtomicPlayer";
+            fs.copySync(buildDir + "Source/AtomicEditor/Release/AtomicEditor.app", editorAppFolder);
 
-    fs.copySync(playerBinary,
-      resourceDest + "ToolData/Deployment/MacOS/AtomicPlayer.app/Contents/MacOS/AtomicPlayer");
+            // We need some resources to run
+            fs.copySync(atomicRoot + "Resources/CoreData",
+            resourceDest + "CoreData");
 
-    // AtomicNET
-    if (buildAtomicNET) {
-        
-      fs.copySync(atomicRoot + "Artifacts/AtomicNET/Release",
-        resourceDest + "ToolData/AtomicNET/Release");
+            fs.copySync(atomicRoot + "Resources/PlayerData",
+            resourceDest + "PlayerData");
 
-      fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json",
-        resourceDest + "ToolData/AtomicNET/Build/Projects/AtomicProject.json");
-    }
+            fs.copySync(atomicRoot + "Data/AtomicEditor",
+            resourceDest + "ToolData");
 
-    console.log("\n\nAtomic Editor build to " + editorAppFolder + "\n\n");
+            fs.copySync(atomicRoot + "Resources/EditorData",
+            resourceDest + "EditorData");
 
-    complete();
+            fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts",
+            resourceDest + "EditorData/AtomicEditor/EditorScripts");
 
-  }, {
-    printStdout: true
-  });
+            // copy the mac player binary to deployment
+            var playerBinary =  buildDir +  "Source/AtomicPlayer/Application/Release/AtomicPlayer.app/Contents/MacOS/AtomicPlayer";
 
-});
+            fs.copySync(playerBinary, resourceDest + "ToolData/Deployment/MacOS/AtomicPlayer.app/Contents/MacOS/AtomicPlayer");
 
-// Generate a XCode Workspace
-task('genxcode', {
-  async: true
-}, function() {
+            if (android) {
 
-  var xcodeRoot = path.resolve(atomicRoot, "") + "-XCode";
+                var androidNativeTask = jake.Task['build:android_native'];
 
-  if (!fs.existsSync(xcodeRoot)) {
-      jake.mkdirP(xcodeRoot);
-  }
+                androidNativeTask.addListener('complete', function () {
+                    copyAtomicNET();
+                    console.log("\n\nAtomic Editor build to " + editorAppFolder + "\n\n");
+                    complete();
+                });
 
-  process.chdir(xcodeRoot);
+                androidNativeTask.invoke();
 
-  var cmds = [];
+            }
+            else {
+                copyAtomicNET();
+                console.log("\n\nAtomic Editor build to " + editorAppFolder + "\n\n");
+                complete();
+            }
 
-  cmds.push("cmake ../AtomicGameEngine -DATOMIC_DEV_BUILD=1 -G Xcode");
+        }, {
+            printStdout: true
+        });
 
-  jake.exec(cmds, function() {
+    });
 
-    complete();
+    // Generate a XCode Workspace
+    task('genxcode', {
+        async: true
+    }, function() {
 
-  }, {
-    printStdout: true
-  });
+        var xcodeRoot = path.resolve(atomicRoot, "") + "-XCode";
 
-});
+        if (!fs.existsSync(xcodeRoot)) {
+            jake.mkdirP(xcodeRoot);
+        }
+
+        process.chdir(xcodeRoot);
+
+        var cmds = [];
+
+        cmds.push("cmake ../AtomicGameEngine -DATOMIC_DEV_BUILD=1 -G Xcode");
+
+        jake.exec(cmds, function() {
+
+            complete();
+
+        }, {
+            printStdout: true
+        });
+
+    });
 
 
 });// end of build namespace

+ 84 - 63
Build/Scripts/BuildWindows.js

@@ -8,99 +8,120 @@ var editorAppFolder = host.artifactsRoot + "AtomicEditor/";
 
 namespace('build', function() {
 
-  // Builds a standalone Atomic Editor, which can be distributed out of build tree
-  task('atomiceditor', {
-    async: true
-  }, function() {
+    // Builds a standalone Atomic Editor, which can be distributed out of build tree
+    task('atomiceditor', {
+        async: true
+    }, function(android) {
 
-    // Clean build
-    var cleanBuild = true;
-    if (cleanBuild) {
-      common.cleanCreateDir(buildDir);
-      common.cleanCreateDir(editorAppFolder);
-      common.cleanCreateDir(host.getGenScriptRootDir("WINDOWS"));
-    }
+        android = android == "android" ? true : false;
 
-    process.chdir(buildDir);
+        // Clean build
+        var cleanBuild = true;
+        if (cleanBuild) {
+            common.cleanCreateDir(host.artifactsRoot + "AtomicNET/");
+            common.cleanCreateDir(buildDir);
+            common.cleanCreateDir(editorAppFolder);
+            common.cleanCreateDir(host.getGenScriptRootDir());
+        }
 
-    var cmds = [];
+        process.chdir(buildDir);
 
-    // Build the AtomicEditor
-    cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAtomicEditor.bat");
+        var cmds = [];
 
-    jake.exec(cmds, function() {
+        // Build the AtomicEditor
+        cmds.push(atomicRoot + "Build/Scripts/Windows/CompileAtomicEditor.bat");
+        cmds.push(host.atomicTool + " net compile " + atomicRoot + "Script/AtomicNET/AtomicNETProject.json " + (android ? "ANDROID" : "WINDOWS") + " Release");
 
-      // Copy the Editor binaries
-      fs.copySync(buildDir + "Source/AtomicEditor/Release",
-        host.artifactsRoot + "AtomicEditor");
+        function copyAtomicNET() {
 
-      // We need some resources to run
-      fs.copySync(atomicRoot + "Resources/CoreData",
-        editorAppFolder + "Resources/CoreData");
+            fs.copySync(atomicRoot + "Artifacts/AtomicNET/Release",
+            editorAppFolder + "Resources/ToolData/AtomicNET/Release");
 
-      fs.copySync(atomicRoot + "Resources/PlayerData",
-        editorAppFolder + "Resources/PlayerData");
+            fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json",
+            editorAppFolder + "Resources/ToolData/AtomicNET/Build/Projects/AtomicProject.json");
 
-      fs.copySync(atomicRoot + "Data/AtomicEditor",
-        editorAppFolder + "Resources/ToolData");
+        }
 
-      fs.copySync(atomicRoot + "Resources/EditorData",
-        editorAppFolder + "Resources/EditorData");
+        jake.exec(cmds, function() {
 
-      fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts",
-        editorAppFolder + "Resources/EditorData/AtomicEditor/EditorScripts");
+            // Copy the Editor binaries
+            fs.copySync(buildDir + "Source/AtomicEditor/Release",
+            host.artifactsRoot + "AtomicEditor");
 
-      fs.copySync(buildDir +  "Source/AtomicPlayer/Application/Release/AtomicPlayer.exe",
-        editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/AtomicPlayer.exe");
+            // We need some resources to run
+            fs.copySync(atomicRoot + "Resources/CoreData",
+            editorAppFolder + "Resources/CoreData");
 
-      fs.copySync(buildDir +  "Source/AtomicPlayer/Application/Release/D3DCompiler_47.dll",
-        editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/D3DCompiler_47.dll");
+            fs.copySync(atomicRoot + "Resources/PlayerData",
+            editorAppFolder + "Resources/PlayerData");
 
-      // AtomicNET
+            fs.copySync(atomicRoot + "Data/AtomicEditor",
+            editorAppFolder + "Resources/ToolData");
 
-      fs.copySync(atomicRoot + "Artifacts/AtomicNET/Release",
-        editorAppFolder + "Resources/ToolData/AtomicNET/Release");
+            fs.copySync(atomicRoot + "Resources/EditorData",
+            editorAppFolder + "Resources/EditorData");
 
-      fs.copySync(atomicRoot + "Script/AtomicNET/AtomicProject.json",
-        editorAppFolder + "Resources/ToolData/AtomicNET/Build/Projects/AtomicProject.json");
+            fs.copySync(atomicRoot + "Artifacts/Build/Resources/EditorData/AtomicEditor/EditorScripts",
+            editorAppFolder + "Resources/EditorData/AtomicEditor/EditorScripts");
 
-      console.log("Atomic Editor build to ", editorAppFolder);
+            fs.copySync(buildDir +  "Source/AtomicPlayer/Application/Release/AtomicPlayer.exe",
+            editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/AtomicPlayer.exe");
 
-      complete();
+            fs.copySync(buildDir +  "Source/AtomicPlayer/Application/Release/D3DCompiler_47.dll",
+            editorAppFolder + "Resources/ToolData/Deployment/Windows/x64/D3DCompiler_47.dll");
+
+            if (android) {
+
+                var androidNativeTask = jake.Task['build:android_native'];
+
+                androidNativeTask.addListener('complete', function () {
+                    copyAtomicNET();
+                    console.log("\nAtomic Editor build to ", editorAppFolder);
+                    complete();
+                });
+
+                androidNativeTask.invoke();
+
+            }
+            else {
+                copyAtomicNET();
+                console.log("\nAtomic Editor build to ", editorAppFolder);
+                complete();
+            }
+
+        }, {
+            printStdout: true
+        });
 
-    }, {
-      printStdout: true
     });
 
-  });
+    // Generate a Visual Studio 2015 solution
+    task('genvs2015', {
+        async: true
+    }, function(devBuild) {
+        if (devBuild === undefined)
+        devBuild = 1;
 
-  // Generate a Visual Studio 2015 solution
-  task('genvs2015', {
-    async: true
-  }, function(devBuild) {
-    if (devBuild === undefined)
-      devBuild = 1;
+        var slnRoot = path.resolve(atomicRoot, "") + "-VS2015\\";
 
-    var slnRoot = path.resolve(atomicRoot, "") + "-VS2015\\";
+        if (!fs.existsSync(slnRoot)) {
+            jake.mkdirP(slnRoot);
+        }
 
-    if (!fs.existsSync(slnRoot)) {
-        jake.mkdirP(slnRoot);
-    }
+        process.chdir(slnRoot);
 
-    process.chdir(slnRoot);
+        var cmds = [];
 
-    var cmds = [];
+        cmds.push(atomicRoot + "Build/Scripts/Windows/GenerateVS2015.bat " + atomicRoot + " " + devBuild);
 
-    cmds.push(atomicRoot + "Build/Scripts/Windows/GenerateVS2015.bat " + atomicRoot + " " + devBuild);
+        jake.exec(cmds, function() {
 
-    jake.exec(cmds, function() {
+            complete();
 
-      complete();
+        }, {
+            printStdout: true
+        });
 
-    }, {
-      printStdout: true
     });
 
-  });
-
 }); // end of build namespace

+ 0 - 1
Build/Scripts/Windows/CompileAtomicEditor.bat

@@ -1,4 +1,3 @@
 call "%VS140COMNTOOLS%..\..\VC\bin\amd64\vcvars64.bat"
 cmake ..\\..\\..\\ -DATOMIC_DEV_BUILD=0 -G "Visual Studio 14 2015 Win64"
 msbuild /m Atomic.sln /t:AtomicEditor /t:AtomicPlayer /t:AtomicNETNative /p:Configuration=Release /p:Platform=x64
-msbuild Source/AtomicTool/GenerateAtomicNET.vcxproj /p:Configuration=Release /p:Platform=x64

+ 28 - 2
Build_AtomicEditor.bat

@@ -1,11 +1,37 @@
-@ECHO OFF
+@echo OFF
+setlocal enabledelayedexpansion
+
+set ATOMICEDITOR_BUILD_CMD=Build\Windows\node\node.exe Build\node_modules\jake\bin\cli.js -f ./Build/Scripts/Bootstrap.js build:atomiceditor
+
+for %%a in (%*) do (
+  if /I "%%a"=="--with-android" (set ATOMICEDITOR_ANDROID=YES)
+)
+
+:: If we're building in android support, make sure ANDROID_NDK is defined
+if "%ATOMICEDITOR_ANDROID%" == "YES" (
+
+    if "%ANDROID_NDK%" == "" (
+        @echo:
+        echo ANDROID_NDK not set, exiting
+        @echo:
+        exit /B
+    )
+
+    @echo:
+    echo Building Atomic Editor with Android support
+    @echo:
+    set ATOMICEDITOR_BUILD_CMD=!ATOMICEDITOR_BUILD_CMD![android]
+)
+
 @echo:
 @echo:
 ECHO Building Atomic Editor, this process will take a few minutes
 @echo:
 @echo:
 PAUSE
-Build\Windows\node\node.exe Build\node_modules\jake\bin\cli.js -f ./Build/Scripts/Bootstrap.js build:atomiceditor
+%ATOMICEDITOR_BUILD_CMD%
 @echo:
 @echo:
 PAUSE
+
+endlocal

+ 17 - 3
Build_AtomicEditor.sh

@@ -1,9 +1,23 @@
 #!/usr/bin/env sh
 
+buildcmd="build:atomiceditor"
+
+for var in "$@"
+do
+    if [ $var == "--with-android" ]; then
+        if [ "$ANDROID_NDK" == "" ]; then
+            echo "\n\nANDROID_NDK environment variable not set, exiting\n\n"
+            exit 1
+        fi
+        echo "\n\nBuilding Atomic Editor with Android support\n\n"
+        buildcmd+="[android]"
+    fi
+done
+
 if [ "$(uname)" = "Darwin" ]; then
-    ./Build/Mac/node/node ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js build:atomiceditor
+    ./Build/Mac/node/node ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js $buildcmd
 elif [ "$(expr substr $(uname -s) 1 5)" = "Linux" ]; then
-    ./Build/Linux/node/node ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js build:atomiceditor
+    ./Build/Linux/node/node ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js $buildcmd
 elif [ "$(expr substr $(uname -s) 1 7)" = "MSYS_NT" ]; then
-    ./Build/Windows/node/node.exe ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js build:atomiceditor
+    ./Build/Windows/node/node.exe ./Build/node_modules/jake/bin/cli.js -f ./Build/Scripts/Bootstrap.js $buildcmd
 fi

+ 14 - 0
Script/AtomicEditor/hostExtensions/languageExtensions/CSharpLanguageExtension.ts

@@ -67,6 +67,7 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
             menu.addItem(new Atomic.UIMenuItem("Open Solution", `${this.name}.opensolution`));
             menu.addItem(new Atomic.UIMenuItem("Compile Project", `${this.name}.compileproject`));
             menu.addItem(new Atomic.UIMenuItem("Generate Solution", `${this.name}.generatesolution`));
+            menu.addItem(new Atomic.UIMenuItem("Package Resources", `${this.name}.packageresources`));
 
             this.compileOnSaveMenuItem = new Atomic.UIMenuItem(`Compile on Save: ${isCompileOnSave ? "On" : "Off"}`, `${this.name}.compileonsave`);
             menu.addItem(this.compileOnSaveMenuItem);
@@ -201,6 +202,9 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
                 case "generatesolution":
                     this.generateSolution();
                     return true;
+                case "packageresources":
+                    this.packageResources();
+                    return true;
                 case "compileonsave":
                     let isCompileOnSave = this.serviceRegistry.projectServices.getUserPreference(this.name, "CompileOnSave", false);
                     // Toggle
@@ -243,5 +247,15 @@ export default class CSharpLanguageExtension implements Editor.HostExtensions.Re
 
     }
 
+    /**
+    * Generate Solution
+    */
+    packageResources() {
+
+        if (ToolCore.netProjectSystem) {
+            ToolCore.netProjectSystem.generateResourcePak();
+        }
+
+    }
 
 }

+ 7 - 2
Source/Atomic/IO/FileSystem.cpp

@@ -439,7 +439,7 @@ bool FileSystem::SystemOpen(const String& fileName, const String& mode)
     {
         // ATOMIC BEGIN
         // allow opening of http and file urls
-        if (!fileName.StartsWith("http://") && !fileName.StartsWith("https://") && !fileName.StartsWith("file://"))        
+        if (!fileName.StartsWith("http://") && !fileName.StartsWith("https://") && !fileName.StartsWith("file://"))
             if (!FileExists(fileName) && !DirExists(fileName))
             {
                 ATOMIC_LOGERROR("File or directory " + fileName + " not found");
@@ -1261,6 +1261,8 @@ String GetSanitizedPath(const String& path)
     String sanitized = GetInternalPath(path);
     StringVector parts = sanitized.Split('/');
 
+    bool hasTrailingSlash = path.EndsWith("/") || path.EndsWith("\\");
+
 #ifndef ATOMIC_PLATFORM_WINDOWS
 
     bool absolute = IsAbsolutePath(path);
@@ -1274,6 +1276,9 @@ String GetSanitizedPath(const String& path)
 
 #endif
 
+    if (hasTrailingSlash)
+        sanitized += "/";
+
     return sanitized;
 
 }
@@ -1305,7 +1310,7 @@ bool GetRelativePath(const String& fromPath, const String& toPath, String& outpu
     for (startIdx = 0; startIdx < toParts.Size(); startIdx++)
     {
         if (startIdx >= fromParts.Size() || fromParts[startIdx] != toParts[startIdx])
-            break;       
+            break;
     }
 
     if (startIdx == toParts.Size())

+ 3 - 0
Source/ToolCore/Build/BuildBase.h

@@ -81,6 +81,9 @@ public:
 	bool GetResourcesOnly() const { return resourcesOnly_; }
 	void SetResourcesOnly(bool resourcesOnly = true) { resourcesOnly_ = resourcesOnly;  }
 
+	bool GetBuildFailed() const { return buildFailed_; }
+	const Vector<String>& GetBuildErrors() const { return buildErrors_; }
+
 protected:
 
     bool BuildClean(const String& path);

+ 13 - 3
Source/ToolCore/Build/BuildWindows.cpp

@@ -173,13 +173,16 @@ void BuildWindows::Build(const String& buildPath)
     ToolSystem* tsystem = GetSubsystem<ToolSystem>();
     Project* project = tsystem->GetProject();
 
-    buildPath_ = AddTrailingSlash(buildPath) + GetBuildSubfolder();
+	buildPath_ = AddTrailingSlash(buildPath);
 
+	if (!resourcesOnly_)
+		buildPath_ += GetBuildSubfolder();
+		
     BuildLog("Starting Windows Deployment");
 
     Initialize();
 
-    if (!BuildClean(buildPath_))
+    if (!resourcesOnly_ && !BuildClean(buildPath_))
         return;
 
     String rootSourceDir = tenv->GetRootSourceDir();        
@@ -187,11 +190,18 @@ void BuildWindows::Build(const String& buildPath)
     if (!BuildCreateDirectory(buildPath_))
         return;
 
-    if (!BuildCreateDirectory(buildPath_ + "/AtomicPlayer_Resources"))
+    if (!resourcesOnly_ && !BuildCreateDirectory(buildPath_ + "/AtomicPlayer_Resources"))
         return;
 
     String resourcePackagePath = buildPath_ + "/AtomicPlayer_Resources/AtomicResources" + PAK_EXTENSION;
+
+	if (resourcesOnly_)
+	{
+		resourcePackagePath = buildPath_ + "/AtomicResources" + PAK_EXTENSION;
+	}
+
     GenerateResourcePackage(resourcePackagePath);
+
     if (buildFailed_)
         return;
 

+ 27 - 17
Source/ToolCore/NETTools/NETProjectGen.cpp

@@ -60,6 +60,9 @@ namespace ToolCore
 
 		String atomicProjectPath = projectGen_->GetAtomicProjectPath();
 
+		// TODO: This is the cause of a bunch of "GetSanitizedPath" calls,
+		// It should be removed, and the few places in csproj/sln that need backslash
+		// adjusted there
 		atomicProjectPath.Replace("/", "\\");
 
 		if (atomicProjectPath.Length())
@@ -219,20 +222,25 @@ namespace ToolCore
 			{
 				if (GetIsPCL())
 				{
+					ref = "AtomicNET";
 					platform = "Portable";
 				}
 				else if (SupportsDesktop())
 				{
+					ref = "AtomicNET";
 					platform = "Desktop";
 				}
 				else if (SupportsPlatform("android"))
 				{
+					if (ref != "AtomicNET.Android.SDL")
+						ref = "AtomicNET";
+
 					platform = "Android";
 				}
 
 				if (platform.Length())
-				{					
-					String atomicNETAssembly = tenv->GetAtomicNETCoreAssemblyDir() + ToString("%s/AtomicNET.dll", platform.CString(), ref.CString());
+				{
+					String atomicNETAssembly = tenv->GetAtomicNETCoreAssemblyDir() + ToString("%s/%s.dll", platform.CString(), ref.CString());
 					xref = igroup.CreateChild("Reference");
 					xref.SetAttribute("Include", atomicNETAssembly);
 				}
@@ -521,7 +529,7 @@ namespace ToolCore
 
 		if (SupportsDesktop())
 		{
-			// AtomicNETNative 
+			// AtomicNETNative
 
 			XMLElement atomicNETNativeDLL = itemGroup.CreateChild("None");
 
@@ -543,7 +551,7 @@ namespace ToolCore
 #endif
 
 #ifdef ATOMIC_DEV_BUILD
-			
+
 			String nativePath = AddTrailingSlash(tenv->GetAtomicNETRootDir()) + config + "/Native/" + platform + "/" + filename;
 #else
 			String nativePath = AddTrailingSlash(tenv->GetAtomicNETRootDir()) + config + "/Native/" + platform + "/" + filename;
@@ -617,9 +625,9 @@ namespace ToolCore
 #endif
 
 			// TODO: more than armeabi-v7a (which this is)
-			String nativePath = AddTrailingSlash(tenv->GetAtomicNETRootDir()) + config + "/Android/Native/libAtomicNETNative.so";
+			String nativePath = AddTrailingSlash(tenv->GetAtomicNETRootDir()) + config + "/Native/Android/libAtomicNETNative.so";
 
-			XMLElement nativeLibrary =  projectRoot.CreateChild("ItemGroup").CreateChild("AndroidNativeLibrary"); 
+			XMLElement nativeLibrary =  projectRoot.CreateChild("ItemGroup").CreateChild("AndroidNativeLibrary");
 			nativeLibrary.SetAttribute("Include", nativePath);
 
 			nativeLibrary.CreateChild("Link").SetValue("Libs\\armeabi-v7a\\libAtomicNETNative.so");
@@ -690,8 +698,8 @@ namespace ToolCore
 	bool NETCSProject::GetRelativeProjectPath(const String& fromPath, const String& toPath, String& output)
 	{
 		String path = fromPath;
-
 		ReplacePathStrings(path);
+		path = GetSanitizedPath(path);
 
 		String relativePath;
 
@@ -767,7 +775,7 @@ namespace ToolCore
 				{
 					pgroup.CreateChild("ProjectTypeGuids").SetValue("{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}");
 				}
-				
+
 				pgroup.CreateChild("AndroidUseLatestPlatformSdk").SetValue("True");
 
 				if (!androidApplication_)
@@ -790,14 +798,15 @@ namespace ToolCore
 
 					String manifestSourceFile = "$ATOMIC_PROJECT_ROOT$/Project/AtomicNET/Platforms/Android/Properties/AndroidManifest.xml";
 					ReplacePathStrings(manifestSourceFile);
+					manifestSourceFile = GetSanitizedPath(manifestSourceFile);
 
 					if (fileSystem->FileExists(manifestSourceFile))
 					{
-						String manifestDest = projectPath_ + "Properties/";
+						String manifestDest = GetSanitizedPath(projectPath_ + "Properties/");
 
 						if (!fileSystem->DirExists(manifestDest))
 						{
-							fileSystem->CreateDirs(projectGen_->GetAtomicProjectPath(), ToString("AtomicNET/Solution/%s/Properties/", name_.CString()));
+							fileSystem->CreateDirs(GetSanitizedPath(projectGen_->GetAtomicProjectPath()), ToString("/AtomicNET/Solution/%s/Properties/", name_.CString()));
 						}
 
 						if (fileSystem->DirExists(manifestDest))
@@ -811,11 +820,11 @@ namespace ToolCore
 						{
 							ATOMIC_LOGERRORF("Unable to create folder %s for AndroidManifest.xml", manifestDest.CString());
 						}
-						
+
 					}
 					else
 					{
-						ATOMIC_LOGERROR("No AndroidManifest.xml, project will not deploy");
+						ATOMIC_LOGERRORF("No AndroidManifest.xml, project will not deploy (%s)", manifestSourceFile.CString());
 					}
 
 					String relativePath;
@@ -828,7 +837,7 @@ namespace ToolCore
 					{
 						ATOMIC_LOGERROR("Unabled to get relative path for AndroidResgenFile");
 					}
-					
+
 					pgroup.CreateChild("GenerateSerializationAssemblies").SetValue("Off");
 				}
 
@@ -1106,10 +1115,11 @@ namespace ToolCore
 		assemblyName_ = root["assemblyName"].GetString();
 		assemblyOutputPath_ = root["assemblyOutputPath"].GetString();
 		ReplacePathStrings(assemblyOutputPath_);
+		assemblyOutputPath_ = GetSanitizedPath(assemblyOutputPath_);
 
 		assemblySearchPaths_ = root["assemblySearchPaths"].GetString();
-
 		ReplacePathStrings(assemblySearchPaths_);
+		assemblySearchPaths_ = GetSanitizedPath(assemblySearchPaths_);
 
 		const JSONArray& platforms = root["platforms"].GetArray();
 
@@ -1306,7 +1316,7 @@ namespace ToolCore
 							source += ToString("        %s\\%s.projitems*{%s}*SharedItemsImports = 4\n", p->name_.CString(), p->name_.CString(), p2->projectGuid_.CString());
 						}
 					}
-						
+
 				}
 
 
@@ -1569,7 +1579,7 @@ namespace ToolCore
 			atomicProjectPath_ = AddTrailingSlash(atomicProjectPath);
 		}
 
-		// Do we have a loaded project?  
+		// Do we have a loaded project?
 		if (Project* project = tsystem->GetProject())
 		{
 			// If so, use loaded project settings
@@ -1640,7 +1650,7 @@ namespace ToolCore
 #else
 		return LoadProject(jvalue);
 #endif
-		
+
 	}
 
 	void NETProjectGen::SetSupportedPlatforms(const StringVector& platforms)

+ 44 - 0
Source/ToolCore/NETTools/NETProjectSystem.cpp

@@ -35,6 +35,8 @@
 #include "../Project/ProjectSettings.h"
 #include "../Project/ProjectEvents.h"
 
+#include "../Build/BuildSystem.h"
+
 #include "../Subprocess/SubprocessSystem.h"
 
 #include "NETProjectGen.h"
@@ -199,6 +201,34 @@ namespace ToolCore
         }
     }
 
+	bool NETProjectSystem::GenerateResourcePak()
+	{
+		ToolSystem* tsystem = GetSubsystem<ToolSystem>();
+		Project* project = tsystem->GetProject();
+		BuildSystem* buildSystem = GetSubsystem<BuildSystem>();
+
+		// TODO: We just use WINDOWS platform for PAK generation for now
+		Platform* platform = tsystem->GetPlatformByName("WINDOWS");
+
+		buildSystem->SetBuildPath(project->GetProjectPath() + "AtomicNET/Resources/");
+
+		SharedPtr<BuildBase> buildBase(platform->NewBuild(project));
+		buildBase->SetResourcesOnly(true);
+		buildBase->SetVerbose(true);
+		buildSystem->QueueBuild(buildBase);
+		buildSystem->StartNextBuild();
+
+		if (buildBase->GetBuildFailed())
+		{
+			const StringVector& errors = buildBase->GetBuildErrors();
+			ATOMIC_LOGERRORF("NETProjectSystem::GenerateSolution - Unable to Build Resources.pak: %s", errors.Size() ? errors[0].CString() : "Unknown Error");
+			return false;
+		}
+
+		return true;
+
+	}
+
     bool NETProjectSystem::GenerateSolution()
     {
         ToolSystem* tsystem = GetSubsystem<ToolSystem>();
@@ -210,6 +240,20 @@ namespace ToolCore
             return false;
         }
 
+		// TODO: Generalize and move me
+		if (project->GetSupportsPlatform("android"))
+		{
+			FileSystem* fileSystem = GetSubsystem<FileSystem>();
+
+			if (!fileSystem->FileExists(project->GetProjectPath() + "AtomicNET/Resources/AtomicResources.pak"))
+			{
+				if (!GenerateResourcePak())
+					return false;
+
+			}
+
+		}
+
         SharedPtr<NETProjectGen> gen(new NETProjectGen(context_));
 
         if (!gen->LoadAtomicProject(project->GetProjectPath()))

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

@@ -63,6 +63,7 @@ namespace ToolCore
         void OpenSourceFile(const String& sourceFilePath);
 
         bool GenerateSolution();
+		bool GenerateResourcePak();
 
     private: