Changeset View
Standalone View
source/rlinterface/RLInterface.cpp
Show All 27 Lines | |||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "simulation2/components/ICmpAIInterface.h" | #include "simulation2/components/ICmpAIInterface.h" | ||||
#include "simulation2/components/ICmpTemplateManager.h" | #include "simulation2/components/ICmpTemplateManager.h" | ||||
#include "simulation2/Simulation2.h" | #include "simulation2/Simulation2.h" | ||||
#include "simulation2/system/LocalTurnManager.h" | #include "simulation2/system/LocalTurnManager.h" | ||||
#include "third_party/mongoose/mongoose.h" | #include "third_party/mongoose/mongoose.h" | ||||
#include <queue> | #include <queue> | ||||
#include <tuple> | #include <tuple> | ||||
vladislavbelov: Wrong order. | |||||
#include <sstream> | #include <sstream> | ||||
// Globally accessible pointer to the RL Interface. | // Globally accessible pointer to the RL Interface. | ||||
RLInterface* g_RLInterface = nullptr; | RLInterface* g_RLInterface = nullptr; | ||||
Done Inline ActionsYou don't need to add RL for each method, you can just wrap the whole code in namespace RL. vladislavbelov: You don't need to add RL for each method, you can just wrap the whole code in `namespace RL`. | |||||
Done Inline ActionsYeah, that would've been a good idea to make it cleaner. Updated now. irishninja: Yeah, that would've been a good idea to make it cleaner. Updated now. | |||||
Not Done Inline ActionsNo need to assign nullptr to a global object. vladislavbelov: No need to assign `nullptr` to a global object. | |||||
// Interactions with the game engine (g_Game) must be done in the main | // Interactions with the game engine (g_Game) must be done in the main | ||||
// thread as there are specific checks for this. We will pass our commands | // thread as there are specific checks for this. We will pass our commands | ||||
// to the main thread to be applied | // to the main thread to be applied | ||||
std::string RLInterface::SendGameMessage(const GameMessage msg) | std::string RLInterface::SendGameMessage(const GameMessage& msg) | ||||
{ | { | ||||
std::unique_lock<std::mutex> msgLock(m_msgLock); | std::unique_lock<std::mutex> msgLock(m_MsgLock); | ||||
Not Done Inline Actionsr-value doesn't make things easier here. vladislavbelov: r-value doesn't make things easier here. | |||||
Done Inline ActionsMy thinking had been that game messages do not need to be used after they are "sent" so I could pass them as an r-value. This should help avoid any additional copying and make it more clear in the code that the message has been "consumed" (so it shouldn't be edited afterwards, etc). Does that make sense? irishninja: My thinking had been that game messages do not need to be used after they are "sent" so I could… | |||||
Not Done Inline ActionsI think vlad's comment in the context that you kept a reference to that r-value below, which didn't help, but since you've fixed that, I think your reasoning holds up. wraitii: I think vlad's comment in the context that you kept a reference to that r-value below, which… | |||||
m_GameMessage = &msg; | m_GameMessage = &msg; | ||||
Not Done Inline ActionsDo you know what's going on here? @Itms it's also the question for you. vladislavbelov: Do you know what's going on here?
@Itms it's also the question for you. | |||||
Done Inline ActionsI am setting m_GameMessage to reference msg (which is on the stack). This doesn't result in any issues since m_GameMessage only needs to be available until m_MsgApplied.wait(msgLock) unblocks which certainly is within the lifetime of the previous stack frame (either Step or Reset). I will probably update this to use an rvalue ref (and use std::move) to make ownership more obvious... Thoughts? irishninja: I am setting `m_GameMessage` to reference `msg` (which is on the stack). This doesn't result in… | |||||
Not Done Inline ActionsYes, and that should be avoided. We shouldn't store pointers/references to local variables as class members until we explicitly guarantee the lifetime. vladislavbelov: Yes, and that should be avoided. We shouldn't store pointers/references to local variables as… | |||||
Not Done Inline ActionsIt should be solved. vladislavbelov: It should be solved. | |||||
Done Inline ActionsMy bad. I forgot to make it an rvalue ref here, too. irishninja: My bad. I forgot to make it an rvalue ref here, too. | |||||
Not Done Inline ActionsThe issue is still here. You're storying reference to a local variable. vladislavbelov: The issue is still here. You're storying reference to a local variable. | |||||
Done Inline ActionsAdding m_GameMessage = std::move(msg); should fix this here, right? I was thinking that it should help since the variable is moved to the data member and will no longer be freed after it goes out of scope (ie, when the variable frame is popped off the stack). Is this correct or am I missing something? irishninja: Adding `m_GameMessage = std::move(msg);` should fix this here, right? I was thinking that it… | |||||
m_msgApplied.wait(msgLock); | m_MsgApplied.wait(msgLock); | ||||
return m_GameState; | return m_GameState; | ||||
Done Inline ActionsDo you need 6 threads? AFAIK you're not using a browser? Stan: Do you need 6 threads? AFAIK you're not using a browser? | |||||
} | } | ||||
std::string RLInterface::Step(const std::vector<Command> commands) | std::string RLInterface::Step(const std::vector<RLGameCommand>& commands) | ||||
{ | { | ||||
std::lock_guard<std::mutex> lock(m_lock); | std::lock_guard<std::mutex> lock(m_Lock); | ||||
GameMessage msg = { GameMessageType::Commands, commands }; | GameMessage msg = { GameMessageType::Commands, commands }; | ||||
return SendGameMessage(msg); | return SendGameMessage(msg); | ||||
} | } | ||||
std::string RLInterface::Reset(const ScenarioConfig* scenario) | std::string RLInterface::Reset(const ScenarioConfig* scenario) | ||||
{ | { | ||||
std::lock_guard<std::mutex> lock(m_lock); | std::lock_guard<std::mutex> lock(m_Lock); | ||||
m_ScenarioConfig = *scenario; | m_ScenarioConfig = *scenario; | ||||
struct GameMessage msg = { GameMessageType::Reset }; | struct GameMessage msg = { GameMessageType::Reset }; | ||||
return SendGameMessage(msg); | return SendGameMessage(msg); | ||||
} | } | ||||
std::vector<std::string> RLInterface::GetTemplates(const std::vector<std::string> names) const | std::vector<std::string> RLInterface::GetTemplates(const std::vector<std::string>& names) const | ||||
{ | { | ||||
std::lock_guard<std::mutex> lock(m_lock); | std::lock_guard<std::mutex> lock(m_Lock); | ||||
CSimulation2& simulation = *g_Game->GetSimulation2(); | CSimulation2& simulation = *g_Game->GetSimulation2(); | ||||
CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation.GetSimContext().GetSystemEntity()); | CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation.GetSimContext().GetSystemEntity()); | ||||
std::vector<std::string> templates; | std::vector<std::string> templates; | ||||
for (const std::string& templateName : names) | for (const std::string& templateName : names) | ||||
{ | { | ||||
const CParamNode* node = cmpTemplateManager->GetTemplate(templateName); | const CParamNode* node = cmpTemplateManager->GetTemplate(templateName); | ||||
if (node != nullptr) | if (node != nullptr) | ||||
{ | { | ||||
std::string content = utf8_from_wstring(node->ToXML()); | std::string content = utf8_from_wstring(node->ToXML()); | ||||
Done Inline ActionsAdditional variables isn't needed here, it doesn't give more information about what's going on here and the lines are pretty short. vladislavbelov: Additional variables isn't needed here, it doesn't give more information about what's going on… | |||||
templates.push_back(content); | templates.push_back(content); | ||||
} | } | ||||
} | } | ||||
return templates; | return templates; | ||||
} | } | ||||
static void* RLMgCallback(mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info) | static void* RLMgCallback(mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info) | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (uri == "/reset") | ||||
scenario.saveReplay = qs.find("saveReplay") != std::string::npos; | scenario.saveReplay = qs.find("saveReplay") != std::string::npos; | ||||
scenario.playerID = 1; | scenario.playerID = 1; | ||||
char playerID[1]; | char playerID[1]; | ||||
int len = mg_get_var(request_info->query_string, qs.length(), "playerID", playerID, 1); | int len = mg_get_var(request_info->query_string, qs.length(), "playerID", playerID, 1); | ||||
if (len != -1) | if (len != -1) | ||||
scenario.playerID = std::stoi(playerID); | scenario.playerID = std::stoi(playerID); | ||||
int bufSize = std::atoi(val); | int bufSize = std::atoi(val); | ||||
Not Done Inline ActionsWhat's happening if the val is incorrect integer? vladislavbelov: What's happening if the val is incorrect integer? | |||||
Done Inline ActionsHmm... I was assuming that it was a properly formed HTTP request. Would you like me to be more pessimistic about malformed HTTP requests? So far, I haven't worried too much about it since "Content-Length" is often handled by http request libraries and the RL interface requires both a flag to be set and then only accepts requests from localhost (unless you change the address to 0.0.0.0). I also figured that there wasn't much motivation for malicious agents to attack the game via the RL interface as it is likely being used for development of an AI rather than a hosting the game engine as a server of sorts. (In that context, I had actually imagined there would still be an orchestrator of sorts collecting and applying the commands as all actions at a given step are part of a single call to Step - and it likely wouldn't make sense for both players to control the stepping of the game arbitrarily.) Regardless, I can certainly update it if preferred. Let me know what you think! irishninja: Hmm... I was assuming that it was a properly formed HTTP request. Would you like me to be more… | |||||
Done Inline Actionsatoi will return 0 if it can't be converted, which ought to be fairly safe. I think we have to trust mongoose here. wraitii: `atoi` will return 0 if it can't be converted, which ought to be fairly safe. I think we have… | |||||
std::unique_ptr<char> buf = std::unique_ptr<char>(new char[bufSize]); | std::unique_ptr<char> buf = std::unique_ptr<char>(new char[bufSize]); | ||||
Done Inline ActionsIncorrect type of std::unique_ptr<char>, it should be std::unique_ptr<char[]>. vladislavbelov: Incorrect type of `std::unique_ptr<char>`, it should be `std::unique_ptr<char[]>`. | |||||
mg_read(conn, buf.get(), bufSize); | mg_read(conn, buf.get(), bufSize); | ||||
std::string content(buf.get(), bufSize); | std::string content(buf.get(), bufSize); | ||||
scenario.content = content; | scenario.content = content; | ||||
Not Done Inline ActionsInstead of duplicating allocations you might create a string with enough space: const int contentSize = std::atoi(val); std::string content(' ', contentSize); mg_read(conn, content.data(), content.size()); scenario.content = std::move(content); vladislavbelov: Instead of duplicating allocations you might create a string with enough space:
```lang=cpp… | |||||
Done Inline ActionsMakes sense. However, it looks like content.data() is const and can't be used to set the contents of the string using mg_read. Am I missing something? irishninja: Makes sense. However, it looks like `content.data()` is `const` and can't be used to set the… | |||||
std::string gameState = interface->Reset(&scenario); | std::string gameState = interface->Reset(&scenario); | ||||
stream << gameState.c_str(); | stream << gameState.c_str(); | ||||
} | } | ||||
else if (uri == "/step") | else if (uri == "/step") | ||||
{ | { | ||||
if (!interface->IsGameRunning()) | if (!interface->IsGameRunning()) | ||||
{ | { | ||||
mg_printf(conn, "%s", notRunningResponse); | mg_printf(conn, "%s", notRunningResponse); | ||||
return handled; | return handled; | ||||
} | } | ||||
const char* val = mg_get_header(conn, "Content-Length"); | const char* val = mg_get_header(conn, "Content-Length"); | ||||
if (!val) | if (!val) | ||||
{ | { | ||||
mg_printf(conn, "%s", noPostData); | mg_printf(conn, "%s", noPostData); | ||||
return handled; | return handled; | ||||
} | } | ||||
int bufSize = std::atoi(val); | int bufSize = std::atoi(val); | ||||
std::unique_ptr<char> buf = std::unique_ptr<char>(new char[bufSize]); | std::unique_ptr<char> buf = std::unique_ptr<char>(new char[bufSize]); | ||||
mg_read(conn, buf.get(), bufSize); | mg_read(conn, buf.get(), bufSize); | ||||
std::string postData(buf.get(), bufSize); | std::string postData(buf.get(), bufSize); | ||||
Not Done Inline ActionsThe same here. vladislavbelov: The same here. | |||||
std::stringstream postStream(postData); | std::stringstream postStream(postData); | ||||
std::string line; | std::string line; | ||||
std::vector<Command> commands; | std::vector<RLGameCommand> commands; | ||||
while (std::getline(postStream, line, '\n')) | while (std::getline(postStream, line, '\n')) | ||||
{ | { | ||||
Command cmd; | RLGameCommand cmd; | ||||
const std::size_t splitPos = line.find(";"); | const std::size_t splitPos = line.find(";"); | ||||
if (splitPos != std::string::npos) | if (splitPos != std::string::npos) | ||||
{ | { | ||||
cmd.playerID = std::stoi(line.substr(0, splitPos)); | cmd.playerID = std::stoi(line.substr(0, splitPos)); | ||||
cmd.json_cmd = line.substr(splitPos + 1); | cmd.json_cmd = line.substr(splitPos + 1); | ||||
commands.push_back(cmd); | commands.push_back(cmd); | ||||
} | } | ||||
} | } | ||||
Show All 14 Lines | else if (uri == "/templates") | ||||
} | } | ||||
const char* val = mg_get_header(conn, "Content-Length"); | const char* val = mg_get_header(conn, "Content-Length"); | ||||
if (!val) | if (!val) | ||||
{ | { | ||||
mg_printf(conn, "%s", noPostData); | mg_printf(conn, "%s", noPostData); | ||||
return handled; | return handled; | ||||
} | } | ||||
int bufSize = std::atoi(val); | int bufSize = std::atoi(val); | ||||
std::unique_ptr<char> buf = std::unique_ptr<char>(new char[bufSize]); | std::unique_ptr<char> buf = std::unique_ptr<char>(new char[bufSize]); | ||||
mg_read(conn, buf.get(), bufSize); | mg_read(conn, buf.get(), bufSize); | ||||
std::string postData(buf.get(), bufSize); | std::string postData(buf.get(), bufSize); | ||||
Not Done Inline ActionsAnd here. It seems a code duplication, might be unified. vladislavbelov: And here. It seems a code duplication, might be unified. | |||||
std::stringstream postStream(postData); | std::stringstream postStream(postData); | ||||
std::string line; | std::string line; | ||||
std::vector<std::string> templateNames; | std::vector<std::string> templateNames; | ||||
while (std::getline(postStream, line, '\n')) | while (std::getline(postStream, line, '\n')) | ||||
templateNames.push_back(line); | templateNames.push_back(line); | ||||
for (std::string templateStr : interface->GetTemplates(templateNames)) | for (std::string templateStr : interface->GetTemplates(templateNames)) | ||||
stream << templateStr.c_str() << "\n"; | stream << templateStr.c_str() << "\n"; | ||||
Show All 25 Lines | static void* RLMgCallback(mg_event event, struct mg_connection *conn, const struct mg_request_info *request_info) | ||||
default: | default: | ||||
debug_warn(L"Invalid Mongoose event type"); | debug_warn(L"Invalid Mongoose event type"); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
}; | }; | ||||
void RLInterface::EnableHTTP(const char* server_address) | void RLInterface::EnableHTTP(const char* server_address) | ||||
{ | { | ||||
LOGMESSAGERENDER("Starting RL interface HTTP server"); | LOGMESSAGERENDER("Starting RL interface HTTP server"); | ||||
Not Done Inline ActionsI suppose Enable != Start. Enable doesn't mean that it starts something. vladislavbelov: I suppose `Enable != Start`. Enable doesn't mean that it starts something. | |||||
Done Inline ActionsThis was following the convention used in CProfiler2 but I don't have a preference myself either way. Let me know if you would like it to be changed to something like StartHTTP irishninja: This was following the convention used in CProfiler2 but I don't have a preference myself… | |||||
// Ignore multiple enablings | // Ignore multiple enablings | ||||
if (m_MgContext) | if (m_MgContext) | ||||
return; | return; | ||||
const char *options[] = { | const char *options[] = { | ||||
"listening_ports", server_address, | "listening_ports", server_address, | ||||
"num_threads", "6", // enough for the browser's parallel connection limit | "num_threads", "6", // enough for the browser's parallel connection limit | ||||
nullptr | nullptr | ||||
}; | }; | ||||
m_MgContext = mg_start(RLMgCallback, this, options); | m_MgContext = mg_start(RLMgCallback, this, options); | ||||
ENSURE(m_MgContext); | ENSURE(m_MgContext); | ||||
} | } | ||||
bool RLInterface::TryGetGameMessage(GameMessage& msg) | bool RLInterface::TryGetGameMessage(GameMessage& msg) | ||||
{ | { | ||||
if (m_GameMessage != nullptr) { | if (m_GameMessage != nullptr) { | ||||
Done Inline ActionsThe brace should be on the new line. vladislavbelov: The brace should be on the new line. | |||||
msg = *m_GameMessage; | msg = *m_GameMessage; | ||||
m_GameMessage = nullptr; | m_GameMessage = nullptr; | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
void RLInterface::TryApplyMessage() | void RLInterface::TryApplyMessage() | ||||
{ | { | ||||
const static std::string EMPTY_STATE; | |||||
const bool nonVisual = !g_GUI; | const bool nonVisual = !g_GUI; | ||||
const bool isGameStarted = g_Game && g_Game->IsGameStarted(); | const bool isGameStarted = g_Game && g_Game->IsGameStarted(); | ||||
if (m_NeedsGameState && isGameStarted) | if (m_NeedsGameState && isGameStarted) | ||||
{ | { | ||||
m_GameState = GetGameState(); | m_GameState = GetGameState(); | ||||
m_msgApplied.notify_one(); | m_MsgApplied.notify_one(); | ||||
m_msgLock.unlock(); | m_MsgLock.unlock(); | ||||
m_NeedsGameState = false; | m_NeedsGameState = false; | ||||
} | } | ||||
if (m_msgLock.try_lock()) | if (m_MsgLock.try_lock()) | ||||
Done Inline ActionsEarly return; Stan: Early return; | |||||
{ | { | ||||
GameMessage msg; | GameMessage msg; | ||||
if (TryGetGameMessage(msg)) { | if (TryGetGameMessage(msg)) { | ||||
Done Inline ActionsThe brace should be on the new line. vladislavbelov: The brace should be on the new line. | |||||
Done Inline ActionsInvert, early return, to remove indent. Stan: Invert, early return, to remove indent. | |||||
switch (msg.type) | switch (msg.type) | ||||
Done Inline ActionsCould be a helper function? ApplyMessageMaybe? Stan: Could be a helper function? ApplyMessageMaybe? | |||||
{ | { | ||||
case GameMessageType::Reset: | case GameMessageType::Reset: | ||||
{ | { | ||||
if (isGameStarted) | if (isGameStarted) | ||||
EndGame(); | EndGame(); | ||||
g_Game = new CGame(m_ScenarioConfig.saveReplay); | g_Game = new CGame(m_ScenarioConfig.saveReplay); | ||||
ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); | ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::RootedValue attrs(cx); | JS::RootedValue attrs(cx); | ||||
scriptInterface.ParseJSON(m_ScenarioConfig.content, &attrs); | scriptInterface.ParseJSON(m_ScenarioConfig.content, &attrs); | ||||
g_Game->SetPlayerID(m_ScenarioConfig.playerID); | g_Game->SetPlayerID(m_ScenarioConfig.playerID); | ||||
g_Game->StartGame(&attrs, ""); | g_Game->StartGame(&attrs, ""); | ||||
if (nonVisual) | if (nonVisual) | ||||
{ | { | ||||
LDR_NonprogressiveLoad(); | LDR_NonprogressiveLoad(); | ||||
ENSURE(g_Game->ReallyStartGame() == PSRETURN_OK); | ENSURE(g_Game->ReallyStartGame() == PSRETURN_OK); | ||||
m_GameState = GetGameState(); | m_GameState = GetGameState(); | ||||
m_msgApplied.notify_one(); | m_MsgApplied.notify_one(); | ||||
m_msgLock.unlock(); | m_MsgLock.unlock(); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
JS::RootedValue initData(cx); | JS::RootedValue initData(cx); | ||||
scriptInterface.CreateObject(cx, &initData); | scriptInterface.CreateObject(cx, &initData); | ||||
scriptInterface.SetProperty(initData, "attribs", attrs); | scriptInterface.SetProperty(initData, "attribs", attrs); | ||||
JS::RootedValue playerAssignments(cx); | JS::RootedValue playerAssignments(cx); | ||||
scriptInterface.CreateObject(cx, &playerAssignments); | scriptInterface.CreateObject(cx, &playerAssignments); | ||||
scriptInterface.SetProperty(initData, "playerAssignments", playerAssignments); | scriptInterface.SetProperty(initData, "playerAssignments", playerAssignments); | ||||
g_GUI->SwitchPage(L"page_loading.xml", &scriptInterface, initData); | g_GUI->SwitchPage(L"page_loading.xml", &scriptInterface, initData); | ||||
m_NeedsGameState = true; | m_NeedsGameState = true; | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
case GameMessageType::Commands: | case GameMessageType::Commands: | ||||
{ | { | ||||
if (!g_Game) | if (!g_Game) | ||||
{ | { | ||||
m_GameState = EMPTY_STATE; | m_GameState = EMPTY_STATE; | ||||
m_msgApplied.notify_one(); | m_MsgApplied.notify_one(); | ||||
m_msgLock.unlock(); | m_MsgLock.unlock(); | ||||
return; | return; | ||||
} | } | ||||
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); | const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); | ||||
CLocalTurnManager* turnMgr = static_cast<CLocalTurnManager*>(g_Game->GetTurnManager()); | CLocalTurnManager* turnMgr = static_cast<CLocalTurnManager*>(g_Game->GetTurnManager()); | ||||
for (Command command : msg.commands) | for (RLGameCommand command : msg.commands) | ||||
StanUnsubmitted Done Inline ActionsConst & ? Stan: Const & ? | |||||
{ | { | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::RootedValue commandJSON(cx); | JS::RootedValue commandJSON(cx); | ||||
scriptInterface.ParseJSON(command.json_cmd, &commandJSON); | scriptInterface.ParseJSON(command.json_cmd, &commandJSON); | ||||
turnMgr->PostCommand(command.playerID, commandJSON); | turnMgr->PostCommand(command.playerID, commandJSON); | ||||
} | } | ||||
const double deltaRealTime = DEFAULT_TURN_LENGTH_SP; | const double deltaRealTime = DEFAULT_TURN_LENGTH_SP; | ||||
if (nonVisual) | if (nonVisual) | ||||
{ | { | ||||
const double deltaSimTime = deltaRealTime * g_Game->GetSimRate(); | const double deltaSimTime = deltaRealTime * g_Game->GetSimRate(); | ||||
size_t maxTurns = static_cast<size_t>(g_Game->GetSimRate()); | size_t maxTurns = static_cast<size_t>(g_Game->GetSimRate()); | ||||
g_Game->GetTurnManager()->Update(deltaSimTime, maxTurns); | g_Game->GetTurnManager()->Update(deltaSimTime, maxTurns); | ||||
} | } | ||||
else | else | ||||
g_Game->Update(deltaRealTime); | g_Game->Update(deltaRealTime); | ||||
m_GameState = GetGameState(); | m_GameState = GetGameState(); | ||||
m_msgApplied.notify_one(); | m_MsgApplied.notify_one(); | ||||
m_msgLock.unlock(); | m_MsgLock.unlock(); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
else | else | ||||
m_msgLock.unlock(); | m_MsgLock.unlock(); | ||||
} | } | ||||
} | } | ||||
std::string RLInterface::GetGameState() | std::string RLInterface::GetGameState() | ||||
StanUnsubmitted Done Inline Actionsconst ? Stan: const ? | |||||
{ | { | ||||
const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); | const ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); | ||||
const CSimContext simContext = g_Game->GetSimulation2()->GetSimContext(); | const CSimContext simContext = g_Game->GetSimulation2()->GetSimContext(); | ||||
CmpPtr<ICmpAIInterface> cmpAIInterface(simContext.GetSystemEntity()); | CmpPtr<ICmpAIInterface> cmpAIInterface(simContext.GetSystemEntity()); | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::RootedValue state(cx); | JS::RootedValue state(cx); | ||||
cmpAIInterface->GetFullRepresentation(&state, true); | cmpAIInterface->GetFullRepresentation(&state, true); | ||||
return scriptInterface.StringifyJSON(&state, false); | return scriptInterface.StringifyJSON(&state, false); | ||||
} | } | ||||
bool RLInterface::IsGameRunning() | bool RLInterface::IsGameRunning() const | ||||
{ | { | ||||
return !!g_Game; | return !!g_Game; | ||||
Done Inline ActionsMaybe g_Game != nullptr? No strong feelings. Stan: Maybe g_Game != nullptr? No strong feelings. | |||||
} | } | ||||
Not Done Inline ActionsMight be const float. vladislavbelov: Might be `const float`. |
Wrong order.