Bläddra i källkod

Add IPCServerApp that can be used to run a headless IPC server to communicate with IPC clients.

Matt Benic 8 år sedan
förälder
incheckning
dfe81de447

+ 62 - 7
Script/AtomicNET/AtomicNET/Application/Application.cs

@@ -12,6 +12,8 @@ namespace AtomicEngine
 
 
     public partial class Application : AObject
     public partial class Application : AObject
     {
     {
+        public static AppBase AppBase { get; private set; }
+
 
 
         public static int Run<T>(string[] args) where T : AppDelegate, new()
         public static int Run<T>(string[] args) where T : AppDelegate, new()
         {
         {
@@ -22,10 +24,8 @@ namespace AtomicEngine
         {
         {
             // Create the Application
             // Create the Application
 
 
-            AppBase app = null;
-
 #if ATOMIC_DESKTOP
 #if ATOMIC_DESKTOP
-            app = NETIPCPlayerApp.Create(args);
+            AppBase = NETIPCPlayerApp.Create(args);
 #endif
 #endif
 
 
 #if ATOMIC_IOS
 #if ATOMIC_IOS
@@ -36,7 +36,7 @@ namespace AtomicEngine
 
 
 #if ATOMIC_MOBILE
 #if ATOMIC_MOBILE
 
 
-            app = NETAtomicPlayer.Create(args);
+            AppBase = NETAtomicPlayer.Create(args);
             
             
             var renderer = AtomicNET.GetSubsystem<Renderer>();
             var renderer = AtomicNET.GetSubsystem<Renderer>();
             renderer.ReuseShadowMaps = false;
             renderer.ReuseShadowMaps = false;
@@ -54,7 +54,7 @@ namespace AtomicEngine
                 appDelegate.Start();
                 appDelegate.Start();
 
 
                 // Managed code in charge of main loop
                 // Managed code in charge of main loop
-                while (app.RunFrame())
+                while (AppBase.RunFrame())
                 {
                 {
                     appDelegate.PostFrame();
                     appDelegate.PostFrame();
                 }
                 }
@@ -62,7 +62,7 @@ namespace AtomicEngine
                 appDelegate.Shutdown();
                 appDelegate.Shutdown();
 
 
                 // Shut 'er down
                 // Shut 'er down
-                app.Shutdown();
+                AppBase.Shutdown();
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {
@@ -79,13 +79,68 @@ namespace AtomicEngine
                     throw e;
                     throw e;
                 }
                 }
             }
             }
+            finally
+            {
+                AppBase = null;
+            }
 
 
             return 0;
             return 0;
         }
         }
 
 
 
 
+#if ATOMIC_DESKTOP
+        public static int RunServer<T>(string[] args) where T : AppDelegate, new()
+        {
+            return RunServer(typeof(T), args);
+        }
+
+        public static int RunServer(Type appDelegateType, string[] args)
+        {
+            // Create the Application
+            AppBase = NETIPCServerApp.Create(args);
+
+            appDelegate = (AppDelegate)Activator.CreateInstance(appDelegateType);
+
+            try
+            {
+                appDelegate.Start();
+
+                // Managed code in charge of main loop
+                while (AppBase.RunFrame())
+                {
+                    appDelegate.PostFrame();
+                }
+
+                appDelegate.Shutdown();
+
+                // Shut 'er down
+                AppBase.Shutdown();
+            }
+            catch (Exception e)
+            {
+                if (e.InnerException != null)
+                {
+                    Log.Error(e.InnerException.StackTrace);
+                    // rethrow inner exception
+                    throw e.InnerException;
+                }
+                else
+                {
+                    Log.Error(e.StackTrace);
+                    // rethrow
+                    throw e;
+                }
+            }
+            finally
+            {
+                AppBase = null;
+            }
+
+
+            return 0;
+        }
+#endif
         internal static AppDelegate appDelegate;
         internal static AppDelegate appDelegate;
 
 
     }
     }
-
 }
 }

+ 33 - 0
Script/AtomicNET/AtomicNET/Application/NETIPCServerApp.cs

@@ -0,0 +1,33 @@
+using System;
+using System.Reflection;
+
+#if ATOMIC_DESKTOP
+
+namespace AtomicEngine
+{
+    public partial class NETIPCServerApp : IPCServerApp
+    {
+        /// <summary>
+        ///  IPC Player App used with the Atomic Editor
+        /// </summary>
+        /// <param name="args"></param>
+        /// <param name="headless"></param>
+        /// <returns></returns>
+        public static NETIPCServerApp Create(string[] args, bool headless = false)
+        {
+            // Initialize AtomicNET
+            AtomicNET.Initialize();
+
+            var app = CreateInternal();
+
+            app.Initialize();
+
+            return app;
+        }
+
+
+    }
+
+}
+
+#endif

+ 3 - 2
Script/Packages/AtomicApp/AtomicApp.json

@@ -1,9 +1,10 @@
 {
 {
 	"name" : "AtomicApp",
 	"name" : "AtomicApp",
 	"sources" : ["Source/AtomicApp", "Source/AtomicApp/Player"],
 	"sources" : ["Source/AtomicApp", "Source/AtomicApp/Player"],
-	"classes" : ["AppBase", "PlayerApp", "IPCClientApp", "IPCPlayerApp"],
+	"classes" : ["AppBase", "PlayerApp", "IPCClientApp", "IPCPlayerApp", "IPCServerApp"],
 	"classExcludes" : {
 	"classExcludes" : {
 		"IPCClientApp" : ["ANDROID", "IOS", "WEB"],
 		"IPCClientApp" : ["ANDROID", "IOS", "WEB"],
-		"IPCPlayerApp" : ["ANDROID", "IOS", "WEB"]
+		"IPCPlayerApp" : ["ANDROID", "IOS", "WEB"],
+		"IPCServerApp" : ["ANDROID", "IOS", "WEB"]
 	}
 	}
 }
 }

+ 2 - 1
Script/Packages/AtomicNETNative/AtomicNETNative.json

@@ -1,9 +1,10 @@
 {
 {
 	"name" : "AtomicNETNative",
 	"name" : "AtomicNETNative",
 	"sources" : ["Source/AtomicNET/NETNative", "Source/AtomicNET/NETNative/Desktop"],
 	"sources" : ["Source/AtomicNET/NETNative", "Source/AtomicNET/NETNative/Desktop"],
-	"classes" : ["NETCore", "NETAtomicPlayer","NETIPCPlayerApp", "NETServiceApplication"],
+	"classes" : ["NETCore", "NETAtomicPlayer","NETIPCPlayerApp", "NETIPCServerApp", "NETServiceApplication"],
 	"classExcludes" : {
 	"classExcludes" : {
 		"NETIPCPlayerApp" : ["ANDROID", "IOS", "WEB"],
 		"NETIPCPlayerApp" : ["ANDROID", "IOS", "WEB"],
+		"NETIPCServerApp" : ["ANDROID", "IOS", "WEB"],
 		"NETServiceApplication" : ["ANDROID", "IOS", "WEB"]
 		"NETServiceApplication" : ["ANDROID", "IOS", "WEB"]
 	}
 	}
 
 

+ 10 - 0
Source/AtomicApp/AppBase.cpp

@@ -79,6 +79,16 @@ namespace Atomic
         arguments_.Push(argument);
         arguments_.Push(argument);
     }
     }
 
 
+    unsigned AppBase::GetNumArguments()
+    {
+        return arguments_.Size();
+    }
+
+    String AppBase::GetArgument(unsigned index)
+    {
+        return arguments_[index];
+    }
+
     void AppBase::ProcessArguments()
     void AppBase::ProcessArguments()
     {
     {
         for (unsigned i = 0; i < arguments_.Size(); ++i)
         for (unsigned i = 0; i < arguments_.Size(); ++i)

+ 6 - 0
Source/AtomicApp/AppBase.h

@@ -53,6 +53,12 @@ namespace Atomic
         /// Called before initializing application for inserting arguments
         /// Called before initializing application for inserting arguments
         static void AddArgument(const String& argument);
         static void AddArgument(const String& argument);
 
 
+        /// Returns the number of arguments specified on the commandline and added with AddArgument
+        static unsigned GetNumArguments();
+
+        /// Returns an argument from the list of arguments specified on the commandline or added with AddArgument
+        static String GetArgument(unsigned index);
+
         virtual void ProcessArguments();
         virtual void ProcessArguments();
 
 
         static void AddEngineConfigSearchPath(const String& path) { engineConfigSearchPaths_.Push(path); }
         static void AddEngineConfigSearchPath(const String& path) { engineConfigSearchPaths_.Push(path); }

+ 261 - 0
Source/AtomicApp/IPCServerApp.cpp

@@ -0,0 +1,261 @@
+#include <Atomic/IO/Log.h>
+#include <Atomic/IO/FileSystem.h>
+
+#include <Atomic/IO/IOEvents.h>
+#include <Atomic/Core/ProcessUtils.h>
+#include <Atomic/Core/CoreEvents.h>
+
+#include <Atomic/IPC/IPC.h>
+#include <Atomic/IPC/IPCEvents.h>
+#include <Atomic/IPC/IPCWorker.h>
+#include <Atomic/IPC/IPCBroker.h>
+
+#include <ToolCore/ToolSystem.h>
+#include <ToolCore/ToolEnvironment.h>
+#include <ToolCore/Project/Project.h>
+#include <ToolCore/Project/ProjectSettings.h>
+
+#include <Atomic/UI/SystemUI/DebugHud.h>
+#include <AtomicApp/Player/IPCPlayerAppEvents.h>
+
+#include <AtomicJS/Javascript/JSIPCEvents.h>
+
+#include <Atomic/Input/InputEvents.h>
+
+#include "IPCServerApp.h"
+
+#pragma push_macro("PostMessage")
+#undef PostMessage
+
+using namespace ToolCore;
+
+namespace Atomic
+{
+
+    IPCServerApp::IPCServerApp(Context* context) :
+        AppBase(context),
+        playerEnabled_(false)
+    {
+    }
+
+    IPCServerApp::~IPCServerApp()
+    {
+    }
+
+    void IPCServerApp::Setup()
+    {
+        AppBase::Setup();
+
+        // Register IPC system
+        context_->RegisterSubsystem(new IPC(context_));
+
+        ToolEnvironment* env = new ToolEnvironment(context_);
+        context_->RegisterSubsystem(env);
+
+        env->Initialize();
+
+        ToolSystem* system = new ToolSystem(context_);
+        context_->RegisterSubsystem(system);
+
+        engineParameters_["Headless"] = true;
+        engineParameters_["LogLevel"] = LOG_INFO;
+    }
+
+    void IPCServerApp::Stop()
+    {
+        IPC* ipc = GetSubsystem<IPC>();
+
+        if (ipc)
+        {
+            ipc->Shutdown();
+        }
+
+        AppBase::Stop();
+    }
+
+    bool IPCServerApp::RunIPCPlayer(const String& projectName, const String& projectPath, const String &addArgs)
+    {
+        /* Params to pass in (possibly) from PE
+        --windowposx 244
+        --windowposy 157
+        --windowwidth 1440
+        --windowheight 806
+        --resizable
+
+        ALSO STUFF TO TELL VSEATOMIC WHICH CUTSCENE TO LAUNCH..app delegate will need to parse run params I think
+
+        */
+
+        if (playerBroker_.NotNull())
+            return false;
+
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        ToolSystem* tsystem = GetSubsystem<ToolSystem>();
+        ToolEnvironment* tenv = GetSubsystem<ToolEnvironment>();
+
+        String projectAssembly = projectName + ".dll";
+        String projectExe = projectName + ".exe";
+
+        String playerBinary = "";
+
+        String resourcePath = projectPath + "Resources/" + projectAssembly;
+
+        // TODO: We need to configure project as managed
+        if (fileSystem->FileExists(resourcePath))
+        {
+#ifdef ATOMIC_DEV_BUILD
+
+#ifdef ATOMIC_DEBUG        
+            playerBinary = projectPath + "AtomicNET/Debug/Bin/Desktop/" + projectExe;
+#else
+            playerBinary = projectPath + "AtomicNET/Release/Bin/Desktop/" + projectExe;
+#endif
+
+#else
+            // TODO: We are using the release build of the managed project here, how and when to use debug?
+            playerBinary = projectPath + "AtomicNET/Release/Bin/Desktop/" + projectExe;
+#endif
+
+
+            if (!fileSystem->FileExists(playerBinary))
+            {
+                ATOMIC_LOGERRORF("Managed player: %s does not exist", playerBinary.CString());
+                return false;
+            }
+
+        }
+        else
+        {
+            return false;
+        }
+
+        Vector<String> vargs;
+
+        String args = ToString("--player --project \"%s\"", projectPath.CString());
+
+        vargs = args.Split(' ');
+
+#ifdef ATOMIC_DEV_BUILD
+        vargs.Insert(0, ToString("\"%s/Resources/\"", tenv->GetRootSourceDir().CString()));
+#else
+
+#ifdef ATOMIC_PLATFORM_OSX
+        vargs.Insert(0, ToString("\"%s\"", (fileSystem->GetProgramDir() + "../Resources/").CString()));
+#else
+        vargs.Insert(0, ToString("\"%s\"", (fileSystem->GetProgramDir() + "Resources/").CString()));
+#endif
+
+#endif
+        vargs.Insert(0, "--resourcePrefix");
+
+        if (addArgs.Length() > 0)
+            vargs.Insert(0, addArgs.Split(' '));
+
+
+        String dump;
+        dump.Join(vargs, " ");
+        ATOMIC_LOGINFOF("Launching Broker %s %s", playerBinary.CString(), dump.CString());
+
+        IPC* ipc = GetSubsystem<IPC>();
+        playerBroker_ = ipc->SpawnWorker(playerBinary, vargs);
+
+        if (playerBroker_)
+        {
+            SubscribeToEvent(playerBroker_, E_IPCWORKERSTART, ATOMIC_HANDLER(IPCServerApp, HandleIPCWorkerStarted));
+            SubscribeToEvent(playerBroker_, E_IPCJSERROR, ATOMIC_HANDLER(IPCServerApp, HandleIPCJSError));
+            SubscribeToEvent(playerBroker_, E_IPCWORKEREXIT, ATOMIC_HANDLER(IPCServerApp, HandleIPCWorkerExit));
+            SubscribeToEvent(playerBroker_, E_IPCWORKERLOG, ATOMIC_HANDLER(IPCServerApp, HandleIPCWorkerLog));
+        }
+
+        return playerBroker_.NotNull();
+    }
+
+    void IPCServerApp::HandleIPCWorkerStarted(StringHash eventType, VariantMap& eventData)
+    {
+        VariantMap startupData;
+        DebugHud* debugHud = GetSubsystem<DebugHud>();
+
+        startupData["debugHudMode"] = debugHud ? debugHud->GetMode() : (unsigned)0;
+        startupData["debugHudProfilerMode"] = (unsigned)(debugHud ? debugHud->GetProfilerMode() : DEBUG_HUD_PROFILE_PERFORMANCE);
+
+        playerBroker_->PostMessage(E_IPCINITIALIZE, startupData);
+
+        playerEnabled_ = true;
+    }
+
+
+    void IPCServerApp::HandleIPCWorkerExit(StringHash eventType, VariantMap& eventData)
+    {
+        if (eventData[IPCWorkerExit::P_BROKER] == playerBroker_)
+        {
+            playerBroker_ = 0;
+            playerEnabled_ = false;
+
+            UnsubscribeFromEvent(E_IPCWORKERSTART);
+            UnsubscribeFromEvent(E_IPCPLAYERPAUSERESUMEREQUEST);
+            UnsubscribeFromEvent(E_IPCPLAYERUPDATESPAUSEDRESUMED);
+            UnsubscribeFromEvent(E_IPCPLAYERPAUSESTEPREQUEST);
+            UnsubscribeFromEvent(E_IPCPLAYEREXITREQUEST);
+        }
+        else
+        {
+            ATOMIC_LOGERROR("IPCServerApp::HandleIPCWorkerExit - Unknown Broker");
+        }
+    }
+
+    void IPCServerApp::HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData)
+    {
+        using namespace IPCWorkerLog;
+
+        // convert to a player log
+
+        VariantMap playerLogData;
+
+        playerLogData["message"] = eventData[P_MESSAGE].GetString();
+        playerLogData["level"] = eventData[P_LEVEL].GetInt();
+
+        //SendEvent("EditorPlayerLog", playerLogData);
+
+    }
+
+    void IPCServerApp::HandleIPCJSError(StringHash eventType, VariantMap& eventData)
+    {
+
+    }
+    
+    void IPCServerApp::RequestTogglePlayerUpdatesPaused()
+    {
+        if (!playerBroker_)
+        {
+            return;
+        }
+
+        VariantMap noEventData;
+        playerBroker_->PostMessage(E_PAUSERESUMEREQUESTED, noEventData);
+    }
+
+    void IPCServerApp::RequestPlayerPauseStep()
+    {
+        if (!playerBroker_)
+        {
+            return;
+        }
+
+        VariantMap noEventData;
+        playerBroker_->PostMessage(E_PAUSESTEPREQUESTED, noEventData);
+    }
+
+    void IPCServerApp::RequestPlayerExit()
+    {
+        if (!playerBroker_)
+        {
+            return;
+        }
+
+        VariantMap noEventData;
+        playerBroker_->PostMessage(E_EXITREQUESTED, noEventData);
+    }
+
+}
+
+#pragma pop_macro("PostMessage")

+ 43 - 0
Source/AtomicApp/IPCServerApp.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include <Atomic/IPC/IPC.h>
+#include "AppBase.h"
+
+namespace Atomic
+{
+    
+    class IPCServerApp : public AppBase
+    {
+
+        ATOMIC_OBJECT(IPCServerApp, AppBase)
+
+    public:
+        /// Construct.
+        IPCServerApp(Context* context);
+        /// Destruct.
+        virtual ~IPCServerApp();
+
+        virtual void Setup();
+        virtual void Stop();
+
+        bool RunIPCPlayer(const String& projectName, const String& projectPath, const String &addArgs);
+
+        void RequestTogglePlayerUpdatesPaused();
+        void RequestPlayerPauseStep();
+        void RequestPlayerExit();
+
+
+    private:
+
+        void HandleIPCWorkerStarted(StringHash eventType, VariantMap& eventData);
+        void HandleIPCJSError(StringHash eventType, VariantMap& eventData);
+        void HandleIPCWorkerLog(StringHash eventType, VariantMap& eventData);
+        void HandleIPCWorkerExit(StringHash eventType, VariantMap& eventData);        
+        
+        SharedPtr<IPCBroker> playerBroker_;
+
+        bool playerEnabled_;
+
+    };
+
+}

+ 1 - 1
Source/AtomicNET/NETNative/CMakeLists.txt

@@ -27,7 +27,7 @@ add_library(AtomicNETNative SHARED ${SOURCE_FILES} ${CSHARP_BINDINGS_SOURCE})
 if (ATOMIC_DESKTOP)
 if (ATOMIC_DESKTOP)
     add_dependencies(AtomicNETNative AtomicToolCheckScripts)
     add_dependencies(AtomicNETNative AtomicToolCheckScripts)
 endif ()
 endif ()
-target_link_libraries(AtomicNETNative AtomicApp AtomicNETScriptBindings AtomicNETScript AtomicJS AtomicPlayerLib AtomicPlayerJS Atomic)
+target_link_libraries(AtomicNETNative AtomicApp AtomicNETScriptBindings AtomicNETScript AtomicJS AtomicPlayerLib AtomicPlayerJS Atomic ToolCore Poco Iphlpapi)
 target_include_directories(AtomicNETNative PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
 target_include_directories(AtomicNETNative PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
 
 
 if (APPLE)
 if (APPLE)

+ 99 - 0
Source/AtomicNET/NETNative/Desktop/NETIPCServerApp.cpp

@@ -0,0 +1,99 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#include <Atomic/Engine/Engine.h>
+#include <Atomic/IO/FileSystem.h>
+#include "NETCore.h"
+#include <AtomicNET/NETScript/NETScript.h>
+#include <AtomicNET/NETScript/CSComponentAssembly.h>
+
+#include "NETIPCServerApp.h"
+
+#ifdef ATOMIC_PLATFORM_OSX
+#include <unistd.h>
+#endif
+
+#ifdef ATOMIC_PLATFORM_WINDOWS
+#include <stdio.h>
+#endif
+
+namespace Atomic
+{
+
+    NETIPCServerApp::NETIPCServerApp(Context* context) :
+        IPCServerApp(context)
+    {
+
+    }
+
+    void NETIPCServerApp::Setup()
+    {
+        IPCServerApp::Setup();
+
+        // TODO: we should always have a --project for IPCPlayer, however it is doing 
+        // double duty right now as managed player
+        StringVector args = GetArguments();
+        if (!args.Contains("--project"))
+        {
+            engineParameters_["ResourcePrefixPaths"] = "AtomicPlayer_Resources";
+            engineParameters_["ResourcePaths"] = "AtomicResources";
+        }
+    }
+
+    int NETIPCServerApp::Initialize()
+    {
+        Setup();
+
+        RegisterNETScriptLibrary(context_);
+
+        if (exitCode_)
+            return exitCode_;
+
+        if (!engine_->Initialize(engineParameters_))
+        {
+            ErrorExit();
+            return exitCode_;
+        }
+
+        // TODO: Proper CSComponent assembly preload
+        // For now, user must ensure that assemblies are loaded via
+        // referencing their types or load assembly before initializing
+        // AtomicNET in application.  This is commented out as it
+        // causes an issue with double loading referenced assemblies
+        // and the ones in the project file
+        // CSComponentAssembly::PreloadClassAssemblies();
+
+        Start();
+
+        if (exitCode_)
+            return exitCode_;
+
+        return 0;
+    }
+    
+    NETIPCServerApp* NETIPCServerApp::CreateInternal()
+    {
+        return new NETIPCServerApp(NETCore::GetContext());
+    }
+
+}

+ 51 - 0
Source/AtomicNET/NETNative/Desktop/NETIPCServerApp.h

@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#pragma once
+
+#include <AtomicApp/IPCServerApp.h>
+
+namespace Atomic
+{
+
+    class NETIPCServerApp : public IPCServerApp
+    {
+        ATOMIC_OBJECT(NETIPCServerApp,IPCServerApp)
+
+    public:
+
+        static NETIPCServerApp* CreateInternal();
+
+        int Initialize();
+
+    private:
+
+        /// Construct.
+        NETIPCServerApp(Context* context);
+
+        /// Setup before engine initialization.
+        virtual void Setup();
+
+    };
+
+}