2013-12-05 08:26:21 +08:00
/****************************************************************************
2014-01-07 11:47:11 +08:00
Copyright ( c ) 2013 - 2014 Chukong Technologies Inc .
2013-12-05 08:26:21 +08:00
http : //www.cocos2d-x.org
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-11-27 10:58:36 +08:00
2013-12-05 11:33:50 +08:00
# include "CCConsole.h"
2013-11-27 10:58:36 +08:00
2013-12-04 10:46:54 +08:00
# include <thread>
2013-12-05 10:28:09 +08:00
# include <algorithm>
2014-02-09 04:46:44 +08:00
# include <functional>
# include <cctype>
# include <locale>
# include <sstream>
2013-12-04 10:46:54 +08:00
2013-11-27 10:58:36 +08:00
# include <stdio.h>
2013-12-05 04:26:43 +08:00
# include <time.h>
# include <fcntl.h>
2013-12-05 16:09:38 +08:00
2014-01-04 14:40:22 +08:00
# if defined(_MSC_VER) || defined(__MINGW32__)
2013-12-05 16:09:38 +08:00
# include <io.h>
# include <WS2tcpip.h>
# define bzero(a, b) memset(a, 0, b);
# else
# include <netdb.h>
# include <unistd.h>
2013-12-05 04:26:43 +08:00
# include <arpa/inet.h>
2013-12-04 10:46:54 +08:00
# include <netinet/in.h>
# include <sys/socket.h>
# include <sys/un.h>
2013-12-05 16:09:38 +08:00
# endif
2013-11-27 10:58:36 +08:00
# include "CCDirector.h"
2013-12-04 10:46:54 +08:00
# include "CCScheduler.h"
2013-12-05 08:57:44 +08:00
# include "CCScene.h"
2014-01-11 11:04:07 +08:00
# include "CCPlatformConfig.h"
2014-01-15 12:05:17 +08:00
# include "platform/CCFileUtils.h"
2014-01-15 09:22:45 +08:00
# include "CCConfiguration.h"
# include "CCTextureCache.h"
2014-02-09 04:46:44 +08:00
# include "CCGLView.h"
2013-12-05 08:57:44 +08:00
2013-12-05 16:09:38 +08:00
NS_CC_BEGIN
2013-11-27 10:58:36 +08:00
2013-12-05 13:51:08 +08:00
2014-02-09 04:46:44 +08:00
//
// Trimming functions were taken from: http://stackoverflow.com/a/217605
//
// trim from start
static std : : string & ltrim ( std : : string & s ) {
s . erase ( s . begin ( ) , std : : find_if ( s . begin ( ) , s . end ( ) , std : : not1 ( std : : ptr_fun < int , int > ( std : : isspace ) ) ) ) ;
return s ;
}
// trim from end
static std : : string & rtrim ( std : : string & s ) {
s . erase ( std : : find_if ( s . rbegin ( ) , s . rend ( ) , std : : not1 ( std : : ptr_fun < int , int > ( std : : isspace ) ) ) . base ( ) , s . end ( ) ) ;
return s ;
}
// trim from both ends
static std : : string & trim ( std : : string & s ) {
return ltrim ( rtrim ( s ) ) ;
}
2013-12-05 13:51:08 +08:00
// helper free functions
// dprintf() is not defined in Android
// so we add our own 'dpritnf'
static ssize_t mydprintf ( int sock , const char * format , . . . )
{
va_list args ;
2014-01-15 09:22:45 +08:00
char buf [ 16386 ] ;
2013-12-05 13:51:08 +08:00
va_start ( args , format ) ;
vsnprintf ( buf , sizeof ( buf ) , format , args ) ;
va_end ( args ) ;
return write ( sock , buf , strlen ( buf ) ) ;
}
2014-02-11 16:57:30 +08:00
static void sendPrompt ( int fd )
{
2014-02-11 17:05:10 +08:00
const char prompt [ ] = " > " ;
2014-02-11 16:57:30 +08:00
write ( fd , prompt , sizeof ( prompt ) ) ;
}
2013-12-13 06:30:22 +08:00
static int printSceneGraph ( int fd , Node * node , int level )
2013-12-05 13:51:08 +08:00
{
2013-12-13 06:30:22 +08:00
int total = 1 ;
2013-12-05 13:51:08 +08:00
for ( int i = 0 ; i < level ; + + i )
write ( fd , " - " , 1 ) ;
2013-12-13 06:30:22 +08:00
mydprintf ( fd , " %s \n " , node - > getDescription ( ) . c_str ( ) ) ;
2013-12-05 13:51:08 +08:00
2013-12-05 14:07:23 +08:00
for ( const auto & child : node - > getChildren ( ) )
2013-12-13 06:30:22 +08:00
total + = printSceneGraph ( fd , child , level + 1 ) ;
return total ;
2013-12-05 13:51:08 +08:00
}
static void printSceneGraphBoot ( int fd )
{
write ( fd , " \n " , 1 ) ;
auto scene = Director : : getInstance ( ) - > getRunningScene ( ) ;
2013-12-13 06:30:22 +08:00
int total = printSceneGraph ( fd , scene , 0 ) ;
mydprintf ( fd , " Total Nodes: %d \n " , total ) ;
2014-02-11 16:57:30 +08:00
sendPrompt ( fd ) ;
2013-12-05 13:51:08 +08:00
}
2014-01-15 09:22:45 +08:00
static void printFileUtils ( int fd )
{
FileUtils * fu = FileUtils : : getInstance ( ) ;
mydprintf ( fd , " \n Search Paths: \n " ) ;
auto list = fu - > getSearchPaths ( ) ;
for ( const auto & item : list ) {
mydprintf ( fd , " %s \n " , item . c_str ( ) ) ;
}
mydprintf ( fd , " \n Resolution Order: \n " ) ;
list = fu - > getSearchResolutionsOrder ( ) ;
for ( const auto & item : list ) {
mydprintf ( fd , " %s \n " , item . c_str ( ) ) ;
}
mydprintf ( fd , " \n Writeble Path: \n " ) ;
mydprintf ( fd , " %s \n " , fu - > getWritablePath ( ) . c_str ( ) ) ;
mydprintf ( fd , " \n Full Path Cache: \n " ) ;
auto cache = fu - > getFullPathCache ( ) ;
for ( const auto & item : cache ) {
mydprintf ( fd , " %s -> %s \n " , item . first . c_str ( ) , item . second . c_str ( ) ) ;
}
2014-02-11 16:57:30 +08:00
sendPrompt ( fd ) ;
2014-01-15 09:22:45 +08:00
}
2014-01-04 14:40:22 +08:00
# if defined(__MINGW32__)
static const char * inet_ntop ( int af , const void * src , char * dst , int cnt )
{
struct sockaddr_in srcaddr ;
memset ( & srcaddr , 0 , sizeof ( struct sockaddr_in ) ) ;
memcpy ( & ( srcaddr . sin_addr ) , src , sizeof ( srcaddr . sin_addr ) ) ;
srcaddr . sin_family = af ;
if ( WSAAddressToString ( ( struct sockaddr * ) & srcaddr , sizeof ( struct sockaddr_in ) , 0 , dst , ( LPDWORD ) & cnt ) ! = 0 )
{
2014-01-09 17:48:37 +08:00
return nullptr ;
2014-01-04 14:40:22 +08:00
}
return dst ;
}
# endif
2013-12-05 13:51:08 +08:00
2014-01-11 11:04:07 +08:00
//
// Free functions to log
//
2014-01-16 03:17:21 +08:00
static void _log ( const char * format , va_list args )
2014-01-11 11:04:07 +08:00
{
char buf [ MAX_LOG_LENGTH ] ;
vsnprintf ( buf , MAX_LOG_LENGTH - 3 , format , args ) ;
strcat ( buf , " \n " ) ;
# if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
__android_log_print ( ANDROID_LOG_DEBUG , " cocos2d-x debug info " , " %s " , buf ) ;
# elif CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
WCHAR wszBuf [ MAX_LOG_LENGTH ] = { 0 } ;
2014-01-14 12:28:24 +08:00
MultiByteToWideChar ( CP_UTF8 , 0 , buf , - 1 , wszBuf , sizeof ( wszBuf ) ) ;
2014-01-11 11:04:07 +08:00
OutputDebugStringW ( wszBuf ) ;
2014-01-14 12:28:24 +08:00
WideCharToMultiByte ( CP_ACP , 0 , wszBuf , sizeof ( wszBuf ) , buf , sizeof ( buf ) , NULL , FALSE ) ;
2014-02-05 00:59:56 +08:00
printf ( " %s " , buf ) ;
2014-01-11 11:04:07 +08:00
# else
// Linux, Mac, iOS, etc
fprintf ( stdout , " cocos2d: %s " , buf ) ;
fflush ( stdout ) ;
# endif
Director : : getInstance ( ) - > getConsole ( ) - > log ( buf ) ;
}
2014-01-16 03:17:21 +08:00
// XXX: Deprecated
void CCLog ( const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
_log ( format , args ) ;
va_end ( args ) ;
}
void log ( const char * format , . . . )
{
va_list args ;
va_start ( args , format ) ;
_log ( format , args ) ;
va_end ( args ) ;
}
2014-01-11 11:04:07 +08:00
2013-12-05 13:51:08 +08:00
//
// Console code
//
2013-11-27 10:58:36 +08:00
Console : : Console ( )
2013-12-04 10:46:54 +08:00
: _listenfd ( - 1 )
2013-11-27 10:58:36 +08:00
, _running ( false )
, _endThread ( false )
2013-12-05 16:09:38 +08:00
, _userCommands ( nullptr )
, _maxUserCommands ( 0 )
2014-01-11 09:58:54 +08:00
, _sendDebugStrings ( false )
2013-12-05 16:09:38 +08:00
{
2013-12-05 16:49:05 +08:00
// VS2012 doesn't support initializer list, so we create a new array and assign its elements to '_command'.
2013-12-05 16:09:38 +08:00
Command commands [ ] = {
2014-02-09 13:29:39 +08:00
{ " config " , " Print the Configuration object " , std : : bind ( & Console : : commandConfig , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " debugmsg " , " Whether or not to forward the debug messages on the console. Args: [on | off] " , [ & ] ( int fd , const std : : string & args ) {
2014-02-09 04:46:44 +08:00
if ( args . compare ( " on " ) = = 0 | | args . compare ( " off " ) = = 0 ) {
_sendDebugStrings = ( args . compare ( " on " ) = = 0 ) ;
} else {
2014-02-09 13:29:39 +08:00
mydprintf ( fd , " Debug message is: %s \n " , _sendDebugStrings ? " on " : " off " ) ;
2014-02-09 04:46:44 +08:00
}
2014-01-11 09:58:54 +08:00
} } ,
2014-02-09 04:46:44 +08:00
{ " exit " , " Close connection to the console " , std : : bind ( & Console : : commandExit , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-02-09 13:29:39 +08:00
{ " fileutils " , " Flush or print the FileUtils info. Args: [flush | ] " , std : : bind ( & Console : : commandFileUtils , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " fps " , " Turn on / off the FPS. Args: [on | off] " , [ ] ( int fd , const std : : string & args ) {
2014-02-09 04:46:44 +08:00
if ( args . compare ( " on " ) = = 0 | | args . compare ( " off " ) = = 0 ) {
bool state = ( args . compare ( " on " ) = = 0 ) ;
Director * dir = Director : : getInstance ( ) ;
Scheduler * sched = dir - > getScheduler ( ) ;
sched - > performFunctionInCocosThread ( std : : bind ( & Director : : setDisplayStats , dir , state ) ) ;
} else {
2014-02-09 13:29:39 +08:00
mydprintf ( fd , " FPS is: %s \n " , Director : : getInstance ( ) - > isDisplayStats ( ) ? " on " : " off " ) ;
2014-02-09 04:46:44 +08:00
}
2014-01-11 09:58:54 +08:00
} } ,
2014-02-09 04:46:44 +08:00
{ " help " , " Print this message " , std : : bind ( & Console : : commandHelp , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-02-09 13:29:39 +08:00
{ " projection " , " Change or print the current projection. Args: [2d | 3d] " , std : : bind ( & Console : : commandProjection , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " resolution " , " Change or print the window resolution. Args: [width height resolution_policy | ] " , std : : bind ( & Console : : commandResolution , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " scenegraph " , " Print the scene graph " , std : : bind ( & Console : : commandSceneGraph , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
{ " texture " , " Flush or print the TextureCache info. Args: [flush | ] " , std : : bind ( & Console : : commandTextures , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) } ,
2014-01-11 09:58:54 +08:00
} ;
_maxCommands = sizeof ( commands ) / sizeof ( commands [ 0 ] ) ;
2014-01-11 12:26:15 +08:00
for ( int i = 0 ; i < _maxCommands ; + + i )
2013-12-05 16:09:38 +08:00
{
_commands [ i ] = commands [ i ] ;
}
2013-12-05 09:38:11 +08:00
}
2013-11-27 10:58:36 +08:00
Console : : ~ Console ( )
{
2014-01-11 09:11:14 +08:00
stop ( ) ;
2013-11-27 10:58:36 +08:00
}
2013-12-04 10:46:54 +08:00
bool Console : : listenOnTCP ( int port )
{
int listenfd , n ;
const int on = 1 ;
2013-12-05 10:19:51 +08:00
struct addrinfo hints , * res , * ressave ;
2013-12-04 10:46:54 +08:00
char serv [ 30 ] ;
2013-12-05 13:51:08 +08:00
snprintf ( serv , sizeof ( serv ) - 1 , " %d " , port ) ;
2013-12-04 10:46:54 +08:00
serv [ sizeof ( serv ) - 1 ] = 0 ;
bzero ( & hints , sizeof ( struct addrinfo ) ) ;
hints . ai_flags = AI_PASSIVE ;
2013-12-05 13:51:08 +08:00
hints . ai_family = AF_INET ; // AF_UNSPEC: Do we need IPv6 ?
2013-12-04 10:46:54 +08:00
hints . ai_socktype = SOCK_STREAM ;
2013-12-05 16:09:38 +08:00
# if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
WSADATA wsaData ;
n = WSAStartup ( MAKEWORD ( 2 , 2 ) , & wsaData ) ;
# endif
2013-12-04 10:46:54 +08:00
if ( ( n = getaddrinfo ( NULL , serv , & hints , & res ) ) ! = 0 ) {
fprintf ( stderr , " net_listen error for %s: %s " , serv , gai_strerror ( n ) ) ;
return false ;
}
ressave = res ;
do {
listenfd = socket ( res - > ai_family , res - > ai_socktype , res - > ai_protocol ) ;
if ( listenfd < 0 )
2013-12-05 10:19:51 +08:00
continue ; /* error, try next one */
2013-12-04 10:46:54 +08:00
2013-12-05 16:09:38 +08:00
setsockopt ( listenfd , SOL_SOCKET , SO_REUSEADDR , ( const char * ) & on , sizeof ( on ) ) ;
2013-12-04 10:46:54 +08:00
if ( bind ( listenfd , res - > ai_addr , res - > ai_addrlen ) = = 0 )
2013-12-05 10:19:51 +08:00
break ; /* success */
2013-12-04 10:46:54 +08:00
2013-12-05 10:19:51 +08:00
close ( listenfd ) ; /* bind error, close and try next one */
2013-12-04 10:46:54 +08:00
} while ( ( res = res - > ai_next ) ! = NULL ) ;
if ( res = = NULL ) {
perror ( " net_listen: " ) ;
freeaddrinfo ( ressave ) ;
return false ;
}
2013-12-05 08:26:21 +08:00
2013-12-04 10:46:54 +08:00
listen ( listenfd , 50 ) ;
2013-12-05 08:26:21 +08:00
if ( res - > ai_family = = AF_INET ) {
char buf [ INET_ADDRSTRLEN ] = " " ;
struct sockaddr_in * sin = ( struct sockaddr_in * ) res - > ai_addr ;
2013-12-05 13:51:08 +08:00
if ( inet_ntop ( res - > ai_family , & sin - > sin_addr , buf , sizeof ( buf ) ) ! = NULL )
2014-01-11 09:58:54 +08:00
cocos2d : : log ( " Console: listening on %s : %d " , buf , ntohs ( sin - > sin_port ) ) ;
2013-12-05 13:51:08 +08:00
else
perror ( " inet_ntop " ) ;
} else if ( res - > ai_family = = AF_INET6 ) {
char buf [ INET6_ADDRSTRLEN ] = " " ;
struct sockaddr_in6 * sin = ( struct sockaddr_in6 * ) res - > ai_addr ;
if ( inet_ntop ( res - > ai_family , & sin - > sin6_addr , buf , sizeof ( buf ) ) ! = NULL )
2014-01-11 09:58:54 +08:00
cocos2d : : log ( " Console: listening on %s : %d " , buf , ntohs ( sin - > sin6_port ) ) ;
2013-12-05 08:26:21 +08:00
else
perror ( " inet_ntop " ) ;
}
2013-12-05 13:51:08 +08:00
2013-12-04 10:46:54 +08:00
freeaddrinfo ( ressave ) ;
return listenOnFileDescriptor ( listenfd ) ;
}
bool Console : : listenOnFileDescriptor ( int fd )
2013-11-27 10:58:36 +08:00
{
2014-01-11 09:11:14 +08:00
if ( _running ) {
cocos2d : : log ( " Console already started. 'stop' it before calling 'listen' again " ) ;
return false ;
}
2013-12-04 10:46:54 +08:00
_listenfd = fd ;
2013-11-27 10:58:36 +08:00
_thread = std : : thread ( std : : bind ( & Console : : loop , this ) ) ;
2013-12-04 10:46:54 +08:00
return true ;
2013-11-27 10:58:36 +08:00
}
2014-01-11 09:11:14 +08:00
void Console : : stop ( )
2013-11-27 10:58:36 +08:00
{
2013-12-04 10:46:54 +08:00
if ( _running ) {
_endThread = true ;
_thread . join ( ) ;
}
2013-11-27 10:58:36 +08:00
}
2013-12-05 09:38:11 +08:00
void Console : : setUserCommands ( Command * commands , int numberOfCommands )
{
_userCommands = commands ;
_maxUserCommands = numberOfCommands ;
}
2013-12-05 08:26:21 +08:00
//
// commands
//
2014-02-09 04:46:44 +08:00
void Console : : commandHelp ( int fd , const std : : string & args )
2013-12-04 10:46:54 +08:00
{
2013-12-05 08:26:21 +08:00
const char help [ ] = " \n Available commands: \n " ;
write ( fd , help , sizeof ( help ) ) ;
2013-12-05 09:38:11 +08:00
for ( int i = 0 ; i < _maxCommands ; + + i ) {
2014-02-09 13:29:39 +08:00
mydprintf ( fd , " \t %s " , _commands [ i ] . name ) ;
ssize_t tabs = strlen ( _commands [ i ] . name ) / 8 ;
tabs = 3 - tabs ;
for ( int j = 0 ; j < tabs ; j + + ) {
mydprintf ( fd , " \t " ) ;
}
mydprintf ( fd , " %s \n " , _commands [ i ] . help ) ;
2013-12-05 09:38:11 +08:00
}
// User commands
for ( int i = 0 ; i < _maxUserCommands ; + + i ) {
2014-02-09 13:29:39 +08:00
mydprintf ( fd , " \t %s " , _userCommands [ i ] . name ) ;
ssize_t tabs = strlen ( _userCommands [ i ] . name ) / 8 ;
tabs = 3 - tabs ;
for ( int j = 0 ; j < tabs ; j + + ) {
mydprintf ( fd , " \t " ) ;
}
mydprintf ( fd , " %s \n " , _userCommands [ i ] . help ) ;
2013-12-04 10:46:54 +08:00
}
2013-12-05 08:26:21 +08:00
}
2013-12-04 10:46:54 +08:00
2014-02-09 04:46:44 +08:00
void Console : : commandExit ( int fd , const std : : string & args )
2013-12-05 08:26:21 +08:00
{
FD_CLR ( fd , & _read_set ) ;
_fds . erase ( std : : remove ( _fds . begin ( ) , _fds . end ( ) , fd ) , _fds . end ( ) ) ;
close ( fd ) ;
}
2014-02-09 04:46:44 +08:00
void Console : : commandSceneGraph ( int fd , const std : : string & args )
2013-12-05 08:57:44 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
sched - > performFunctionInCocosThread ( std : : bind ( & printSceneGraphBoot , fd ) ) ;
}
2014-02-09 04:46:44 +08:00
void Console : : commandFileUtils ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
2014-02-09 04:46:44 +08:00
if ( args . compare ( " flush " ) = = 0 )
{
FileUtils : : getInstance ( ) - > purgeCachedEntries ( ) ;
}
else if ( args . length ( ) = = 0 )
{
sched - > performFunctionInCocosThread ( std : : bind ( & printFileUtils , fd ) ) ;
}
else
{
mydprintf ( fd , " Unsupported argument: '%s'. Supported arguments: 'flush' or nothing " , args . c_str ( ) ) ;
}
2014-01-15 09:22:45 +08:00
}
2014-02-09 04:46:44 +08:00
void Console : : commandConfig ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
sched - > performFunctionInCocosThread ( [ & ] ( ) {
mydprintf ( fd , " %s " , Configuration : : getInstance ( ) - > getInfo ( ) . c_str ( ) ) ;
}
) ;
}
2014-02-09 04:46:44 +08:00
void Console : : commandResolution ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
2014-02-09 04:46:44 +08:00
if ( args . length ( ) = = 0 ) {
auto director = Director : : getInstance ( ) ;
Size points = director - > getWinSize ( ) ;
Size pixels = director - > getWinSizeInPixels ( ) ;
auto glview = director - > getOpenGLView ( ) ;
Size design = glview - > getDesignResolutionSize ( ) ;
ResolutionPolicy res = glview - > getResolutionPolicy ( ) ;
Rect visibleRect = glview - > getVisibleRect ( ) ;
mydprintf ( fd , " Window Size: \n "
" \t %d x %d (points) \n "
" \t %d x %d (pixels) \n "
" \t %d x %d (design resolution) \n "
" Resolution Policy: %d \n "
" Visible Rect: \n "
" \t origin: %d x %d \n "
2014-02-11 17:00:09 +08:00
" \t size: %d x %d \n " ,
2014-02-09 04:46:44 +08:00
( int ) points . width , ( int ) points . height ,
( int ) pixels . width , ( int ) pixels . height ,
( int ) design . width , ( int ) design . height ,
( int ) res ,
( int ) visibleRect . origin . x , ( int ) visibleRect . origin . y ,
( int ) visibleRect . size . width , ( int ) visibleRect . size . height
) ;
2014-02-11 10:48:18 +08:00
sendPrompt ( fd ) ;
2014-02-09 04:46:44 +08:00
} else {
int width , height , policy ;
std : : istringstream stream ( args ) ;
stream > > width > > height > > policy ;
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
sched - > performFunctionInCocosThread ( [ & ] ( ) {
Director : : getInstance ( ) - > getOpenGLView ( ) - > setDesignResolutionSize ( width , height , static_cast < ResolutionPolicy > ( policy ) ) ;
} ) ;
}
}
void Console : : commandProjection ( int fd , const std : : string & args )
{
auto director = Director : : getInstance ( ) ;
Scheduler * sched = director - > getScheduler ( ) ;
if ( args . length ( ) = = 0 )
{
char buf [ 20 ] ;
auto proj = director - > getProjection ( ) ;
switch ( proj ) {
case cocos2d : : Director : : Projection : : _2D :
sprintf ( buf , " 2d " ) ;
break ;
case cocos2d : : Director : : Projection : : _3D :
sprintf ( buf , " 3d " ) ;
break ;
case cocos2d : : Director : : Projection : : CUSTOM :
sprintf ( buf , " custom " ) ;
break ;
default :
sprintf ( buf , " unknown " ) ;
break ;
}
2014-02-11 16:14:49 +08:00
mydprintf ( fd , " Current projection: %s \n " , buf ) ;
2014-02-09 04:46:44 +08:00
}
else if ( args . compare ( " 2d " ) = = 0 )
{
sched - > performFunctionInCocosThread ( [ & ] ( ) {
director - > setProjection ( Director : : Projection : : _2D ) ;
} ) ;
}
else if ( args . compare ( " 3d " ) = = 0 )
{
sched - > performFunctionInCocosThread ( [ & ] ( ) {
director - > setProjection ( Director : : Projection : : _3D ) ;
} ) ;
}
else
{
2014-02-11 16:14:49 +08:00
mydprintf ( fd , " Unsupported argument: '%s'. Supported arguments: '2d' or '3d' \n " , args . c_str ( ) ) ;
2014-02-09 04:46:44 +08:00
}
}
void Console : : commandTextures ( int fd , const std : : string & args )
2014-01-15 09:22:45 +08:00
{
Scheduler * sched = Director : : getInstance ( ) - > getScheduler ( ) ;
2014-02-09 04:46:44 +08:00
if ( args . compare ( " flush " ) = = 0 )
{
sched - > performFunctionInCocosThread ( [ & ] ( ) {
Director : : getInstance ( ) - > getTextureCache ( ) - > removeAllTextures ( ) ;
}
) ;
}
else if ( args . length ( ) = = 0 )
{
sched - > performFunctionInCocosThread ( [ & ] ( ) {
mydprintf ( fd , " %s " , Director : : getInstance ( ) - > getTextureCache ( ) - > getCachedTextureInfo ( ) . c_str ( ) ) ;
2014-02-11 16:14:49 +08:00
sendPrompt ( fd ) ;
2014-02-09 04:46:44 +08:00
}
) ;
}
else
{
mydprintf ( fd , " Unsupported argument: '%s'. Supported arguments: 'flush' or nothing " , args . c_str ( ) ) ;
2014-01-15 09:22:45 +08:00
}
}
2013-12-05 09:38:11 +08:00
bool Console : : parseCommand ( int fd )
2013-12-05 08:26:21 +08:00
{
auto r = readline ( fd ) ;
if ( r < 1 )
return false ;
2013-12-05 09:38:11 +08:00
bool found = false ;
for ( int i = 0 ; i < _maxCommands ; + + i ) {
2014-02-09 04:46:44 +08:00
ssize_t commandLen = strlen ( _commands [ i ] . name ) ;
if ( strncmp ( _buffer , _commands [ i ] . name , commandLen ) = = 0 ) {
2013-12-05 08:26:21 +08:00
// XXX TODO FIXME
// Ideally this loop should execute the function in the cocos2d according to a variable
// But clang crashes in runtime when doing that (bug in clang, not in the code).
// So, unfortunately, the only way to fix it was to move that logic to the callback itself
2014-02-09 04:46:44 +08:00
std : : string args ;
if ( strlen ( _buffer ) > = commandLen + 2 ) {
args = std : : string ( & _buffer [ commandLen ] + 1 ) ;
args = trim ( args ) ;
}
_commands [ i ] . callback ( fd , args ) ;
2013-12-05 09:38:11 +08:00
found = true ;
2013-12-05 08:26:21 +08:00
break ;
}
}
2013-12-05 09:38:11 +08:00
// user commands
for ( int i = 0 ; i < _maxUserCommands & & ! found ; + + i ) {
2014-02-09 04:46:44 +08:00
ssize_t commandLen = strlen ( _userCommands [ i ] . name ) ;
if ( strncmp ( _buffer , _userCommands [ i ] . name , commandLen ) = = 0 ) {
std : : string args ;
if ( strlen ( _buffer ) > = commandLen + 2 ) {
args = std : : string ( & _buffer [ commandLen ] + 1 ) ;
args = trim ( args ) ;
}
_userCommands [ i ] . callback ( fd , args ) ;
2013-12-05 09:38:11 +08:00
found = true ;
break ;
}
}
2014-01-11 10:11:35 +08:00
if ( ! found & & strcmp ( _buffer , " \r \n " ) ! = 0 ) {
2013-12-05 08:26:21 +08:00
const char err [ ] = " Unknown command. Type 'help' for options \n " ;
write ( fd , err , sizeof ( err ) ) ;
}
sendPrompt ( fd ) ;
return true ;
}
//
// Helpers
//
2014-02-11 16:57:30 +08:00
2013-11-27 10:58:36 +08:00
2013-12-04 10:46:54 +08:00
ssize_t Console : : readline ( int fd )
2013-12-03 01:57:16 +08:00
{
2013-12-05 08:26:21 +08:00
int maxlen = sizeof ( _buffer ) - 1 ;
2013-12-05 10:19:51 +08:00
ssize_t n , rc ;
char c , * ptr ;
2013-12-03 01:57:16 +08:00
2013-12-04 10:46:54 +08:00
ptr = _buffer ;
2013-12-03 01:57:16 +08:00
2013-12-05 10:19:51 +08:00
for ( n = 1 ; n < maxlen ; n + + ) {
if ( ( rc = read ( fd , & c , 1 ) ) = = 1 ) {
* ptr + + = c ;
if ( c = = ' \n ' )
break ;
} else if ( rc = = 0 ) {
return 0 ;
} else if ( errno = = EINTR ) {
2013-12-03 01:57:16 +08:00
continue ;
} else {
return - 1 ;
}
2013-12-05 10:19:51 +08:00
}
2013-12-03 01:57:16 +08:00
2013-12-05 10:19:51 +08:00
* ptr = 0 ;
return n ;
2013-12-03 01:57:16 +08:00
}
2013-12-05 08:26:21 +08:00
void Console : : addClient ( )
2013-11-27 10:58:36 +08:00
{
2013-12-05 08:26:21 +08:00
struct sockaddr client ;
2013-12-05 10:19:51 +08:00
socklen_t client_len ;
2013-12-05 08:26:21 +08:00
/* new client */
client_len = sizeof ( client ) ;
int fd = accept ( _listenfd , ( struct sockaddr * ) & client , & client_len ) ;
// add fd to list of FD
if ( fd ! = - 1 ) {
FD_SET ( fd , & _read_set ) ;
_fds . push_back ( fd ) ;
_maxfd = std : : max ( _maxfd , fd ) ;
sendPrompt ( fd ) ;
}
}
2014-01-11 09:58:54 +08:00
void Console : : log ( const char * buf )
{
if ( _sendDebugStrings ) {
_DebugStringsMutex . lock ( ) ;
_DebugStrings . push_back ( buf ) ;
_DebugStringsMutex . unlock ( ) ;
}
}
2013-12-05 08:26:21 +08:00
//
// Main Loop
//
void Console : : loop ( )
{
fd_set copy_set ;
2013-12-05 10:19:51 +08:00
struct timeval timeout , timeout_copy ;
2013-11-27 10:58:36 +08:00
2013-12-05 08:26:21 +08:00
_running = true ;
FD_ZERO ( & _read_set ) ;
FD_SET ( _listenfd , & _read_set ) ;
2013-12-05 04:26:43 +08:00
_maxfd = _listenfd ;
2013-12-04 10:46:54 +08:00
2013-12-05 10:19:51 +08:00
timeout . tv_sec = 0 ;
2013-12-05 04:26:43 +08:00
/* 0.016 seconds. Wake up once per frame at 60PFS */
2014-02-03 06:24:58 +08:00
timeout . tv_usec = 16000 ;
2013-11-27 10:58:36 +08:00
2013-12-05 10:19:51 +08:00
while ( ! _endThread ) {
2013-11-27 10:58:36 +08:00
2013-12-05 10:19:51 +08:00
copy_set = _read_set ;
2013-12-04 10:46:54 +08:00
timeout_copy = timeout ;
2013-12-05 10:19:51 +08:00
int nready = select ( _maxfd + 1 , & copy_set , NULL , NULL , & timeout_copy ) ;
2013-11-27 10:58:36 +08:00
2014-01-11 09:58:54 +08:00
if ( nready = = - 1 )
{
/* error */
2013-12-05 10:19:51 +08:00
if ( errno ! = EINTR )
log ( " Abnormal error in select() \n " ) ;
continue ;
2013-12-04 10:46:54 +08:00
}
2014-01-11 09:58:54 +08:00
else if ( nready = = 0 )
{
/* timeout. do somethig ? */
2013-12-04 10:46:54 +08:00
}
2014-01-11 09:58:54 +08:00
else
{
/* new client */
if ( FD_ISSET ( _listenfd , & copy_set ) ) {
addClient ( ) ;
if ( - - nready < = 0 )
continue ;
}
2013-12-04 10:46:54 +08:00
2014-01-11 09:58:54 +08:00
/* data from client */
std : : vector < int > to_remove ;
for ( const auto & fd : _fds ) {
if ( FD_ISSET ( fd , & copy_set ) ) {
if ( ! parseCommand ( fd ) ) {
to_remove . push_back ( fd ) ;
}
if ( - - nready < = 0 )
break ;
2013-12-05 08:26:21 +08:00
}
2014-01-11 09:58:54 +08:00
}
/* remove closed conections */
for ( int fd : to_remove ) {
FD_CLR ( fd , & _read_set ) ;
_fds . erase ( std : : remove ( _fds . begin ( ) , _fds . end ( ) , fd ) , _fds . end ( ) ) ;
2013-12-04 10:46:54 +08:00
}
}
2013-12-05 08:26:21 +08:00
2014-01-11 09:58:54 +08:00
/* Any message for the remote console ? send it! */
if ( ! _DebugStrings . empty ( ) ) {
_DebugStringsMutex . lock ( ) ;
for ( const auto & str : _DebugStrings ) {
for ( const auto & fd : _fds ) {
write ( fd , str . c_str ( ) , str . length ( ) ) ;
}
}
_DebugStrings . clear ( ) ;
_DebugStringsMutex . unlock ( ) ;
2013-12-05 08:26:21 +08:00
}
2013-12-05 04:26:43 +08:00
}
// clean up: ignore stdin, stdout and stderr
for ( const auto & fd : _fds )
close ( fd ) ;
close ( _listenfd ) ;
2013-12-05 08:26:21 +08:00
_running = false ;
2013-11-27 10:58:36 +08:00
}
2013-12-05 16:09:38 +08:00
NS_CC_END