Skip to content

Instantly share code, notes, and snippets.

@lzubiaur
Last active August 29, 2015 14:13
Show Gist options
  • Save lzubiaur/d49dd6db1a08b6b5e5fa to your computer and use it in GitHub Desktop.
Save lzubiaur/d49dd6db1a08b6b5e5fa to your computer and use it in GitHub Desktop.
Custom Cocos2d-x console commands (run remote lua script...)
/****************************************************************************
Copyright (c) 2013-2015 Laurent Zubiaur.
http://voodoocactus.com
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 "ConsoleCommands.h"
#if defined(_MSC_VER) || defined(__MINGW32__)
#include <io.h>
#include <WS2tcpip.h>
#include <Winsock2.h>
#define bzero(a, b) memset(a, 0, b);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
#include "inet_ntop_winrt.h"
#include "CCWinRTUtils.h"
#endif
#else
#include <netdb.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#endif
NS_CC_BEGIN
ConsoleCommands* ConsoleCommands::_instance = nullptr;
ConsoleCommands* ConsoleCommands::getInstance(void)
{
if (!_instance)
{
_instance = new (std::nothrow) ConsoleCommands();
_instance->init();
}
return _instance;
}
ConsoleCommands::ConsoleCommands(void)
{
}
ConsoleCommands::~ConsoleCommands(void)
{
_instance = nullptr;
}
bool ConsoleCommands::init(void)
{
/// Nothing to do for now
return true;
}
ssize_t ConsoleCommands::readBytes(int fd, char* buffer, size_t maxlen, bool* more)
{
size_t n, rc;
char c, *ptr = buffer;
*more = false;
for( n = 0; n < maxlen; n++ ) {
if( (rc = recv(fd, &c, 1, 0)) ==1 ) {
*ptr++ = c;
if(c == '\n') {
return n;
}
} else if( rc == 0 ) {
return 0;
} else if( errno == EINTR ) {
continue;
} else {
return -1;
}
}
*more = true;
return n;
}
void ConsoleCommands::addCommands(Console *console)
{
console->addCommand({
"runlua",
"Run a Lua script (base64 encoded).",
std::bind(&ConsoleCommands::commandRunLua, this, std::placeholders::_1, std::placeholders::_2)
});
}
void ConsoleCommands::addCommandsToDefaultConsole()
{
addCommands(Director::getInstance()->getConsole());
}
void ConsoleCommands::readAllCommand(int fd, const std::string &in, std::string &out)
{
std::string buf(in);
while (true)
{
char data[4096] = { 0 };
bool more_data;
ssize_t n = readBytes(fd, data, 4096, &more_data);
if (n > 0) {
buf.append(data,n);
}
if (!more_data) {
break;
}
}
unsigned char *decode;
int dt = base64Decode((unsigned char *)buf.c_str(), (unsigned int)buf.length(), &decode);
out.clear();
out.append((const char *)decode,dt);
free(decode);
}
void ConsoleCommands::commandRunLua(int fd, const std::string &s)
{
std::string out;
readAllCommand(fd, s, out);
/// Since we call the cocos2d API we must run it from the main cocos2d thread
/// Note that since the lambda is executed on another thread closures must
/// be passed by value (and not by reference) or they will not be valid once the
/// main function returns.
Director::getInstance()->getScheduler()->performFunctionInCocosThread([=]{
ScriptEngineManager::getInstance()->getScriptEngine()->executeString(out.c_str());
});
}
NS_CC_END // namespace cocos2d
/****************************************************************************
Copyright (c) 2013-2015 Laurent Zubiaur.
http://voodoocactus.com
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.
****************************************************************************/
#ifndef CONSOLECOMMANDS
#define CONSOLECOMMANDS
#include "cocos2d.h"
NS_CC_BEGIN
/*
Singleton class to load custom commands into the cocos2dx remote console (CCConsole).
You can load the custom commands by calling addCommandsToDefaultConsole somewhere in
your code (for instance in AppDelegate::applicationDidFinishLaunching)
/// Load the commands
ConsoleCommands::getInstance()->addCommandsToDefaultConsole();
/// Now start the console
Director::getInstance()->getConsole()->listenOnTCP(8080);
To run a Lua script remotely just have to connect to your game on the port 8080
and type the command "runlua" following by a whitespace and the script (must be base64 encoded).
How to call the "runlua" from the command line?
(echo -n 'runlua '; cat ~/myscript.lua | base64) | nc 192.168.1.10 8080
*/
class ConsoleCommands : public cocos2d::Ref
{
public:
static ConsoleCommands* getInstance(void);
/// Load the custom commands in a console
void addCommands(Console *console);
/// Load the custom commands in the default console
void addCommandsToDefaultConsole();
protected:
/// Private constructor/destructor
ConsoleCommands();
~ConsoleCommands();
/// The singleton instance
static ConsoleCommands* _instance;
bool init();
/// Run a Lua script from the console interface. The script must be base64 encoded.
void commandRunLua(int fd, const std::string &s);
/// cocos2dx only read the first 512 bytes from the command.
/// We have to read the rest of the command ourself from the socket `fd`
void readAllCommand(int fd, const std::string &in, std::string &out);
/// Stolen from cocos2dx::Console
ssize_t readBytes(int fd, char* buffer, size_t maxlen, bool* more);
};
NS_CC_END // namespace cocos2d
#endif // CONSOLECOMMANDS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment