| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- //
- // Copyright (c) 2014-2016 THUNDERBEAST GAMES LLC
- //
- // 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/Core/CoreEvents.h>//
- #include <Atomic/IO/IOEvents.h>
- #include <Atomic/Input/InputEvents.h>
- #include <Atomic/Graphics/Graphics.h>
- #include <Atomic/Graphics/GraphicsEvents.h>
- #include <Atomic/IPC/IPCEvents.h>
- #include <AtomicJS/Javascript/JSIPCEvents.h>
- #include "IPCPlayerAppEvents.h"
- #include <Atomic/Engine/Engine.h>
- #include <Atomic/IPC/IPC.h>
- #include <AtomicJS/Javascript/Javascript.h>
- #include <AtomicJS/Javascript/JSDebugger.h>
- #include <Atomic/UI/SystemUI/DebugHud.h>
- #include "IPCPlayerApp.h"
- namespace Atomic
- {
- IPCPlayerApp::IPCPlayerApp(Context* context) :
- PlayerApp(context),
- subprocess_(false),
- debugPlayer_(false),
- brokerActive_(false)
- {
- fd_[0] = INVALID_IPCHANDLE_VALUE;
- fd_[1] = INVALID_IPCHANDLE_VALUE;
- }
- IPCPlayerApp::~IPCPlayerApp()
- {
- }
- void IPCPlayerApp::Setup()
- {
- PlayerApp::Setup();
- // This should be configurable
- engineParameters_.InsertNew("LogLevel", LOG_DEBUG);
- ipc_ = new IPC(context_);
- context_->RegisterSubsystem(ipc_);
- }
- void IPCPlayerApp::ProcessArguments()
- {
- PlayerApp::ProcessArguments();
- FileSystem* fileSystem = GetSubsystem<FileSystem>();
- if (!fileSystem)
- {
- ErrorExit("IPCPlayerApp::ProcessArguments FileSystem subsystem does not exist");
- }
- String resourcePrefix;
- engineParameters_["ResourcePrefixPaths"] = "";
- for (unsigned i = 0; i < arguments_.Size(); ++i)
- {
- if (arguments_[i].Length() > 1)
- {
- String argument = arguments_[i].ToLower();
- String value = i + 1 < arguments_.Size() ? arguments_[i + 1] : String::EMPTY;
- if (argument.StartsWith("--ipc-server=") || argument.StartsWith("--ipc-client="))
- {
- subprocess_ = true;
- }
- else if (argument == "--debug")
- {
- debugPlayer_ = true;
- }
- else if (argument == "--resourceprefix" && value.Length())
- {
- resourcePrefix = value;
- engineParameters_["ResourcePrefixPaths"] = resourcePrefix;
- }
- else if (argument == "--project" && value.Length())
- {
- value = AddTrailingSlash(value);
- AddEngineConfigSearchPath(value + "Settings/");
- // check that cache exists
- if (!fileSystem->DirExists(value + "Cache"))
- {
- ErrorExit("Project cache folder does not exist, projects must be loaded into the Atomic Editor at least once before using the --player command line mode");
- return;
- }
- #ifdef ATOMIC_DEV_BUILD
- String resourcePaths = ToString("%s/Resources/CoreData;%s/Resources/PlayerData;%sResources;%s;%sCache",
- ATOMIC_ROOT_SOURCE_DIR, ATOMIC_ROOT_SOURCE_DIR, value.CString(), value.CString(), value.CString());
- #else
- #ifdef __APPLE__
- if (!resourcePrefix.Length())
- {
- engineParameters_["ResourcePrefixPaths"] = fileSystem->GetProgramDir() + "../Resources";
- }
- #else
- if (!resourcePrefix.Length())
- {
- engineParameters_["ResourcePrefixPaths"] = fileSystem->GetProgramDir() + "Resources";
- }
- #endif
- String resourcePaths = ToString("CoreData;PlayerData;%s/;%s/Resources;%s;%sCache",
- value.CString(), value.CString(), value.CString(), value.CString());
- #endif
- ATOMIC_LOGINFOF("Adding ResourcePaths: %s", resourcePaths.CString());
- engineParameters_["ResourcePaths"] = resourcePaths;
- }
- }
- }
- // IPC client player should not auto exit if a subprocess
- if (subprocess_)
- engine_->SetAutoExit(false);
- }
- void IPCPlayerApp::Start()
- {
- if (subprocess_)
- {
- // do not execute main in the player app
- executeJSMain_ = false;
- }
- PlayerApp::Start();
- int id = -1;
- if (IPC::ProcessArguments(arguments_, id, fd_[0], fd_[1]))
- {
- SubscribeToEvent(E_IPCINITIALIZE, ATOMIC_HANDLER(IPCPlayerApp, HandleIPCInitialize));
- SubscribeToEvent(E_LOGMESSAGE, ATOMIC_HANDLER(IPCPlayerApp, HandleLogMessage));
- SubscribeToEvent(E_JSERROR, ATOMIC_HANDLER(IPCPlayerApp, HandleJSError));
- SubscribeToEvent(E_EXITREQUESTED, ATOMIC_HANDLER(IPCPlayerApp, HandleExitRequest));
- SubscribeToEvent(E_SCREENMODE, ATOMIC_HANDLER(IPCPlayerApp, HandlePlayerWindowChanged));
- SubscribeToEvent(E_WINDOWPOS, ATOMIC_HANDLER(IPCPlayerApp, HandlePlayerWindowChanged));
- SubscribeToEvent(E_UPDATESPAUSEDRESUMED, ATOMIC_HANDLER(IPCPlayerApp, HandleUpdatesPausedResumed));
- if (ipc_->InitWorker((unsigned)id, fd_[0], fd_[1]))
- {
- brokerActive_ = true;
- }
- else if (subprocess_)
- {
- ATOMIC_LOGERROR("IPCPlayerApp::Start() - Unable to initialize IPC Worker");
- }
- }
- if (subprocess_)
- {
- JSVM* vm = JSVM::GetJSVM(0);
- if (!vm->ExecuteMain())
- {
- SendEvent(E_EXITREQUESTED);
- }
- SubscribeToEvent(E_PLAYERQUIT, ATOMIC_HANDLER(IPCPlayerApp, HandleQuit));
- }
- GetSubsystem<Graphics>()->RaiseWindow();
- if (debugPlayer_)
- {
- ATOMIC_LOGDEBUG("Starting JSDebugger Subsystem");
- context_->RegisterSubsystem(new JSDebugger(context_));
- context_->GetSubsystem<JSDebugger>()->Reconnect();
- }
- }
- void IPCPlayerApp::HandleQuit(StringHash eventType, VariantMap& eventData)
- {
- engine_->Exit();
- }
- void IPCPlayerApp::Stop()
- {
- if (debugPlayer_)
- {
- context_->GetSubsystem<JSDebugger>()->Shutdown();
- }
- PlayerApp::Stop();
- }
- void IPCPlayerApp::HandleIPCInitialize(StringHash eventType, VariantMap& eventData)
- {
- brokerActive_ = true;
- // If the parent application has a profile mode up, sync
- DebugHud* debugHud = GetSubsystem<DebugHud>();
- if (debugHud)
- {
- unsigned mode = eventData["debugHudMode"].GetUInt();
- // Only set if we haven't set the mode in player code
- if (mode && !debugHud->GetMode())
- {
- debugHud->SetMode(mode);
- debugHud->SetProfilerMode((DebugHudProfileMode)eventData["debugHudProfilerMode"].GetUInt());
- }
- }
- }
- void IPCPlayerApp::HandleJSError(StringHash eventType, VariantMap& eventData)
- {
- if (brokerActive_)
- {
- if (ipc_.Null())
- return;
- String errName = eventData[JSError::P_ERRORNAME].GetString();
- String errStack = eventData[JSError::P_ERRORSTACK].GetString();
- String errMessage = eventData[JSError::P_ERRORMESSAGE].GetString();
- String errFilename = eventData[JSError::P_ERRORFILENAME].GetString();
- int errLineNumber = eventData[JSError::P_ERRORLINENUMBER].GetInt();
- VariantMap ipcErrorData;
- ipcErrorData[IPCJSError::P_ERRORNAME] = errName;
- ipcErrorData[IPCJSError::P_ERRORSTACK] = errStack;
- ipcErrorData[IPCJSError::P_ERRORMESSAGE] = errMessage;
- ipcErrorData[IPCJSError::P_ERRORFILENAME] = errFilename;
- ipcErrorData[IPCJSError::P_ERRORLINENUMBER] = errLineNumber;
- ipc_->SendEventToBroker(E_IPCJSERROR, ipcErrorData);
- ATOMIC_LOGERROR("SENDING E_IPCJSERROR");
- }
- }
- void IPCPlayerApp::HandlePlayerWindowChanged(StringHash eventType, VariantMap& eventData)
- {
- Graphics* graphics = GetSubsystem<Graphics>();
- using namespace IPCPlayerWindowChanged;
- VariantMap data;
- data[P_POSX] = graphics->GetWindowPosition().x_;
- data[P_POSY] = graphics->GetWindowPosition().y_;
- data[P_WIDTH] = graphics->GetWidth();
- data[P_HEIGHT] = graphics->GetHeight();
- data[P_MONITOR] = graphics->GetCurrentMonitor();
- data[P_MAXIMIZED] = graphics->GetMaximized();
- ipc_->SendEventToBroker(E_IPCPLAYERWINDOWCHANGED, data);
- }
- void IPCPlayerApp::HandleUpdatesPausedResumed(StringHash eventType, VariantMap& eventData)
- {
- ipc_->SendEventToBroker(E_IPCPLAYERUPDATESPAUSEDRESUMED, eventData);
- }
- void IPCPlayerApp::HandleExitRequest(StringHash eventType, VariantMap& eventData)
- {
- UnsubscribeFromEvent(E_LOGMESSAGE);
- SendEvent(E_PLAYERQUIT);
- }
- void IPCPlayerApp::HandleLogMessage(StringHash eventType, VariantMap& eventData)
- {
- using namespace LogMessage;
- if (brokerActive_)
- {
- if (ipc_.Null())
- return;
- VariantMap logEvent;
- logEvent[IPCWorkerLog::P_LEVEL] = eventData[P_LEVEL].GetInt();
- logEvent[IPCWorkerLog::P_MESSAGE] = eventData[P_MESSAGE].GetString();
- ipc_->SendEventToBroker(E_IPCWORKERLOG, logEvent);
- }
- }
- }
|