From 4bbcd91bdf70581becf310550b03d1890638b7bf Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Mon, 13 Jan 2014 20:51:56 +0900 Subject: [PATCH 01/51] Fix for compiling error for windows --- cocos/2d/renderer/CCFrustum.cpp | 3 +++ cocos/base/CCConsole.cpp | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cocos/2d/renderer/CCFrustum.cpp b/cocos/2d/renderer/CCFrustum.cpp index cc26b67cab..ccff1e6dee 100644 --- a/cocos/2d/renderer/CCFrustum.cpp +++ b/cocos/2d/renderer/CCFrustum.cpp @@ -27,6 +27,9 @@ #include +#undef far +#undef near + NS_CC_BEGIN ViewTransform::ViewTransform() diff --git a/cocos/base/CCConsole.cpp b/cocos/base/CCConsole.cpp index 58636d15cf..69c44c4494 100644 --- a/cocos/base/CCConsole.cpp +++ b/cocos/base/CCConsole.cpp @@ -143,12 +143,12 @@ void log(const char *format, va_list args) #elif CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 WCHAR wszBuf[MAX_LOG_LENGTH] = {0}; - MultiByteToWideChar(CP_UTF8, 0, szBuf, -1, wszBuf, sizeof(wszBuf)); + MultiByteToWideChar(CP_UTF8, 0, buf, -1, wszBuf, sizeof(wszBuf)); OutputDebugStringW(wszBuf); OutputDebugStringA("\n"); - WideCharToMultiByte(CP_ACP, 0, wszBuf, sizeof(wszBuf), szBuf, sizeof(szBuf), NULL, FALSE); - printf("%s\n", szBuf); + WideCharToMultiByte(CP_ACP, 0, wszBuf, sizeof(wszBuf), buf, sizeof(buf), NULL, FALSE); + printf("%s\n", buf); #else // Linux, Mac, iOS, etc From b45abf3f2d3c80125f7fe8b460e020085743e4fd Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Mon, 13 Jan 2014 21:14:50 +0900 Subject: [PATCH 02/51] Bug fixes for new label --- cocos/2d/CCFontAtlas.cpp | 4 +++- cocos/2d/CCFontDefinition.cpp | 4 +++- cocos/2d/CCLabel.cpp | 6 ++++++ cocos/2d/CCLabelTextFormatter.cpp | 2 -- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cocos/2d/CCFontAtlas.cpp b/cocos/2d/CCFontAtlas.cpp index 4d35ce980d..d1abc79a8d 100644 --- a/cocos/2d/CCFontAtlas.cpp +++ b/cocos/2d/CCFontAtlas.cpp @@ -114,6 +114,8 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) std::unordered_map fontDefs; int length = cc_wcslen(utf16String); + auto yDelta = _currentPageLineHeight * 0.7; + //find out new letter for (int i = 0; i < length; ++i) { @@ -150,7 +152,7 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) tempDef.letteCharUTF16 = utf16String[i]; tempDef.width = tempRect.size.width + _letterPadding; tempDef.height = _currentPageLineHeight - 1; - tempDef.offsetY = tempRect.origin.y; + tempDef.offsetY = tempRect.origin.y + yDelta; tempDef.commonLineHeight = _currentPageLineHeight; } diff --git a/cocos/2d/CCFontDefinition.cpp b/cocos/2d/CCFontDefinition.cpp index c0d8af5051..d2c74ebf30 100644 --- a/cocos/2d/CCFontDefinition.cpp +++ b/cocos/2d/CCFontDefinition.cpp @@ -215,13 +215,15 @@ FontAtlas * FontDefinitionTTF::createFontAtlas() // set the common line height retAtlas->setCommonLineHeight(_commonLineHeight * 0.8); - + auto yDelta = _commonLineHeight * 0.7; + for( auto &item: _fontLettersDefinitionUTF16 ) { if ( item.second.validDefinition ) { FontLetterDefinition tempDefinition = item.second; tempDefinition.offsetX = 0; + tempDefinition.offsetY += yDelta; tempDefinition.anchorX = 0.0f; tempDefinition.anchorY = 1.0f; retAtlas->addLetterDefinition(tempDefinition); diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index d7125bcd30..d343bcd241 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -194,6 +194,8 @@ bool Label::setText(const std::string& stringToRender, float lineWidth, TextHAli // align text alignText(); + updateColor(); + // done here return true; } @@ -438,6 +440,8 @@ bool Label::recordLetterInfo(const cocos2d::Point& point,unsigned short int theC if (static_cast(spriteIndex) >= _lettersInfo.size()) { LetterInfo tmpInfo; + + memset(&tmpInfo, 0, sizeof(tmpInfo)); _lettersInfo.push_back(tmpInfo); } @@ -454,6 +458,8 @@ bool Label::recordPlaceholderInfo(int spriteIndex) if (static_cast(spriteIndex) >= _lettersInfo.size()) { LetterInfo tmpInfo; + + memset(&tmpInfo, 0, sizeof(tmpInfo)); _lettersInfo.push_back(tmpInfo); } diff --git a/cocos/2d/CCLabelTextFormatter.cpp b/cocos/2d/CCLabelTextFormatter.cpp index 956c5c3bb1..b4977c8a92 100644 --- a/cocos/2d/CCLabelTextFormatter.cpp +++ b/cocos/2d/CCLabelTextFormatter.cpp @@ -241,8 +241,6 @@ bool LabelTextFormatter::alignText(LabelTextFormatProtocol *theLabel) continue; } int index = static_cast(i + lineLength - 1 + lineNumber); - if(currentChar == 0) - index -= 1; if (index < 0) continue; LetterInfo* info = &leterInfo->at( index ); From 567455dd380420506271dc0c0fe1155ee8c82db1 Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Mon, 13 Jan 2014 21:28:42 +0900 Subject: [PATCH 03/51] convert tab to space --- cocos/2d/CCFontAtlas.cpp | 2 +- cocos/2d/CCFontDefinition.cpp | 2 +- cocos/2d/CCLabel.cpp | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cocos/2d/CCFontAtlas.cpp b/cocos/2d/CCFontAtlas.cpp index d1abc79a8d..53a07c6c8a 100644 --- a/cocos/2d/CCFontAtlas.cpp +++ b/cocos/2d/CCFontAtlas.cpp @@ -114,7 +114,7 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) std::unordered_map fontDefs; int length = cc_wcslen(utf16String); - auto yDelta = _currentPageLineHeight * 0.7; + auto yDelta = _currentPageLineHeight * 0.7; //find out new letter for (int i = 0; i < length; ++i) diff --git a/cocos/2d/CCFontDefinition.cpp b/cocos/2d/CCFontDefinition.cpp index d2c74ebf30..b3e3eae13e 100644 --- a/cocos/2d/CCFontDefinition.cpp +++ b/cocos/2d/CCFontDefinition.cpp @@ -223,7 +223,7 @@ FontAtlas * FontDefinitionTTF::createFontAtlas() { FontLetterDefinition tempDefinition = item.second; tempDefinition.offsetX = 0; - tempDefinition.offsetY += yDelta; + tempDefinition.offsetY += yDelta; tempDefinition.anchorX = 0.0f; tempDefinition.anchorY = 1.0f; retAtlas->addLetterDefinition(tempDefinition); diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index d343bcd241..ab4a612d2b 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -193,8 +193,8 @@ bool Label::setText(const std::string& stringToRender, float lineWidth, TextHAli // align text alignText(); - - updateColor(); + + updateColor(); // done here return true; @@ -441,7 +441,7 @@ bool Label::recordLetterInfo(const cocos2d::Point& point,unsigned short int theC { LetterInfo tmpInfo; - memset(&tmpInfo, 0, sizeof(tmpInfo)); + memset(&tmpInfo, 0, sizeof(tmpInfo)); _lettersInfo.push_back(tmpInfo); } @@ -459,7 +459,7 @@ bool Label::recordPlaceholderInfo(int spriteIndex) { LetterInfo tmpInfo; - memset(&tmpInfo, 0, sizeof(tmpInfo)); + memset(&tmpInfo, 0, sizeof(tmpInfo)); _lettersInfo.push_back(tmpInfo); } From 36421ca3b96b023ec5907c1ce5acca9aab81f7b0 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Thu, 23 Jan 2014 10:10:39 +0800 Subject: [PATCH 04/51] fix:Update the RELEASE_NOTES.md file --- docs/RELEASE_NOTES.md | 49 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index c9e5c61dcd..b859d35caa 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -45,11 +45,13 @@ - [`ccTypes.h`](#cctypesh) - [deprecated functions and global variables](#deprecated-functions-and--global-variables) - [Changes in the Lua bindings](#changes-in-the-lua-bindings) - - [Use bindings-generator tool for Lua binding](#use-bindings-generator-tool-for-lua-binding) + - [Use bindings-generator tool for lua binding](#use-bindings-generator-tool-for-lua-binding) + - [Bind the classes with namespace to lua](#bind-the-classes-with-namespace-to-lua) - [Use ScriptHandlerMgr to manage the register and unregister of lua function](#use-scripthandlermgr-to-manage-the-register-and-unregister-of-lua-function) - [Use "cc" and "ccs" as module name](#use-cc-and-ccs-as-module-name) - [Deprecated funtions, tables and classes](#deprecated-funtions-tables-and-classes) - [Use the lua table instead of the some structs and classes binding](#use-the-lua-table-instead-of-the-some-structs-and-classes-binding) + - [Integrate more modules into lua](#integrate-more-modules-into-lua) - [Known issues](#known-issues) # Misc Information @@ -633,9 +635,22 @@ color3B = Color3B::WHITE; ## Changes in the Lua bindings -### Use bindings-generator tool for Lua binding +### Use bindings-generator tool for lua binding -Only configurating the *.ini files in the tools/tolua folder,not to write a lot of *.pkg files +Only configurate the *.ini files in the tools/tolua folder,not to write a lot of *.pkg files + +### Bind the classes with namespace to lua +With v2.x mechanism,Bind the classes which have same name but different namespace to lua would lead to confusion,for example: +when the cocos2d::extension::ScrollView and the gui::ScrollView are bound to lua,the ScrollView metatable only represent the map of the gui::ScrollView.It will lead to unknow errors. +The main difference is as follows: + + | v2.x | v3.0 | + | tolua_usertype(tolua_S,"CCNode") | tolua_usertype(tolua_S,"cc.Node") | + | tolua_isusertable(tolua_S,1,"CCNode",0,&tolua_err | tolua_isusertable(tolua_S,1,"cc.Node",0,&tolua_err | + | tolua_isusertype(tolua_S,1,"CCNode",0,&tolua_err) | tolua_isusertype(tolua_S,1,"cc.Node",0,&tolua_err) | + | toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"CCNode") | toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"cc.Node") | + | tolua_pushusertype(tolua_S,(void*)tolua_ret,"CCFileUtils") | tolua_pushusertype(tolua_S,(void*)tolua_ret,"cc.FileUtils") | + | tolua.cast(pChildren[i + 1], "CCNode") | tolua.cast(pChildren[i + 1], "cc.Node") | ### Use ScriptHandlerMgr to manage the register and unregister of Lua function @@ -656,20 +671,24 @@ In v3.0 version, we only need to add the `HandlerType` enum in the `ScriptHandle ScriptHandlerMgr:getInstance():registerScriptHandler(menuItem, luafunction,cc.HANDLERTYPE_MENU_CLICKED) ``` -### Use "cc" and "ccs" as module name +### Use "cc"、"ccs" and "ccui" as module name ```lua // v2.x CCSprite:create(s_pPathGrossini) CCEaseIn:create(createSimpleMoveBy(), 2.5) -UILayout:create() +CCArmature:create("bear") + +ImageView:create() // v3.0 cc.Director:getInstance():getWinSize() cc.EaseIn:create(createSimpleMoveBy(), 2.5) -ccs.UILayer:create() +ccs.Armature:create("bear") + +ccui.ImageView:create() ``` ### Deprecated funtions, tables and classes @@ -705,6 +724,24 @@ local color4B = cc.c4b(0,0,0,0) Through the funtions of the LuaBasicConversion file,they can be converted the Lua table when they are as a parameter in the bindings generator. +### Integrate more modules into lua +In the version 3.0,more modules were integrated into lua,specific as follows: + +``` +1.physics +2.spine +3.XMLHttpRequest +``` +The XMLHttpRequest and physics are in the "cc" module,and the spine is in the "sp" module. +The related test cases located in: + +``` +physics ---> TestLua/PhysicsTest +spine ---> TestLua/SpineTest +XMLHttpRequest ---> TestLua/XMLHttpRequestTest +``` + + ## Known issues From 7d0f8c90dbd05b87a203a43a37fd876c6da3810f Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Thu, 23 Jan 2014 14:12:34 +0800 Subject: [PATCH 05/51] fix:Update some description --- docs/RELEASE_NOTES.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index ceb63fb599..6ac6e83c83 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -667,12 +667,11 @@ color3B = Color3B::WHITE; ### Use bindings-generator tool for lua binding -Only configurate the *.ini files in the tools/tolua folder,not to write a lot of *.pkg files +Only have to write an ini file for a module, don't have to write a lot of .pkg files ### Bind the classes with namespace to lua -With v2.x mechanism,Bind the classes which have same name but different namespace to lua would lead to confusion,for example: -when the cocos2d::extension::ScrollView and the gui::ScrollView are bound to lua,the ScrollView metatable only represent the map of the gui::ScrollView.It will lead to unknow errors. -The main difference is as follows: + +In previous, the lua binding can not bind classes that have the same class name but different namespaces. In order to resolve this issue, now the metatable name of a class is changed. For example, it will changed from CCNode to cc.Node. This modification will affect somewhere as follows: | v2.x | v3.0 | | tolua_usertype(tolua_S,"CCNode") | tolua_usertype(tolua_S,"cc.Node") | @@ -701,8 +700,13 @@ In v3.0 version, we only need to add the `HandlerType` enum in the `ScriptHandle ScriptHandlerMgr:getInstance():registerScriptHandler(menuItem, luafunction,cc.HANDLERTYPE_MENU_CLICKED) ``` -### Use "cc"、"ccs" and "ccui" as module name +### Use "cc"、"ccs"、"ccui" and "sp" as module name +The classes in the cocos2d、cocos2d::extension、CocosDenshion and cocosbuilder namespace were bound to lua in the "cc" module; +The classes in the cocos2d::gui namespace were bound to lua in the "ccui" module; +The classes in the spine namespace were bound to lua in the "sp" module; +The classes in the cocostudio namespace were bound to lua in the "ccs" module. +The main differences in the script are as follows: ```lua // v2.x CCSprite:create(s_pPathGrossini) @@ -755,7 +759,7 @@ local color4B = cc.c4b(0,0,0,0) Through the funtions of the LuaBasicConversion file,they can be converted the Lua table when they are as a parameter in the bindings generator. ### Integrate more modules into lua -In the version 3.0,more modules were integrated into lua,specific as follows: +In the version 3.0,more modules were bound to lua,specific as follows: ``` 1.physics From 45f353d65f825414bb7333df9f282c8ef90ec94a Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Thu, 23 Jan 2014 15:00:03 +0800 Subject: [PATCH 06/51] issue #3822:Update the accelerometerTest by the new event-dispatcher --- .../AccelerometerTest/AccelerometerTest.lua | 90 ++++++++++--------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/samples/Lua/TestLua/Resources/luaScript/AccelerometerTest/AccelerometerTest.lua b/samples/Lua/TestLua/Resources/luaScript/AccelerometerTest/AccelerometerTest.lua index 0aa26faf6c..76aeb3a008 100644 --- a/samples/Lua/TestLua/Resources/luaScript/AccelerometerTest/AccelerometerTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/AccelerometerTest/AccelerometerTest.lua @@ -5,54 +5,60 @@ local function AccelerometerMainLayer() end local layer = cc.Layer:create() - layer:setAccelerometerEnabled(true) + local function onEnter() + layer:setAccelerometerEnabled(true) - local label = cc.LabelTTF:create(title(), "Arial", 32) - layer:addChild(label, 1) - label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) ) + local label = cc.LabelTTF:create(title(), "Arial", 32) + layer:addChild(label, 1) + label:setPosition( cc.p(VisibleRect:center().x, VisibleRect:top().y - 50) ) - local ball = cc.Sprite:create("Images/ball.png") - ball:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y)) - layer:addChild(ball) + local ball = cc.Sprite:create("Images/ball.png") + ball:setPosition(cc.p(VisibleRect:center().x, VisibleRect:center().y)) + layer:addChild(ball) - ball:retain() - - local function didAccelerate(x,y,z,timestamp) + local function accelerometerListener(event,x,y,z,timestamp) + local target = event:getCurrentTarget() + local ballSize = target:getContentSize() + local ptNowX,ptNowY = target:getPosition() + ptNowX = ptNowX + x * 9.81 + ptNowY = ptNowY + y * 9.81 - if nil == ball then - return - end - - local director = cc.Director:getInstance() - local szBall = ball:getContentSize() - local ptNowX,ptNowY = ball:getPosition() - local ptTemp = director:convertToUI(cc.p(ptNowX,ptNowY)) - - ptTemp.x = ptTemp.x + x * 9.81 - ptTemp.y = ptTemp.y - y * 9.81 - - local ptNext = director:convertToGL(cc.p(ptTemp.x,ptTemp.y)) - - local minX = math.floor(VisibleRect:left().x + szBall.width / 2.0) - local maxX = math.floor(VisibleRect:right().x - szBall.width / 2.0) - if ptNext.x < minX then - ptNext.x = minX - elseif ptNext.x > maxX then - ptNext.x = maxX - end + local minX = math.floor(VisibleRect:left().x + ballSize.width / 2.0) + local maxX = math.floor(VisibleRect:right().x - ballSize.width / 2.0) + if ptNowX < minX then + ptNowX = minX + elseif ptNowX > maxX then + ptNowX = maxX + end - local minY = math.floor(VisibleRect:bottom().y + szBall.height / 2.0) - local maxY = math.floor(VisibleRect:top().y - szBall.height / 2.0) - if ptNext.y < minY then - ptNext.y = minY - elseif ptNext.y > maxY then - ptNext.y = maxY - end - - ball:setPosition(cc.p(ptNext.x , ptNext.y)) + local minY = math.floor(VisibleRect:bottom().y + ballSize.height / 2.0) + local maxY = math.floor(VisibleRect:top().y - ballSize.height / 2.0) + if ptNowY < minY then + ptNowY = minY + elseif ptNowY > maxY then + ptNowY = maxY + end + + target:setPosition(cc.p(ptNowX , ptNowY)) + end + + local listerner = cc.EventListenerAcceleration:create(accelerometerListener) + layer:getEventDispatcher():addEventListenerWithSceneGraphPriority(listerner,ball) end - - layer:registerScriptAccelerateHandler(didAccelerate) + + local function onExit() + layer:setAccelerometerEnabled(false) + end + + local function onNodeEvent(event) + if "enter" == event then + onEnter() + elseif "exit" == event then + onExit() + end + end + + layer:registerScriptHandler(onNodeEvent) return layer end From 4773fd093724ebf39d7d9766e45038ba5ded9fce Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Thu, 23 Jan 2014 16:20:42 +0900 Subject: [PATCH 07/51] Merge develop --- cocos/2d/CCFontDefinition.cpp | 237 -------------------------------- cocos/2d/CCLabel.cpp | 2 + cocos/2d/renderer/CCFrustum.cpp | 3 - cocos/base/CCConsole.cpp | 1 - 4 files changed, 2 insertions(+), 241 deletions(-) delete mode 100644 cocos/2d/CCFontDefinition.cpp diff --git a/cocos/2d/CCFontDefinition.cpp b/cocos/2d/CCFontDefinition.cpp deleted file mode 100644 index 59295e3549..0000000000 --- a/cocos/2d/CCFontDefinition.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/**************************************************************************** - Copyright (c) 2013 Zynga Inc. - Copyright (c) 2013-2014 Chukong Technologies Inc. - - 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. - ****************************************************************************/ - - -#include "CCFontDefinition.h" -#include "CCDirector.h" - -NS_CC_BEGIN - -const int FontDefinitionTTF::DEFAUL_ATLAS_TEXTURE_SIZE = 1024; - -FontDefinitionTTF::FontDefinitionTTF():_textImages(0), _commonLineHeight(0) -{ -} - -FontDefinitionTTF* FontDefinitionTTF::create(Font *font, int textureSize) -{ - if (textureSize == 0) - textureSize = DEFAUL_ATLAS_TEXTURE_SIZE; - - FontDefinitionTTF *ret = new FontDefinitionTTF; - - if (!ret) - return 0; - - const char *glyph = font->getCurrentGlyphCollection(); - if (!glyph) - return nullptr; - - if (ret->initDefinition(font, glyph, textureSize)) - { - ret->autorelease(); - return ret; - } - else - { - delete ret; - return 0; - } -} - -FontDefinitionTTF::~FontDefinitionTTF() -{ - if (_textImages) - { - delete _textImages; - } -} - -bool FontDefinitionTTF::prepareLetterDefinitions(TextFontPagesDef *pageDefs) -{ - // get all the pages - TextFontPagesDef *pages = pageDefs; - if (!pages) - return (false); - - float maxLineHeight = -1; - - // loops all the pages - for (int cPages = 0; cPages < pages->getNumPages(); ++cPages) - { - // loops all the lines in this page - for (int cLines = 0; cLinesgetPageAt(cPages)->getNumLines(); ++cLines) - { - float posXUV = 0.0; - float posYUV = pages->getPageAt(cPages)->getLineAt(cLines)->getY(); - - int charsCounter = 0; - - for (int c = 0; c < pages->getPageAt(cPages)->getLineAt(cLines)->getNumGlyph(); ++c) - { - // the current glyph - GlyphDef currentGlyph = pages->getPageAt(cPages)->getLineAt(cLines)->getGlyphAt(c); - - // letter width - float letterWidth = currentGlyph.getRect().size.width; - - // letter height - float letterHeight = pages->getPageAt(cPages)->getLineAt(cLines)->getHeight(); - - // add this letter definition - FontLetterDefinition tempDef; - - - // carloX little hack (this should be done outside the loop) - if (posXUV == 0.0) - posXUV = currentGlyph.getPadding(); - - tempDef.validDefinition = currentGlyph.isValid(); - - if (tempDef.validDefinition) - { - tempDef.letteCharUTF16 = currentGlyph.getUTF8Letter(); - tempDef.width = letterWidth + currentGlyph.getPadding(); - tempDef.height = (letterHeight - 1); - tempDef.U = (posXUV - 1); - tempDef.V = posYUV; - tempDef.offsetX = currentGlyph.getRect().origin.x; - tempDef.offsetY = currentGlyph.getRect().origin.y; - tempDef.textureID = cPages; - tempDef.commonLineHeight = currentGlyph.getCommonHeight(); - - // take from pixels to points - tempDef.width = tempDef.width / CC_CONTENT_SCALE_FACTOR(); - tempDef.height = tempDef.height / CC_CONTENT_SCALE_FACTOR(); - tempDef.U = tempDef.U / CC_CONTENT_SCALE_FACTOR(); - tempDef.V = tempDef.V / CC_CONTENT_SCALE_FACTOR(); - - if (tempDef.commonLineHeight>maxLineHeight) - maxLineHeight = tempDef.commonLineHeight; - } - else - { - tempDef.letteCharUTF16 = currentGlyph.getUTF8Letter(); - tempDef.commonLineHeight = 0; - tempDef.width = 0; - tempDef.height = 0; - tempDef.U = 0; - tempDef.V = 0; - tempDef.offsetX = 0; - tempDef.offsetY = 0; - tempDef.textureID = 0; - } - - - // add this definition - addLetterDefinition(tempDef); - - // move bounding box to the next letter - posXUV += letterWidth + currentGlyph.getPadding(); - - // next char in the string - ++charsCounter; - } - } - } - - // store the common line height - _commonLineHeight = maxLineHeight; - - // - return true; -} - -bool FontDefinitionTTF::initDefinition(cocos2d::Font *font, const char *letters, int textureSize) -{ - // preare texture/image stuff - _textImages = new TextImage(); - if (!_textImages) - return false; - - if (!_textImages->initWithString(letters, textureSize, textureSize, font, true)) - { - delete _textImages; - _textImages = 0; - return false; - } - - // prepare the new letter definition - return prepareLetterDefinitions(_textImages->getPages()); -} - -void FontDefinitionTTF::addLetterDefinition(const FontLetterDefinition &defToAdd) -{ - if (_fontLettersDefinitionUTF16.find(defToAdd.letteCharUTF16) == _fontLettersDefinitionUTF16.end()) - { - _fontLettersDefinitionUTF16[defToAdd.letteCharUTF16] = defToAdd; - } -} - -FontAtlas * FontDefinitionTTF::createFontAtlas() -{ - int numTextures = 0; - TextFontPagesDef *pages = _textImages->getPages(); - - if (pages) - numTextures = pages->getNumPages(); - else - return nullptr; - - if (!numTextures) - return nullptr; - - FontAtlas *retAtlas = new FontAtlas(*_textImages->getFont()); - - if (!retAtlas) - return 0; - - for (int c = 0; c < numTextures; ++c) - { - TextFontPagesDef *pPages = _textImages->getPages(); - retAtlas->addTexture(*(pPages->getPageAt(c)->getPageTexture()), c); - } - - // set the common line height - retAtlas->setCommonLineHeight(_commonLineHeight * 0.8); - auto yDelta = _commonLineHeight * 0.7; - - for( auto &item: _fontLettersDefinitionUTF16 ) - { - if ( item.second.validDefinition ) - { - FontLetterDefinition tempDefinition = item.second; - - tempDefinition.anchorX = 0.0f; - tempDefinition.anchorY = 1.0f; - retAtlas->addLetterDefinition(tempDefinition); - } - } - - // done here - return retAtlas; -} - -NS_CC_END diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index 8baa8533ec..c8ba43ba4e 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -321,6 +321,8 @@ void Label::setString(const std::string& text) // align text alignText(); + + updateColor(); } void Label::setAlignment(TextHAlignment alignment) diff --git a/cocos/2d/renderer/CCFrustum.cpp b/cocos/2d/renderer/CCFrustum.cpp index 9a12641713..4f88e2356f 100644 --- a/cocos/2d/renderer/CCFrustum.cpp +++ b/cocos/2d/renderer/CCFrustum.cpp @@ -27,9 +27,6 @@ #include -#undef far -#undef near - NS_CC_BEGIN ViewTransform::ViewTransform() diff --git a/cocos/base/CCConsole.cpp b/cocos/base/CCConsole.cpp index 6c135384b9..af1ac5da25 100644 --- a/cocos/base/CCConsole.cpp +++ b/cocos/base/CCConsole.cpp @@ -161,7 +161,6 @@ static void _log(const char *format, va_list args) OutputDebugStringA("\n"); WideCharToMultiByte(CP_ACP, 0, wszBuf, sizeof(wszBuf), buf, sizeof(buf), NULL, FALSE); printf("%s\n", buf); - #else // Linux, Mac, iOS, etc fprintf(stdout, "cocos2d: %s", buf); From d0319fea2cdc3c7c67ce5baa0d31e4c057bb2832 Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Thu, 23 Jan 2014 16:43:52 +0900 Subject: [PATCH 08/51] Syncing develop --- cocos/base/CCConsole.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cocos/base/CCConsole.cpp b/cocos/base/CCConsole.cpp index af1ac5da25..eea6c483c8 100644 --- a/cocos/base/CCConsole.cpp +++ b/cocos/base/CCConsole.cpp @@ -159,8 +159,10 @@ static void _log(const char *format, va_list args) MultiByteToWideChar(CP_UTF8, 0, buf, -1, wszBuf, sizeof(wszBuf)); OutputDebugStringW(wszBuf); OutputDebugStringA("\n"); + WideCharToMultiByte(CP_ACP, 0, wszBuf, sizeof(wszBuf), buf, sizeof(buf), NULL, FALSE); printf("%s\n", buf); + #else // Linux, Mac, iOS, etc fprintf(stdout, "cocos2d: %s", buf); From 44b2d5d3b8393b7d914c4fbae740914342b6c2a2 Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Thu, 23 Jan 2014 17:16:30 +0900 Subject: [PATCH 09/51] Old / New label test --- .../Classes/LabelTest/LabelTestNew.cpp | 31 ++++++++++++++++++- .../TestCpp/Classes/LabelTest/LabelTestNew.h | 11 +++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp index a3dff56208..f7d4f658c0 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp @@ -68,7 +68,8 @@ static std::function createFunctions[] = CL(LabelTTFDistanceField), CL(LabelTTFDistanceFieldEffect), CL(LabelCharMapTest), - CL(LabelCrashTest) + CL(LabelCrashTest), + CL(LabelTTFOldNew) }; #define MAX_LAYER (sizeof(createFunctions) / sizeof(createFunctions[0])) @@ -1312,3 +1313,31 @@ std::string LabelCrashTest::subtitle() const { return "Not crash and show [Test123] when using unknown character."; } + +LabelTTFOldNew::LabelTTFOldNew() +{ + auto s = Director::getInstance()->getWinSize(); + float delta = s.height/4; + + auto label1 = CCLabelTTF::create("Cocos2d-x Old", "arial", 24); + addChild(label1, 0, kTagBitmapAtlas1); + label1->setAnchorPoint(CCPoint(0.5f, 0.5f)); + label1->setPosition(CCPoint(s.width/2, delta * 2)); + label1->setColor(Color3B::RED); + + TTFConfig ttfConfig("fonts/arial.ttf", 48); + auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Old"); + addChild(label2, 0, kTagBitmapAtlas2); + label2->setAnchorPoint(CCPoint(0.5f, 0.5f)); + label2->setPosition(CCPoint(s.width/2, delta * 2)); +} + +std::string LabelTTFOldNew::title() const +{ + return "New / Old TTF"; +} + +std::string LabelTTFOldNew::subtitle() const +{ + return "Comparison between old(red) and new(white) TTF label"; +} diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h index 45d9374d4c..bcac07c6d8 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h @@ -374,6 +374,17 @@ public: virtual std::string subtitle() const override; }; +class LabelTTFOldNew : public AtlasDemoNew +{ +public: + CREATE_FUNC(LabelTTFOldNew); + + LabelTTFOldNew(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; +}; + // we don't support linebreak mode #endif From a91d9161c753b7169bdda5736b21fad9178c1af0 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Thu, 23 Jan 2014 16:17:24 +0800 Subject: [PATCH 10/51] issue #3822:Update the KeypadTest using the new event-dispatcher --- .../scripting/lua/script/Cocos2dConstants.lua | 162 ++++++++++++++++++ .../luaScript/KeypadTest/KeypadTest.lua | 59 ++++--- 2 files changed, 197 insertions(+), 24 deletions(-) diff --git a/cocos/scripting/lua/script/Cocos2dConstants.lua b/cocos/scripting/lua/script/Cocos2dConstants.lua index 2bcb461d27..11c57e14b2 100644 --- a/cocos/scripting/lua/script/Cocos2dConstants.lua +++ b/cocos/scripting/lua/script/Cocos2dConstants.lua @@ -367,3 +367,165 @@ cc.LabelEffect = GLOW = 3, } +cc.KeyCode = +{ + KEY_NONE = 0, + KEY_PAUSE = 0x0013, + KEY_SCROLL_LOCK = 0x1014, + KEY_PRINT = 0x1061, + KEY_SYSREQ = 0x106A, + KEY_BREAK = 0x106B, + KEY_ESCAPE = 0x001B, + KEY_BACKSPACE = 0x0008, + KEY_TAB = 0x0009, + KEY_BACK_TAB = 0x0089, + KEY_RETURN = 0x000D, + KEY_CAPS_LOCK = 0x00E5, + KEY_SHIFT = 0x00E1, + KEY_CTRL = 0x00E3, + KEY_ALT = 0x00E9, + KEY_MENU = 0x1067, + KEY_HYPER = 0x10ED, + KEY_INSERT = 0x1063, + KEY_HOME = 0x1050, + KEY_PG_UP = 0x1055, + KEY_DELETE = 0x10FF, + KEY_END = 0x1057, + KEY_PG_DOWN = 0x1056, + KEY_LEFT_ARROW = 0x1051, + KEY_RIGHT_ARROW = 0x1053, + KEY_UP_ARROW = 0x1052, + KEY_DOWN_ARROW = 0x1054, + KEY_NUM_LOCK = 0x107F, + KEY_KP_PLUS = 0x10AB, + KEY_KP_MINUS = 0x10AD, + KEY_KP_MULTIPLY = 0x10AA, + KEY_KP_DIVIDE = 0x10AF, + KEY_KP_ENTER = 0x108D, + KEY_KP_HOME = 0x10B7, + KEY_KP_UP = 0x10B8, + KEY_KP_PG_UP = 0x10B9, + KEY_KP_LEFT = 0x10B4, + KEY_KP_FIVE = 0x10B5, + KEY_KP_RIGHT = 0x10B6, + KEY_KP_END = 0x10B1, + KEY_KP_DOWN = 0x10B2, + KEY_KP_PG_DOWN = 0x10B3, + KEY_KP_INSERT = 0x10B0, + KEY_KP_DELETE = 0x10AE, + KEY_F1 = 0x00BE, + KEY_F2 = 0x00BF, + KEY_F3 = 0x00C0, + KEY_F4 = 0x00C1, + KEY_F5 = 0x00C2, + KEY_F6 = 0x00C3, + KEY_F7 = 0x00C4, + KEY_F8 = 0x00C5, + KEY_F9 = 0x00C6, + KEY_F10 = 0x00C7, + KEY_F11 = 0x00C8, + KEY_F12 = 0x00C9, + KEY_SPACE = ' ', + KEY_EXCLAM = '!', + KEY_QUOTE = '"', + KEY_NUMBER = '#', + KEY_DOLLAR = '$', + KEY_PERCENT = '%', + KEY_CIRCUMFLEX = '^', + KEY_AMPERSAND = '&', + KEY_APOSTROPHE = '\'', + KEY_LEFT_PARENTHESIS = '(', + KEY_RIGHT_PARENTHESIS = ')', + KEY_ASTERISK = '*', + KEY_PLUS = '+', + KEY_COMMA = ',', + KEY_MINUS = '-', + KEY_PERIOD = '.', + KEY_SLASH = '/', + KEY_0 = '0', + KEY_1 = '1', + KEY_2 = '2', + KEY_3 = '3', + KEY_4 = '4', + KEY_5 = '5', + KEY_6 = '6', + KEY_7 = '7', + KEY_8 = '8', + KEY_9 = '9', + KEY_COLON = ':', + KEY_SEMICOLON = ';', + KEY_LESS_THAN = '<', + KEY_EQUAL = '=', + KEY_GREATER_THAN = '>', + KEY_QUESTION = '?', + KEY_AT = '@', + KEY_CAPITAL_A = 'A', + KEY_CAPITAL_B = 'B', + KEY_CAPITAL_C = 'C', + KEY_CAPITAL_D = 'D', + KEY_CAPITAL_E = 'E', + KEY_CAPITAL_F = 'F', + KEY_CAPITAL_G = 'G', + KEY_CAPITAL_H = 'H', + KEY_CAPITAL_I = 'I', + KEY_CAPITAL_J = 'J', + KEY_CAPITAL_K = 'K', + KEY_CAPITAL_L = 'L', + KEY_CAPITAL_M = 'M', + KEY_CAPITAL_N = 'N', + KEY_CAPITAL_O = 'O', + KEY_CAPITAL_P = 'P', + KEY_CAPITAL_Q = 'Q', + KEY_CAPITAL_R = 'R', + KEY_CAPITAL_S = 'S', + KEY_CAPITAL_T = 'T', + KEY_CAPITAL_U = 'U', + KEY_CAPITAL_V = 'V', + KEY_CAPITAL_W = 'W', + KEY_CAPITAL_X = 'X', + KEY_CAPITAL_Y = 'Y', + KEY_CAPITAL_Z = 'Z', + KEY_LEFT_BRACKET = '[', + KEY_BACK_SLASH = '\\', + KEY_RIGHT_BRACKET = ']', + KEY_UNDERSCORE = '_', + KEY_GRAVE = '`', + KEY_A = 'a', + KEY_B = 'b', + KEY_C = 'c', + KEY_D = 'd', + KEY_E = 'e', + KEY_F = 'f', + KEY_G = 'g', + KEY_H = 'h', + KEY_I = 'i', + KEY_J = 'j', + KEY_K = 'k', + KEY_L = 'l', + KEY_M = 'm', + KEY_N = 'n', + KEY_O = 'o', + KEY_P = 'p', + KEY_Q = 'q', + KEY_R = 'r', + KEY_S = 's', + KEY_T = 't', + KEY_U = 'u', + KEY_V = 'v', + KEY_W = 'w', + KEY_X = 'x', + KEY_Y = 'y', + KEY_Z = 'z', + KEY_LEFT_BRACE = '{', + KEY_BAR = '|', + KEY_RIGHT_BRACE = '}', + KEY_TILDE = '~', + KEY_EURO = 0x20AC, + KEY_POUND = 0x00A3, + KEY_YEN = 0x00A5, + KEY_MIDDLE_DOT = 0x0095, + KEY_SEARCH = 0xFFAA, +}; + + + diff --git a/samples/Lua/TestLua/Resources/luaScript/KeypadTest/KeypadTest.lua b/samples/Lua/TestLua/Resources/luaScript/KeypadTest/KeypadTest.lua index 9771efe28e..850a908225 100644 --- a/samples/Lua/TestLua/Resources/luaScript/KeypadTest/KeypadTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/KeypadTest/KeypadTest.lua @@ -1,31 +1,42 @@ local function KeypadMainLayer() - local pLayer = cc.Layer:create() - - local s = cc.Director:getInstance():getWinSize() - local label = cc.LabelTTF:create("Keypad Test", "Arial", 28) - pLayer:addChild(label, 0) - label:setPosition( cc.p(s.width/2, s.height-50) ) + local layer = cc.Layer:create() - pLayer:setKeypadEnabled(true) + local function onEnter() + print("come in") + local s = cc.Director:getInstance():getWinSize() + local label = cc.LabelTTF:create("Keypad Test", "Arial", 28) + layer:addChild(label, 0) + label:setPosition(cc.p(s.width/2, s.height-50)) - -- create a label to display the tip string - local pLabelTip = cc.LabelTTF:create("Please press any key...", "Arial", 22) - pLabelTip:setPosition(cc.p(s.width / 2, s.height / 2)) - pLayer:addChild(pLabelTip, 0) - - pLabelTip:retain() - - local function KeypadHandler(strEvent) - if "backClicked" == strEvent then - pLabelTip:setString("BACK clicked!"); - elseif "menuClicked" == strEvent then - pLabelTip:setString("MENU clicked!"); - end + local labelTip = cc.LabelTTF:create("Please press any key...", "Arial", 22) + labelTip:setPosition(cc.p(s.width / 2, s.height / 2)) + layer:addChild(labelTip, 0) + + local function onKeyReleased(keyCode, event) + local label = event:getCurrentTarget() + if keyCode == cc.KeyCode.KEY_BACKSPACE then + label:setString("BACK clicked!") + elseif keyCode == cc.KeyCode.KEY_MENU then + label:setString("MENU clicked!") + end + end + + local listener = cc.EventListenerKeyboard:create() + listener:registerScriptHandler(onKeyReleased, cc.Handler.EVENT_KEYBOARD_RELEASED ) + + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, labelTip) end - - pLayer:registerScriptKeypadHandler(KeypadHandler) - - return pLayer + + local function onNodeEvent(event) + if event == "enter" then + onEnter() + end + end + + layer:registerScriptHandler(onNodeEvent) + + return layer end From c042c5f3dbedf11250276ce4f07d9f06c9f7c0b4 Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Thu, 23 Jan 2014 17:27:28 +0900 Subject: [PATCH 11/51] updateColor should be called after updating quads on alignText --- cocos/2d/CCLabel.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index c8ba43ba4e..42bf573cca 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -33,6 +33,7 @@ #include "CCDirector.h" #include "renderer/CCRenderer.h" #include "CCFont.h" +#include "CCDrawingPrimitives.h" #define DISTANCEFIELD_ATLAS_FONTSIZE 50 @@ -321,8 +322,6 @@ void Label::setString(const std::string& text) // align text alignText(); - - updateColor(); } void Label::setAlignment(TextHAlignment alignment) @@ -473,6 +472,8 @@ void Label::alignText() insertQuadFromSprite(_reusedLetter,vaildIndex++); } } + + updateColor(); } bool Label::computeHorizontalKernings(unsigned short int *stringToRender) From d62f7118841984320106c5ed69132b6ff9af8ebb Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Thu, 23 Jan 2014 17:27:50 +0900 Subject: [PATCH 12/51] New and old label comparison --- .../Classes/LabelTest/LabelTestNew.cpp | 36 +++++++++++++++++-- .../TestCpp/Classes/LabelTest/LabelTestNew.h | 5 +++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp index f7d4f658c0..99edc1525d 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp @@ -1319,19 +1319,51 @@ LabelTTFOldNew::LabelTTFOldNew() auto s = Director::getInstance()->getWinSize(); float delta = s.height/4; - auto label1 = CCLabelTTF::create("Cocos2d-x Old", "arial", 24); + auto label1 = CCLabelTTF::create("Cocos2d-x Label Test", "arial", 24); addChild(label1, 0, kTagBitmapAtlas1); label1->setAnchorPoint(CCPoint(0.5f, 0.5f)); label1->setPosition(CCPoint(s.width/2, delta * 2)); label1->setColor(Color3B::RED); TTFConfig ttfConfig("fonts/arial.ttf", 48); - auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Old"); + auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test"); addChild(label2, 0, kTagBitmapAtlas2); label2->setAnchorPoint(CCPoint(0.5f, 0.5f)); label2->setPosition(CCPoint(s.width/2, delta * 2)); } +void LabelTTFOldNew::onDraw() +{ + kmMat4 oldMat; + kmGLGetMatrix(KM_GL_MODELVIEW, &oldMat); + kmGLLoadMatrix(&_modelViewTransform); + + auto label1 = (Label*)getChildByTag(kTagBitmapAtlas2); + auto labelSize = label1->getContentSize(); + auto origin = Director::getInstance()->getWinSize(); + + origin.width = origin.width / 2 - (labelSize.width / 2); + origin.height = origin.height / 2 - (labelSize.height / 2); + + Point vertices[4]= + { + Point(origin.width, origin.height), + Point(labelSize.width + origin.width, origin.height), + Point(labelSize.width + origin.width, labelSize.height + origin.height), + Point(origin.width, labelSize.height + origin.height) + }; + DrawPrimitives::drawPoly(vertices, 4, true); + + kmGLLoadMatrix(&oldMat); +} + +void LabelTTFOldNew::draw() +{ + _renderCmd.init(_globalZOrder); + _renderCmd.func = CC_CALLBACK_0(LabelTTFOldNew::onDraw, this); + Director::getInstance()->getRenderer()->addCommand(&_renderCmd); +} + std::string LabelTTFOldNew::title() const { return "New / Old TTF"; diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h index bcac07c6d8..ccd52f8d07 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h @@ -381,8 +381,13 @@ public: LabelTTFOldNew(); + virtual void draw() override; + virtual std::string title() const override; virtual std::string subtitle() const override; +protected: + CustomCommand _renderCmd; + void onDraw(); }; // we don't support linebreak mode From 977c84392c9a115754bbab7a14a65a4062db9faf Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Thu, 23 Jan 2014 18:11:40 +0900 Subject: [PATCH 13/51] Tab to space --- samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp index 99edc1525d..35adcbab41 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp @@ -1317,16 +1317,16 @@ std::string LabelCrashTest::subtitle() const LabelTTFOldNew::LabelTTFOldNew() { auto s = Director::getInstance()->getWinSize(); - float delta = s.height/4; + float delta = s.height/4; - auto label1 = CCLabelTTF::create("Cocos2d-x Label Test", "arial", 24); - addChild(label1, 0, kTagBitmapAtlas1); + auto label1 = CCLabelTTF::create("Cocos2d-x Label Test", "arial", 24); + addChild(label1, 0, kTagBitmapAtlas1); label1->setAnchorPoint(CCPoint(0.5f, 0.5f)); label1->setPosition(CCPoint(s.width/2, delta * 2)); - label1->setColor(Color3B::RED); + label1->setColor(Color3B::RED); TTFConfig ttfConfig("fonts/arial.ttf", 48); - auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test"); + auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test"); addChild(label2, 0, kTagBitmapAtlas2); label2->setAnchorPoint(CCPoint(0.5f, 0.5f)); label2->setPosition(CCPoint(s.width/2, delta * 2)); From 1a34a6ff8484f8f2a904a6cf76a88f7377be2710 Mon Sep 17 00:00:00 2001 From: Hanju Kim Date: Thu, 23 Jan 2014 18:55:51 +0900 Subject: [PATCH 14/51] remove unused header remove CC Prefix --- cocos/2d/CCLabel.cpp | 1 - samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cocos/2d/CCLabel.cpp b/cocos/2d/CCLabel.cpp index 42bf573cca..6628006565 100644 --- a/cocos/2d/CCLabel.cpp +++ b/cocos/2d/CCLabel.cpp @@ -33,7 +33,6 @@ #include "CCDirector.h" #include "renderer/CCRenderer.h" #include "CCFont.h" -#include "CCDrawingPrimitives.h" #define DISTANCEFIELD_ATLAS_FONTSIZE 50 diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp index 35adcbab41..432fb99cd1 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp @@ -1319,17 +1319,17 @@ LabelTTFOldNew::LabelTTFOldNew() auto s = Director::getInstance()->getWinSize(); float delta = s.height/4; - auto label1 = CCLabelTTF::create("Cocos2d-x Label Test", "arial", 24); + auto label1 = LabelTTF::create("Cocos2d-x Label Test", "arial", 24); addChild(label1, 0, kTagBitmapAtlas1); - label1->setAnchorPoint(CCPoint(0.5f, 0.5f)); - label1->setPosition(CCPoint(s.width/2, delta * 2)); + label1->setAnchorPoint(Point(0.5f, 0.5f)); + label1->setPosition(Point(s.width/2, delta * 2)); label1->setColor(Color3B::RED); TTFConfig ttfConfig("fonts/arial.ttf", 48); auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test"); addChild(label2, 0, kTagBitmapAtlas2); - label2->setAnchorPoint(CCPoint(0.5f, 0.5f)); - label2->setPosition(CCPoint(s.width/2, delta * 2)); + label2->setAnchorPoint(Point(0.5f, 0.5f)); + label2->setPosition(Point(s.width/2, delta * 2)); } void LabelTTFOldNew::onDraw() From 402d0cf7b13b89156f1123ed849791a822641f58 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Thu, 23 Jan 2014 22:26:14 +0800 Subject: [PATCH 15/51] issue #3822:Update the test cases which are related with touch using the `EventListenerTouchAllAtOnce` or `EventListenerTouchOneByOne` --- .../lua/bindings/LuaBasicConversions.cpp | 2 +- .../lua/bindings/LuaBasicConversions.h | 2 +- .../Resources/luaScript/BugsTest/BugsTest.lua | 300 +++++++++--------- .../ClickAndMoveTest/ClickAndMoveTest.lua | 30 +- .../CocoStudioArmatureTest.lua | 67 ++-- .../CocosDenshionTest/CocosDenshionTest.lua | 42 ++- .../luaScript/ExtensionTest/ExtensionTest.lua | 30 +- .../luaScript/LabelTest/LabelTest.lua | 70 ++-- .../luaScript/LabelTestNew/LabelTestNew.lua | 73 +++-- .../luaScript/LayerTest/LayerTest.lua | 55 ++-- .../Resources/luaScript/MenuTest/MenuTest.lua | 42 ++- .../MotionStreakTest/MotionStreakTest.lua | 25 +- .../Resources/luaScript/NodeTest/NodeTest.lua | 32 +- .../luaScript/ParallaxTest/ParallaxTest.lua | 29 +- .../luaScript/ParticleTest/ParticleTest.lua | 42 +-- .../PerformanceTest/PerformanceTest.lua | 90 +++--- .../RenderTextureTest/RenderTextureTest.lua | 105 +++--- .../luaScript/SpriteTest/SpriteTest.lua | 33 +- .../luaScript/TileMapTest/TileMapTest.lua | 30 +- .../TestLua/Resources/luaScript/mainMenu.lua | 26 +- 20 files changed, 559 insertions(+), 566 deletions(-) diff --git a/cocos/scripting/lua/bindings/LuaBasicConversions.cpp b/cocos/scripting/lua/bindings/LuaBasicConversions.cpp index ed8178972e..e03163e0d6 100644 --- a/cocos/scripting/lua/bindings/LuaBasicConversions.cpp +++ b/cocos/scripting/lua/bindings/LuaBasicConversions.cpp @@ -1071,7 +1071,7 @@ bool luavals_variadic_to_array(lua_State* L,int argc, Array** ret) else if (lua_isuserdata(L, i + 2)) { tolua_Error err; - if (!tolua_isusertype(L, i + 2, "Object", 0, &err)) + if (!tolua_isusertype(L, i + 2, "cc.Object", 0, &err)) { #if COCOS2D_DEBUG >=1 luaval_to_native_err(L,"#ferror:",&err); diff --git a/cocos/scripting/lua/bindings/LuaBasicConversions.h b/cocos/scripting/lua/bindings/LuaBasicConversions.h index 9dcc2fc6e2..5d485daff0 100644 --- a/cocos/scripting/lua/bindings/LuaBasicConversions.h +++ b/cocos/scripting/lua/bindings/LuaBasicConversions.h @@ -88,7 +88,7 @@ bool luavals_variadic_to_ccvector( lua_State* L, int argc, cocos2d::Vector* r { tolua_Error err; //Undo check - if (!tolua_isusertype(L, i + 2, "Object", 0, &err)) + if (!tolua_isusertype(L, i + 2, "cc.Object", 0, &err)) { ok = false; break; diff --git a/samples/Lua/TestLua/Resources/luaScript/BugsTest/BugsTest.lua b/samples/Lua/TestLua/Resources/luaScript/BugsTest/BugsTest.lua index 487b2fec70..822f7be3ad 100644 --- a/samples/Lua/TestLua/Resources/luaScript/BugsTest/BugsTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/BugsTest/BugsTest.lua @@ -1,8 +1,8 @@ -local MAX_COUNT = 9; -local LINE_SPACE = 40; -local kItemTagBasic = 5432; +local MAX_COUNT = 9 +local LINE_SPACE = 40 +local kItemTagBasic = 5432 -local Winsize = cc.Director:getInstance():getWinSize(); +local Winsize = cc.Director:getInstance():getWinSize() local testNames = { "Bug-350", @@ -18,8 +18,8 @@ local testNames = { local function CreateBugsTestBackMenuItem(pLayer) cc.MenuItemFont:setFontName("Arial") - cc.MenuItemFont:setFontSize(24); - local pMenuItemFont = cc.MenuItemFont:create("Back"); + cc.MenuItemFont:setFontSize(24) + local pMenuItemFont = cc.MenuItemFont:create("Back") pMenuItemFont:setPosition(cc.p(VisibleRect:rightBottom().x - 50, VisibleRect:rightBottom().y + 25)) local function menuCallback() local pScene = BugsTestMain() @@ -37,9 +37,9 @@ end --BugTest350 local function BugTest350() local pLayer = cc.Layer:create() - local pBackground = cc.Sprite:create("Hello.png"); - pBackground:setPosition(cc.p(Winsize.width/2, Winsize.height/2)); - pLayer:addChild(pBackground); + local pBackground = cc.Sprite:create("Hello.png") + pBackground:setPosition(cc.p(Winsize.width/2, Winsize.height/2)) + pLayer:addChild(pBackground) return pLayer end @@ -55,7 +55,7 @@ local function BugTest422() print(strLog) end - pResetLayer:removeChild(pNode, false); + pResetLayer:removeChild(pNode, false) local function menuCallback(tag,pMenuItem) if nil ~= pMenuItem then @@ -64,7 +64,7 @@ local function BugTest422() end end cc.MenuItemFont:setFontName("Arial") - cc.MenuItemFont:setFontSize(24); + cc.MenuItemFont:setFontSize(24) local pMenuItem1 = cc.MenuItemFont:create("One") pMenuItem1:registerScriptTapHandler(menuCallback) local pMenuItem2 = cc.MenuItemFont:create("Two") @@ -90,15 +90,15 @@ local function BugTest458() local function InitQuestionContainerSprite(pSprite) --Add label - local pLabel = cc.LabelTTF:create("Answer 1", "Arial", 12); - pLabel:setTag(100); + local pLabel = cc.LabelTTF:create("Answer 1", "Arial", 12) + pLabel:setTag(100) --Add the background - local pCorner = cc.Sprite:create("Images/bugs/corner.png"); - local nWidth = Winsize.width * 0.9 - (pCorner:getContentSize().width * 2); - local nHeight = Winsize.height * 0.15 - (pCorner:getContentSize().height * 2); - local pColorLayer = cc.LayerColor:create(cc.c4b(255, 255, 255, 255 * .75), nWidth, nHeight); - pColorLayer:setPosition(cc.p(-nWidth / 2, -nHeight / 2)); + local pCorner = cc.Sprite:create("Images/bugs/corner.png") + local nWidth = Winsize.width * 0.9 - (pCorner:getContentSize().width * 2) + local nHeight = Winsize.height * 0.15 - (pCorner:getContentSize().height * 2) + local pColorLayer = cc.LayerColor:create(cc.c4b(255, 255, 255, 255 * .75), nWidth, nHeight) + pColorLayer:setPosition(cc.p(-nWidth / 2, -nHeight / 2)) --First button is blue,Second is red,Used for testing - change later if (0 == nColorFlag) then pLabel:setColor(cc.c3b(0,0,255)) @@ -106,53 +106,53 @@ local function BugTest458() print("Color changed") pLabel:setColor(cc.c3b(255,0,0)) end - nColorFlag = nColorFlag + 1; - pSprite:addChild(pColorLayer); + nColorFlag = nColorFlag + 1 + pSprite:addChild(pColorLayer) - pCorner:setPosition(cc.p(-(nWidth / 2 + pCorner:getContentSize().width / 2), -(nHeight / 2 + pCorner:getContentSize().height / 2))); - pSprite:addChild(pCorner); + pCorner:setPosition(cc.p(-(nWidth / 2 + pCorner:getContentSize().width / 2), -(nHeight / 2 + pCorner:getContentSize().height / 2))) + pSprite:addChild(pCorner) local nX,nY = pCorner:getPosition() - local pCorner2 = cc.Sprite:create("Images/bugs/corner.png"); - pCorner2:setPosition(cc.p(-nX, nY)); - pCorner2:setFlipX(true); - pSprite:addChild(pCorner2); + local pCorner2 = cc.Sprite:create("Images/bugs/corner.png") + pCorner2:setPosition(cc.p(-nX, nY)) + pCorner2:setFlipX(true) + pSprite:addChild(pCorner2) - local pCorner3 = cc.Sprite:create("Images/bugs/corner.png"); - pCorner3:setPosition(cc.p(nX, -nY)); - pCorner3:setFlipY(true); - pSprite:addChild(pCorner3); + local pCorner3 = cc.Sprite:create("Images/bugs/corner.png") + pCorner3:setPosition(cc.p(nX, -nY)) + pCorner3:setFlipY(true) + pSprite:addChild(pCorner3) - local pCorner4 = cc.Sprite:create("Images/bugs/corner.png"); - pCorner4:setPosition(cc.p(-nX, -nY)); - pCorner4:setFlipX(true); - pCorner4:setFlipY(true); - pSprite:addChild(pCorner4); + local pCorner4 = cc.Sprite:create("Images/bugs/corner.png") + pCorner4:setPosition(cc.p(-nX, -nY)) + pCorner4:setFlipX(true) + pCorner4:setFlipY(true) + pSprite:addChild(pCorner4) - local pEdge = cc.Sprite:create("Images/bugs/edge.png"); - pEdge:setScaleX(nWidth); - pEdge:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), nY)); - pSprite:addChild(pEdge); + local pEdge = cc.Sprite:create("Images/bugs/edge.png") + pEdge:setScaleX(nWidth) + pEdge:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), nY)) + pSprite:addChild(pEdge) - local pEdge2 = cc.Sprite:create("Images/bugs/edge.png"); - pEdge2:setScaleX(nWidth); - pEdge2:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), -nY)); - pEdge2:setFlipY(true); - pSprite:addChild(pEdge2); + local pEdge2 = cc.Sprite:create("Images/bugs/edge.png") + pEdge2:setScaleX(nWidth) + pEdge2:setPosition(cc.p(nX + (pCorner:getContentSize().width / 2) + (nWidth / 2), -nY)) + pEdge2:setFlipY(true) + pSprite:addChild(pEdge2) - local pEdge3 = cc.Sprite:create("Images/bugs/edge.png"); - pEdge3:setRotation(90); - pEdge3:setScaleX(nHeight); - pEdge3:setPosition(cc.p(nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2))); - pSprite:addChild(pEdge3); + local pEdge3 = cc.Sprite:create("Images/bugs/edge.png") + pEdge3:setRotation(90) + pEdge3:setScaleX(nHeight) + pEdge3:setPosition(cc.p(nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2))) + pSprite:addChild(pEdge3) - local pEdge4 = cc.Sprite:create("Images/bugs/edge.png"); - pEdge4:setRotation(270); - pEdge4:setScaleX(nHeight); - pEdge4:setPosition(cc.p(-nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2))); - pSprite:addChild(pEdge4); + local pEdge4 = cc.Sprite:create("Images/bugs/edge.png") + pEdge4:setRotation(270) + pEdge4:setScaleX(nHeight) + pEdge4:setPosition(cc.p(-nX, nY + (pCorner:getContentSize().height / 2) + (nHeight / 2))) + pSprite:addChild(pEdge4) - pSprite:addChild(pLabel); + pSprite:addChild(pLabel) end local pQuestion1 = cc.Sprite:create() @@ -165,19 +165,19 @@ local function BugTest458() end local pMenuItemSprite = cc.MenuItemSprite:create(pQuestion1,pQuestion2) pMenuItemSprite:registerScriptTapHandler(menuCallback) - local pLayerColor1 = cc.LayerColor:create(cc.c4b(0,0,255,255), 100, 100); --- question->release(); --- question2->release(); + local pLayerColor1 = cc.LayerColor:create(cc.c4b(0,0,255,255), 100, 100) +-- question->release() +-- question2->release() - local pLayerColor2 = cc.LayerColor:create(cc.c4b(255,0,0,255), 100, 100); - local pMenuItemSprite2 = cc.MenuItemSprite:create(pLayerColor1, pLayerColor2); + local pLayerColor2 = cc.LayerColor:create(cc.c4b(255,0,0,255), 100, 100) + local pMenuItemSprite2 = cc.MenuItemSprite:create(pLayerColor1, pLayerColor2) pMenuItemSprite2:registerScriptTapHandler(menuCallback) local pMenu = cc.Menu:create(pMenuItemSprite, pMenuItemSprite2) - pMenu:alignItemsVerticallyWithPadding(100); - pMenu:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2)); + pMenu:alignItemsVerticallyWithPadding(100) + pMenu:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2)) -- add the label as a child to this Layer - pLayer:addChild(pMenu); + pLayer:addChild(pMenu) return pLayer end @@ -189,21 +189,21 @@ local BugTest624_2_entry = nil local function BugTest624() local pLayer = cc.Layer:create() - local pLabel = cc.LabelTTF:create("Layer1", "Marker Felt", 36); - pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2)); - pLayer:addChild(pLabel); - pLayer:setAccelerometerEnabled(true); --- schedule(schedule_selector(Bug624Layer::switchLayer), 5.0f); + local pLabel = cc.LabelTTF:create("Layer1", "Marker Felt", 36) + pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2)) + pLayer:addChild(pLabel) + pLayer:setAccelerometerEnabled(true) +-- schedule(schedule_selector(Bug624Layer::switchLayer), 5.0f) local function BugTest624_SwitchLayer() local scheduler = cc.Director:getInstance():getScheduler() scheduler:unscheduleScriptEntry(BugTest624_entry) - local pScene = cc.Scene:create(); + local pScene = cc.Scene:create() local pNewPlayer = BugTest624_2() CreateBugsTestBackMenuItem(pNewPlayer) - pScene:addChild(pNewPlayer); - cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,255,255))); + pScene:addChild(pNewPlayer) + cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,255,255))) end @@ -228,20 +228,20 @@ end function BugTest624_2() local pLayer = cc.Layer:create() - local pLabel = cc.LabelTTF:create("Layer2", "Marker Felt", 36); - pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2)); - pLayer:addChild(pLabel); - pLayer:setAccelerometerEnabled(true); + local pLabel = cc.LabelTTF:create("Layer2", "Marker Felt", 36) + pLabel:setPosition(cc.p(Winsize.width / 2, Winsize.height / 2)) + pLayer:addChild(pLabel) + pLayer:setAccelerometerEnabled(true) local function BugTest624_2_SwitchLayer() local scheduler = cc.Director:getInstance():getScheduler() scheduler:unscheduleScriptEntry(BugTest624_2_entry) - local pScene = cc.Scene:create(); + local pScene = cc.Scene:create() local pNewPlayer = BugTest624() CreateBugsTestBackMenuItem(pNewPlayer) - pScene:addChild(pNewPlayer); - cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,0,0))); + pScene:addChild(pNewPlayer) + cc.Director:getInstance():replaceScene(cc.TransitionFade:create(2.0, pScene, cc.c3b(255,0,0))) end local function BugTest624_2_OnEnterOrExit(tag) @@ -294,65 +294,58 @@ end --BugTest914 local function BugTest914() - local pLayer = cc.Layer:create() + local layer = cc.Layer:create() - pLayer:setTouchEnabled(true); - - local pLayerColor = nil + local layerColor = nil for i = 0, 4 do - pLayerColor = cc.LayerColor:create(cc.c4b(i*20, i*20, i*20,255)) - pLayerColor:setContentSize(cc.size(i*100, i*100)); - pLayerColor:setPosition(cc.p(Winsize.width/2, Winsize.height/2)) - pLayerColor:setAnchorPoint(cc.p(0.5, 0.5)); - pLayerColor:ignoreAnchorPointForPosition(false); - pLayer:addChild(pLayerColor, -1-i); + layerColor = cc.LayerColor:create(cc.c4b(i*20, i*20, i*20,255)) + layerColor:setContentSize(cc.size(i*100, i*100)) + layerColor:setPosition(cc.p(Winsize.width/2, Winsize.height/2)) + layerColor:setAnchorPoint(cc.p(0.5, 0.5)) + layerColor:ignoreAnchorPointForPosition(false) + layer:addChild(layerColor, -1-i) end --create and initialize a Label local function restart() - local pScene = cc.Scene:create() - local pLayer = BugTest914() - CreateBugsTestBackMenuItem(pLayer) - pScene:addChild(pLayer); - cc.Director:getInstance():replaceScene(pScene) + local scene = cc.Scene:create() + local newLayer = BugTest914() + CreateBugsTestBackMenuItem(newLayer) + scene:addChild(newLayer) + cc.Director:getInstance():replaceScene(scene) end local label = cc.LabelTTF:create("Hello World", "Marker Felt", 64) --position the label on the center of the screen - label:setPosition(cc.p( Winsize.width /2 , Winsize.height/2 )); - pLayer:addChild(label); + label:setPosition(cc.p( Winsize.width /2 , Winsize.height/2 )) + layer:addChild(label) local item1 = cc.MenuItemFont:create("restart") item1:registerScriptTapHandler(restart) - --Bug914Layer::restart)); local menu = cc.Menu:create() menu:addChild(item1) menu:alignItemsVertically() menu:setPosition(cc.p(Winsize.width/2, 100)) - pLayer:addChild(menu) + layer:addChild(menu) -- handling touch events - local function onTouchMoved(tableArray) - local nCount = table.getn(tableArray) - nCount = math.floor(nCount / 3) - print(nCount) + local function onTouchMoved(touches, event) + local count = table.getn(touches) + print("Number of touches: ",count) end - local function onTouchBegan(tableArray) - onTouchMoved(tableArray) + local function onTouchBegan(touches, event) + onTouchMoved(touches, event) end - + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCHES_MOVED ) - local function onTouch(eventType,tableArray) - if eventType == "began" then - return onTouchBegan(tableArray) - elseif eventType == "moved" then - return onTouchMoved(tableArray) - end - end - pLayer:registerScriptTouchHandler(onTouch,true) - return pLayer + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) + + return layer end --BugTest1159 @@ -372,25 +365,25 @@ local function BugTest1159() local seq = cc.Sequence:create(cc.MoveTo:create(1.0, cc.p(1024.0, 384.0)), cc.MoveTo:create(1.0, cc.p(0.0, 384.0))) sprite_a:runAction(cc.RepeatForever:create(seq)) - local sprite_b = cc.LayerColor:create(cc.c4b(0, 0, 255, 255), 400, 400); + local sprite_b = cc.LayerColor:create(cc.c4b(0, 0, 255, 255), 400, 400) sprite_b:setAnchorPoint(cc.p(0.5, 0.5)) - sprite_b:ignoreAnchorPointForPosition(false); - sprite_b:setPosition(cc.p(Winsize.width/2, Winsize.height/2)); - pLayer:addChild(sprite_b); + sprite_b:ignoreAnchorPointForPosition(false) + sprite_b:setPosition(cc.p(Winsize.width/2, Winsize.height/2)) + pLayer:addChild(sprite_b) local function menuCallback() local pScene = cc.Scene:create() local pLayer = BugTest1159() CreateBugsTestBackMenuItem(pLayer) - pScene:addChild(pLayer); + pScene:addChild(pLayer) cc.Director:getInstance():replaceScene(cc.TransitionPageTurn:create(1.0, pScene, false)) end - local label = cc.MenuItemLabel:create(cc.LabelTTF:create("Flip Me", "Helvetica", 24)); + local label = cc.MenuItemLabel:create(cc.LabelTTF:create("Flip Me", "Helvetica", 24)) label:registerScriptTapHandler(menuCallback) - local menu = cc.Menu:create(); + local menu = cc.Menu:create() menu:addChild(label) - menu:setPosition(cc.p(Winsize.width - 200.0, 50.0)); - pLayer:addChild(menu); + menu:setPosition(cc.p(Winsize.width - 200.0, 50.0)) + pLayer:addChild(menu) local function onNodeEvent(event) if event == "exit" then @@ -436,7 +429,7 @@ local function BugTest1174() local bRet = false print("Test1 - Start") - local i = 0; + local i = 0 for i = 0, 9999 do --[[ A|b @@ -490,12 +483,12 @@ local function BugTest1174() -------- print("Test2 - Start") - p1 = cc.p(220,480); - p2 = cc.p(304,325); - p3 = cc.p(264,416); - p4 = cc.p(186,416); - s = 0.0; - t = 0.0; + p1 = cc.p(220,480) + p2 = cc.p(304,325) + p3 = cc.p(264,416) + p4 = cc.p(186,416) + s = 0.0 + t = 0.0 bRet,s,t = cc.pIsLineIntersect( p1, p2, p3, p4, s, t) if true == bRet then check_for_error(p1, p2, p3, p4, s, t) @@ -515,7 +508,7 @@ local function BugTest1174() -- c | d local ax = math.random() * -500 local ay = math.random() * 500 - p1 = cc.p(ax,ay); + p1 = cc.p(ax,ay) -- a | b -- ----- -- c | D @@ -579,7 +572,7 @@ end local function BugsTestMainLayer() - local ret = cc.Layer:create(); + local ret = cc.Layer:create() --menu callback local function menuCallback(tag, pMenuItem) @@ -591,8 +584,8 @@ local function BugsTestMainLayer() end -- add menu items for tests - local pItemMenu = cc.Menu:create(); - local nTestCount = table.getn(testNames); + local pItemMenu = cc.Menu:create() + local nTestCount = table.getn(testNames) local i = 1 for i = 1, nTestCount do @@ -605,19 +598,15 @@ local function BugsTestMainLayer() pItemMenu:setPosition(cc.p(0, 0)) ret:addChild(pItemMenu) - ret:setTouchEnabled(true) -- handling touch events local ptBeginPos = {x = 0, y = 0} local ptCurPos = {x = 0, y = 0} - local function onTouchBegan(x, y) - ptBeginPos = {x = x, y = y} - -- cc.TOUCHBEGAN event must return true - return true - end - - local function onTouchMoved(x, y) - local nMoveY = y - ptBeginPos.y + + -- handling touch events + local function onTouchMoved(touches, event) + local touchLocation = touches[1]:getLocation() + local nMoveY = touchLocation.y - ptBeginPos.y local curPosx, curPosy = pItemMenu:getPosition() local nextPosy = curPosy + nMoveY if nextPosy < 0 then @@ -631,26 +620,25 @@ local function BugsTestMainLayer() end pItemMenu:setPosition(curPosx, nextPosy) - ptBeginPos = {x = x, y = y} + ptBeginPos = touchLocation ptCurPos = {x = curPosx, y = nextPosy} end - - local function onTouch(eventType, x, y) - if eventType == "began" then - return onTouchBegan(x, y) - elseif eventType == "moved" then - return onTouchMoved(x, y) - end + local function onTouchBegan(touches, event) + ptBeginPos = touches[1]:getLocation() end + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCHES_MOVED ) - ret:registerScriptTouchHandler(onTouch) + local eventDispatcher = ret:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret) return ret end function BugsTestMain() - cclog("BugsTestMain"); - local scene = cc.Scene:create(); - scene:addChild(BugsTestMainLayer()); - scene:addChild(CreateBackMenuItem()); - return scene; + cclog("BugsTestMain") + local scene = cc.Scene:create() + scene:addChild(BugsTestMainLayer()) + scene:addChild(CreateBackMenuItem()) + return scene end diff --git a/samples/Lua/TestLua/Resources/luaScript/ClickAndMoveTest/ClickAndMoveTest.lua b/samples/Lua/TestLua/Resources/luaScript/ClickAndMoveTest/ClickAndMoveTest.lua index ee13a9c390..87f49208b7 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ClickAndMoveTest/ClickAndMoveTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ClickAndMoveTest/ClickAndMoveTest.lua @@ -17,13 +17,20 @@ local function initWithLayer() cc.FadeIn:create(1), cc.FadeOut:create(1)))) - local function onTouchEnded(x, y) + local function onTouchBegan(touch, event) + return true + end + + local function onTouchEnded(touch, event) + + local location = touch:getLocation() + local s = layer:getChildByTag(kTagSprite) s:stopAllActions() - s:runAction(cc.MoveTo:create(1, cc.p(x, y))) + s:runAction(cc.MoveTo:create(1, cc.p(location.x, location.y))) local posX, posY = s:getPosition() - local o = x - posX - local a = y - posY + local o = location.x - posX + local a = location.y - posY local at = math.atan(o / a) / math.pi * 180.0 if a < 0 then @@ -36,16 +43,11 @@ local function initWithLayer() s:runAction(cc.RotateTo:create(1, at)) end - local function onTouch(eventType, x, y) - if eventType == "began" then - return true - elseif eventType == "ended" then - return onTouchEnded(x, y) - end - end - - layer:setTouchEnabled(true) - layer:registerScriptTouchHandler(onTouch) + local listener = cc.EventListenerTouchOneByOne:create() + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN ) + listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED ) + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) return layer end diff --git a/samples/Lua/TestLua/Resources/luaScript/CocoStudioTest/CocoStudioArmatureTest/CocoStudioArmatureTest.lua b/samples/Lua/TestLua/Resources/luaScript/CocoStudioTest/CocoStudioArmatureTest/CocoStudioArmatureTest.lua index 0163ccf583..adca6996a5 100644 --- a/samples/Lua/TestLua/Resources/luaScript/CocoStudioTest/CocoStudioArmatureTest/CocoStudioArmatureTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/CocoStudioTest/CocoStudioArmatureTest/CocoStudioArmatureTest.lua @@ -812,7 +812,6 @@ function TestParticleDisplay.extend(target) end function TestParticleDisplay:onEnter() - self:setTouchEnabled(true) self.animationID = 0 self.armature = ccs.Armature:create("robot") @@ -840,19 +839,17 @@ function TestParticleDisplay:onEnter() bone:setScale(1.2) self.armature:addBone(bone, "bady-a30") - local function onTouchBegan(x, y) + -- handling touch events + local function onTouchEnded(touches, event) self.animationID = (self.animationID + 1) % self.armature:getAnimation():getMovementCount() self.armature:getAnimation():playWithIndex(self.animationID) - return false end - local function onTouch(eventType, x, y) - if eventType == "began" then - return onTouchBegan(x,y) - end - end + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED ) - self:registerScriptTouchHandler(onTouch) + local eventDispatcher = self:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self) end function TestParticleDisplay.create() @@ -889,7 +886,6 @@ function TestUseMutiplePicture.extend(target) end function TestUseMutiplePicture:onEnter() - self:setTouchEnabled(true) self.displayIndex = 1 self.armature = ccs.Armature:create("Knight_f/Knight") @@ -915,19 +911,17 @@ function TestUseMutiplePicture:onEnter() self.armature:getBone("weapon"):addDisplay(skin, i - 1) end - local function onTouchBegan(x, y) + -- handling touch events + local function onTouchEnded(touches, event) self.displayIndex = (self.displayIndex + 1) % (table.getn(weapon) - 1) self.armature:getBone("weapon"):changeDisplayWithIndex(self.displayIndex, true) - return false end - local function onTouch(eventType, x, y) - if eventType == "began" then - return onTouchBegan(x,y) - end - end + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED ) - self:registerScriptTouchHandler(onTouch) + local eventDispatcher = self:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self) end function TestUseMutiplePicture.create() @@ -1012,7 +1006,6 @@ function TestArmatureNesting.extend(target) end function TestArmatureNesting:onEnter() - self:setTouchEnabled(true) self.weaponIndex = 0 self.armature = ccs.Armature:create("cyborg") @@ -1022,20 +1015,18 @@ function TestArmatureNesting:onEnter() self.armature:getAnimation():setSpeedScale(0.4) self:addChild(self.armature) - local function onTouchBegan(x, y) + -- handling touch events + local function onTouchEnded(touches, event) self.weaponIndex = (self.weaponIndex + 1) % 4 self.armature:getBone("armInside"):getChildArmature():getAnimation():playWithIndex(self.weaponIndex) self.armature:getBone("armOutside"):getChildArmature():getAnimation():playWithIndex(self.weaponIndex) - return false end - local function onTouch(eventType, x, y) - if eventType == "began" then - return onTouchBegan(x,y) - end - end + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED ) - self:registerScriptTouchHandler(onTouch) + local eventDispatcher = self:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self) end function TestArmatureNesting.create() @@ -1131,30 +1122,26 @@ function TestArmatureNesting2.extend(target) end function TestArmatureNesting2:onEnter() - - self:setTouchEnabled(true) - - local function onTouchesEnded(tableArray) - local x,y = tableArray[1],tableArray[2] + -- handling touch events + local function onTouchEnded(touches, event) + local location = touches[1]:getLocation() local armature = self._hero._mount and self._hero._mount or self._hero - if x < armature:getPositionX() then + if location.x < armature:getPositionX() then armature:setScaleX(-1) else armature:setScaleX(1) end - local move = cc.MoveTo:create(2, cc.p(x,y)) + local move = cc.MoveTo:create(2, location) armature:stopAllActions() armature:runAction(cc.Sequence:create(move)) end - local function onTouch(eventType, tableArray) - if eventType == "ended" then - return onTouchesEnded(tableArray) - end - end + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED ) - self:registerScriptTouchHandler(onTouch,true) + local eventDispatcher = self:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self) local function changeMountCallback(sender) self._hero:stopAllActions() diff --git a/samples/Lua/TestLua/Resources/luaScript/CocosDenshionTest/CocosDenshionTest.lua b/samples/Lua/TestLua/Resources/luaScript/CocosDenshionTest/CocosDenshionTest.lua index 2d818a618e..5cc281471a 100644 --- a/samples/Lua/TestLua/Resources/luaScript/CocosDenshionTest/CocosDenshionTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/CocosDenshionTest/CocosDenshionTest.lua @@ -108,7 +108,6 @@ local function CocosDenshionTest() m_pItmeMenu:setContentSize(cc.size(VisibleRect:getVisibleRect().width, (m_nTestCount + 1) * LINE_SPACE)) m_pItmeMenu:setPosition(cc.p(0, 0)) ret:addChild(m_pItmeMenu) - ret:setTouchEnabled(true) -- preload background music and effect AudioEngine.preloadMusic( MUSIC_FILE ) @@ -159,7 +158,46 @@ local function CocosDenshionTest() end end - ret:registerScriptTouchHandler(onTouchEvent) + local function onTouchBegan(touch, event) + local location = touch:getLocation() + prev.x = location.x + prev.y = location.y + m_tBeginPos = location + return true + end + + local function onTouchMoved(touch, event) + local location = touch:getLocation() + local touchLocation = location + local nMoveY = touchLocation.y - m_tBeginPos.y + local curPosX, curPosY = m_pItmeMenu:getPosition() + local curPos = cc.p(curPosX, curPosY) + local nextPos = cc.p(curPos.x, curPos.y + nMoveY) + + if nextPos.y < 0.0 then + m_pItmeMenu:setPosition(cc.p(0, 0)) + end + + if nextPos.y > ((m_nTestCount + 1)* LINE_SPACE - VisibleRect:getVisibleRect().height) then + m_pItmeMenu:setPosition(cc.p(0, ((m_nTestCount + 1)* LINE_SPACE - VisibleRect:getVisibleRect().height))) + end + + m_pItmeMenu:setPosition(nextPos) + m_tBeginPos.x = touchLocation.x + m_tBeginPos.y = touchLocation.y + + prev.x = location.x + prev.y = location.y + end + + local listener = cc.EventListenerTouchOneByOne:create() + listener:setSwallowTouches(true) + + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN ) + listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED ) + local eventDispatcher = ret:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret) + return ret end diff --git a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua index 80deae2f4d..8283c71e99 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ExtensionTest/ExtensionTest.lua @@ -1239,14 +1239,15 @@ local function ExtensionsMainLayer() layer:addChild(menu) -- handling touch events - local beginPos = {x = 0, y = 0} - local function onTouchBegan(x, y) - beginPos = {x = x, y = y} - return true + local beginPos = {x = 0, y = 0} + local function onTouchesBegan(touches, event) + beginPos = touches[1]:getLocation() end - local function onTouchMoved(x, y) - local nMoveY = y - beginPos.y + local function onTouchesMoved(touches, event) + local location = touches[1]:getLocation() + + local nMoveY = location.y - beginPos.y local curPosx, curPosy = menu:getPosition() local nextPosy = curPosy + nMoveY local winSize = cc.Director:getInstance():getWinSize() @@ -1261,20 +1262,15 @@ local function ExtensionsMainLayer() end menu:setPosition(curPosx, nextPosy) - beginPos = {x = x, y = y} + beginPos = {x = location.x, y = location.y} end - local function onTouch(eventType, x, y) - if eventType == "began" then - return onTouchBegan(x, y) - elseif eventType == "moved" then - return onTouchMoved(x, y) - end - end + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCH_MOVED ) - layer:setTouchEnabled(true) - - layer:registerScriptTouchHandler(onTouch) + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) return layer end diff --git a/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua b/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua index 3025c2afce..c92d347fcb 100644 --- a/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/LabelTest/LabelTest.lua @@ -992,8 +992,6 @@ function BitmapFontMultiLineAlignment.create() local layer = cc.Layer:create() Helper.initWithLayer(layer) - layer:setTouchEnabled(true) - -- ask director the the window size local size = cc.Director:getInstance():getWinSize() @@ -1068,7 +1066,44 @@ function BitmapFontMultiLineAlignment.create() layer:addChild(stringMenu) layer:addChild(alignmentMenu) layer:registerScriptHandler(BitmapFontMultiLineAlignment.onNodeEvent) - layer:registerScriptTouchHandler(BitmapFontMultiLineAlignment.onTouchEvent) + + local function onTouchesBegan(touches, event) + local location = touches[1]:getLocationInView() + if cc.rectContainsPoint(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), location) then + BitmapFontMultiLineAlignment._drag = true + BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true) + end + end + + local function onTouchesMoved(touches, event) + if BitmapFontMultiLine._drag == false then + return + end + local location = touches[1]:getLocationInView() + local winSize = cc.Director:getInstance():getWinSize() + BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition( + math.max(math.min(location.x, ArrowsMax*winSize.width), ArrowsMin*winSize.width), + BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionY()) + + local labelWidth = math.abs(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionX() - BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2 + + BitmapFontMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth) + end + + local function onTouchesEnded(touch, event) + BitmapFontMultiLineAlignment._drag = false + BitmapFontMultiLineAlignment.snapArrowsToEdge() + BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false) + end + + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED ) + + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) + return layer end @@ -1118,35 +1153,6 @@ function BitmapFontMultiLineAlignment.alignmentChanged(tag, sender) BitmapFontMultiLineAlignment.snapArrowsToEdge() end -function BitmapFontMultiLineAlignment.onTouchEvent(eventType, x, y) - -- cclog("type:"..eventType.."["..x..","..y.."]") - if eventType == "began" then - if cc.rectContainsPoint(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(x, y)) then - BitmapFontMultiLineAlignment._drag = true - BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true) - return true - end - elseif eventType == "ended" then - BitmapFontMultiLineAlignment._drag = false - BitmapFontMultiLineAlignment.snapArrowsToEdge() - BitmapFontMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false) - elseif eventType == "moved" then - if BitmapFontMultiLine._drag == false then - return - end - - local winSize = cc.Director:getInstance():getWinSize() - BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition( - math.max(math.min(x, ArrowsMax*winSize.width), ArrowsMin*winSize.width), - BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionY()) - - local labelWidth = math.abs(BitmapFontMultiLineAlignment._pArrowsShouldRetain:getPositionX() - BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2 - - BitmapFontMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth) - - end -end - function BitmapFontMultiLineAlignment.snapArrowsToEdge() BitmapFontMultiLineAlignment._pArrowsShouldRetain:setPosition( BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionX() + BitmapFontMultiLineAlignment._pLabelShouldRetain:getContentSize().width/2, BitmapFontMultiLineAlignment._pLabelShouldRetain:getPositionY() diff --git a/samples/Lua/TestLua/Resources/luaScript/LabelTestNew/LabelTestNew.lua b/samples/Lua/TestLua/Resources/luaScript/LabelTestNew/LabelTestNew.lua index 68108fc1d9..0bcdadd979 100644 --- a/samples/Lua/TestLua/Resources/luaScript/LabelTestNew/LabelTestNew.lua +++ b/samples/Lua/TestLua/Resources/luaScript/LabelTestNew/LabelTestNew.lua @@ -596,9 +596,6 @@ local LabelFNTMultiLineAlignment = { function LabelFNTMultiLineAlignment.create() local layer = cc.Layer:create() Helper.initWithLayer(layer) - - layer:setTouchEnabled(true) - -- ask director the the window size local size = cc.Director:getInstance():getWinSize() @@ -674,7 +671,46 @@ function LabelFNTMultiLineAlignment.create() layer:addChild(stringMenu) layer:addChild(alignmentMenu) layer:registerScriptHandler(LabelFNTMultiLineAlignment.onNodeEvent) - layer:registerScriptTouchHandler(LabelFNTMultiLineAlignment.onTouchEvent) + + local function onTouchesBegan(touches, event) + local location = touches[1]:getLocationInView() + if cc.rectContainsPoint(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(location.x, location.y)) then + LabelFNTMultiLineAlignment._drag = true + LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true) + end + end + + local function onTouchesMoved(touches, event) + if LabelFNTMultiLineAlignment._drag == false then + return + end + + local winSize = cc.Director:getInstance():getWinSize() + local location = touches[1]:getLocationInView() + + LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition( + math.max(math.min(location.x, ArrowsMax*winSize.width), ArrowsMin*winSize.width), + LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionY()) + + local labelWidth = math.abs(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionX() - LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2 + + LabelFNTMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth) + end + + local function onTouchesEnded(touch, event) + LabelFNTMultiLineAlignment._drag = false + LabelFNTMultiLineAlignment.snapArrowsToEdge() + LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false) + end + + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED ) + + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) + return layer end @@ -724,35 +760,6 @@ function LabelFNTMultiLineAlignment.alignmentChanged(tag, sender) LabelFNTMultiLineAlignment.snapArrowsToEdge() end -function LabelFNTMultiLineAlignment.onTouchEvent(eventType, x, y) - -- cclog("type:"..eventType.."["..x..","..y.."]") - if eventType == "began" then - if cc.rectContainsPoint(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getBoundingBox(), cc.p(x, y)) then - LabelFNTMultiLineAlignment._drag = true - LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(true) - return true - end - elseif eventType == "ended" then - LabelFNTMultiLineAlignment._drag = false - LabelFNTMultiLineAlignment.snapArrowsToEdge() - LabelFNTMultiLineAlignment._pArrowsBarShouldRetain:setVisible(false) - elseif eventType == "moved" then - if LabelFNTMultiLineAlignment._drag == false then - return - end - - local winSize = cc.Director:getInstance():getWinSize() - LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition( - math.max(math.min(x, ArrowsMax*winSize.width), ArrowsMin*winSize.width), - LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionY()) - - local labelWidth = math.abs(LabelFNTMultiLineAlignment._pArrowsShouldRetain:getPositionX() - LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX()) * 2 - - LabelFNTMultiLineAlignment._pLabelShouldRetain:setWidth(labelWidth) - - end -end - function LabelFNTMultiLineAlignment.snapArrowsToEdge() LabelFNTMultiLineAlignment._pArrowsShouldRetain:setPosition( LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionX() + LabelFNTMultiLineAlignment._pLabelShouldRetain:getContentSize().width/2, LabelFNTMultiLineAlignment._pLabelShouldRetain:getPositionY() diff --git a/samples/Lua/TestLua/Resources/luaScript/LayerTest/LayerTest.lua b/samples/Lua/TestLua/Resources/luaScript/LayerTest/LayerTest.lua index 5a8be68410..7fce8fdc99 100644 --- a/samples/Lua/TestLua/Resources/luaScript/LayerTest/LayerTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/LayerTest/LayerTest.lua @@ -302,8 +302,6 @@ end local function LayerTest1() local ret = createLayerDemoLayer("ColorLayer resize (tap & move)") - ret:setTouchEnabled(true) - local s = cc.Director:getInstance():getWinSize() local layer = cc.LayerColor:create( cc.c4b(0xFF, 0x00, 0x00, 0x80), 200, 200) @@ -321,15 +319,23 @@ local function LayerTest1() l:setContentSize( newSize ) end - local function onTouchEvent(eventType, x, y) - if eventType == "began" then - updateSize(x, y) - return true - else - updateSize(x, y) - end + local function onTouchesMoved(touches, event) + local touchLocation = touches[1]:getLocation() + + updateSize(touchLocation.x, touchLocation.y) end - ret:registerScriptTouchHandler(onTouchEvent) + + local function onTouchesBegan(touches, event) + onTouchesMoved(touches, event) + end + + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + + local eventDispatcher = ret:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret) + return ret end @@ -430,8 +436,6 @@ local function LayerGradient() local layer1 = cc.LayerGradient:create(cc.c4b(255,0,0,255), cc.c4b(0,255,0,255), cc.p(0.9, 0.9)) ret:addChild(layer1, 0, kTagLayer) - ret:setTouchEnabled(true) - local label1 = cc.LabelTTF:create("Compressed Interpolation: Enabled", "Marker Felt", 26) local label2 = cc.LabelTTF:create("Compressed Interpolation: Disabled", "Marker Felt", 26) local item1 = cc.MenuItemLabel:create(label1) @@ -452,22 +456,23 @@ local function LayerGradient() local s = cc.Director:getInstance():getWinSize() menu:setPosition(cc.p(s.width / 2, 100)) - local function onTouchEvent(eventType, x, y) - if eventType == "began" then - return true - elseif eventType == "moved" then - local s = cc.Director:getInstance():getWinSize() - local start = cc.p(x, y) - local movingPos = cc.p(s.width/2,s.height/2) - local diff = cc.p(movingPos.x - start.x, movingPos.y - start.y) - diff = cc.pNormalize(diff) + local function onTouchesMoved(touches, event) + local s = cc.Director:getInstance():getWinSize() + local start = touches[1]:getLocation() + local movingPos = cc.p(s.width/2,s.height/2) + local diff = cc.p(movingPos.x - start.x, movingPos.y - start.y) + diff = cc.pNormalize(diff) - local gradient = tolua.cast(ret:getChildByTag(1), "cc.LayerGradient") - gradient:setVector(diff) - end + local gradient = tolua.cast(ret:getChildByTag(1), "cc.LayerGradient") + gradient:setVector(diff) end - ret:registerScriptTouchHandler(onTouchEvent) + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + + local eventDispatcher = ret:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret) + return ret end diff --git a/samples/Lua/TestLua/Resources/luaScript/MenuTest/MenuTest.lua b/samples/Lua/TestLua/Resources/luaScript/MenuTest/MenuTest.lua index 7569f70cf2..5c1c78c42a 100644 --- a/samples/Lua/TestLua/Resources/luaScript/MenuTest/MenuTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/MenuTest/MenuTest.lua @@ -22,8 +22,6 @@ local function MenuLayerMainMenu() local m_disabledItem = nil local ret = cc.Layer:create() - ret:setTouchEnabled(true) - ret:setTouchMode(cc.TOUCHES_ONE_BY_ONE ) -- Font Item local spriteNormal = cc.Sprite:create(s_MenuItem, cc.rect(0,23*2,115,23)) @@ -542,32 +540,32 @@ local function RemoveMenuItemWhenMove() menu:setPosition(cc.p(s.width/2, s.height/2)) - ret:setTouchEnabled(true) ---[[ + local function onTouchBegan(touch, event) + return true + end + + local function onTouchMoved(touch, event) + if item ~= nil then + item:removeFromParent(true) + --item:release() + --item = nil + end + end + + local listener = cc.EventListenerTouchOneByOne:create() + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN ) + listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED ) + local eventDispatcher = ret:getEventDispatcher() + eventDispatcher:addEventListenerWithFixedPriority(listener, -129) + local function onNodeEvent(event) - if event == "enter" then - cc.Director:getInstance():getTouchDispatcher():addTargetedDelegate(ret, -129, false) - elseif event == "exit" then - -- item:release() + if event == "exit" then + ret:getEventDispatcher():removeEventListener(listener) end end ret:registerScriptHandler(onNodeEvent) - ]]-- - local function onTouchEvent(eventType, x, y) - if eventType == "began" then - return true - elseif eventType == "moved" then - if item ~= nil then - item:removeFromParent(true) - --item:release() - --item = nil - end - end - end - - ret:registerScriptTouchHandler(onTouchEvent,false,-129,false) return ret end diff --git a/samples/Lua/TestLua/Resources/luaScript/MotionStreakTest/MotionStreakTest.lua b/samples/Lua/TestLua/Resources/luaScript/MotionStreakTest/MotionStreakTest.lua index 60cd559053..79db81c8c7 100644 --- a/samples/Lua/TestLua/Resources/luaScript/MotionStreakTest/MotionStreakTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/MotionStreakTest/MotionStreakTest.lua @@ -106,28 +106,17 @@ local function MotionStreakTest2() streak:setPosition(cc.p(s.width / 2, s.height / 2)) - local function onTouchMoved(x, y) - if firstTick == true then - firstTick = false - return - end - - streak:setPosition(cc.p(x, y)) + local function onTouchesMoved(touches, event) + streak:setPosition( touches[1]:getLocation() ) end - local function onTouch(eventType, x, y) - if eventType == "began" then - return true - elseif eventType == "moved" then - return onTouchMoved(x, y) - end - end - - firstTick = true - layer:setTouchEnabled(true) - layer:registerScriptTouchHandler(onTouch) + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) Helper.titleLabel:setString("MotionStreak test") + return layer end diff --git a/samples/Lua/TestLua/Resources/luaScript/NodeTest/NodeTest.lua b/samples/Lua/TestLua/Resources/luaScript/NodeTest/NodeTest.lua index d4ee880113..6cf01b65e6 100644 --- a/samples/Lua/TestLua/Resources/luaScript/NodeTest/NodeTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/NodeTest/NodeTest.lua @@ -569,27 +569,25 @@ local function ConvertToNode() ConvertToNode_layer:addChild(sprite, i) end - local function onTouchEnded(x, y) - for i = 0, 2 do - local node = ConvertToNode_layer:getChildByTag(100 + i) - local p1, p2 - p1 = node:convertToNodeSpaceAR(cc.p(x, y)) - p2 = node:convertToNodeSpace(cc.p(x, y)) + local function onTouchesEnded(touches, event) + local count = table.getn(touches) + for i = 1, count do + local location = touches[i]:getLocation() + for j = 1,3 do + local node = ConvertToNode_layer:getChildByTag(100 + i - 1) + local p1, p2 + p1 = node:convertToNodeSpaceAR(location) + p2 = node:convertToNodeSpace(location) - cclog("AR: x=" .. p1.x .. ", y=" .. p1.y .. " -- Not AR: x=" .. p2.x .. ", y=" .. p2.y) + cclog("AR: x=" .. p1.x .. ", y=" .. p1.y .. " -- Not AR: x=" .. p2.x .. ", y=" .. p2.y) + end end end - local function onTouch(eventType, x, y) - if eventType == "began" then - return true - elseif eventType == "ended" then - return onTouchEnded(x, y) - end - end - - ConvertToNode_layer:setTouchEnabled(true) - ConvertToNode_layer:registerScriptTouchHandler(onTouch) + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED ) + local eventDispatcher = ConvertToNode_layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ConvertToNode_layer) Helper.titleLabel:setString("Convert To Node Space") Helper.subtitleLabel:setString("testing convertToNodeSpace / AR. Touch and see console") diff --git a/samples/Lua/TestLua/Resources/luaScript/ParallaxTest/ParallaxTest.lua b/samples/Lua/TestLua/Resources/luaScript/ParallaxTest/ParallaxTest.lua index 24f5405368..af6d1c160f 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ParallaxTest/ParallaxTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ParallaxTest/ParallaxTest.lua @@ -83,7 +83,6 @@ end local function Parallax2() local ret = createParallaxLayer("Parallax: drag screen") - ret:setTouchEnabled( true ) -- Top Layer, a simple image local cocosImage = cc.Sprite:create(s_Power) @@ -126,25 +125,19 @@ local function Parallax2() -- top image is moved at a ratio of 3.0x, 2.5y voidNode:addChild( cocosImage, 2, cc.p(3.0,2.5), cc.p(200,1000) ) ret:addChild(voidNode, 0, kTagNode) - local prev = {x = 0, y = 0} - local function onTouchEvent(eventType, x, y) - if eventType == "began" then - prev.x = x - prev.y = y - return true - elseif eventType == "moved" then - local node = ret:getChildByTag(kTagNode) - local newX = node:getPositionX() - local newY = node:getPositionY() - local diffX = x - prev.x - local diffY = y - prev.y - node:setPosition( cc.pAdd(cc.p(newX, newY), cc.p(diffX, diffY)) ) - prev.x = x - prev.y = y - end + local function onTouchesMoved(touches, event) + local diff = touches[1]:getDelta() + + local node = ret:getChildByTag(kTagNode) + local currentPosX, currentPosY = node:getPosition() + node:setPosition(cc.p(currentPosX + diff.x, currentPosY + diff.y)) end - ret:registerScriptTouchHandler(onTouchEvent) + + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + local eventDispatcher = ret:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret) return ret end diff --git a/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua b/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua index 54c0631ebd..2b4848251b 100644 --- a/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/ParticleTest/ParticleTest.lua @@ -147,28 +147,34 @@ local function getBaseLayer() local seq = cc.Sequence:create(move, move_back) background:runAction(cc.RepeatForever:create(seq)) - local function onTouchEnded(x, y) - local pos = cc.p(0, 0) - if background ~= nil then - pos = background:convertToWorldSpace(cc.p(0, 0)) - end + local function onTouchesEnded(touches, event) + local location = touches[1]:getLocation() + local pos = cc.p(0, 0) + if background ~= nil then + pos = background:convertToWorldSpace(cc.p(0, 0)) + end - if emitter ~= nil then - local newPos = cc.pSub(cc.p(x, y), pos) - emitter:setPosition(newPos.x, newPos.y) - end - end - - local function onTouch(eventType, x, y) - if eventType == "began" then - return true - else - return onTouchEnded(x, y) + if emitter ~= nil then + local newPos = cc.pSub(location, pos) + emitter:setPosition(newPos.x, newPos.y) end end - layer:setTouchEnabled(true) - layer:registerScriptTouchHandler(onTouch) + local function onTouchesBegan(touches, event) + onTouchesEnded(touches, event); + end + + local function onTouchesMoved(touches, event) + onTouchesEnded(touches, event); + end + + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED ) + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) + layer:registerScriptHandler(baseLayer_onEnterOrExit) return layer diff --git a/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua b/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua index f70a5a59b0..070d78b44d 100644 --- a/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua @@ -1548,48 +1548,37 @@ local function runTouchesTest() end -- handling touch events - local function onTouchBegan(tableArray) - if 0 == nCurCase then - nNumberOfTouchesB = nNumberOfTouchesB + 1 - elseif 1 == nCurCase then - nNumberOfTouchesB = nNumberOfTouchesB + table.getn(tableArray) - end - end - - local function onTouchMoved(tableArray) - if 0 == nCurCase then - nNumberOfTouchesM = nNumberOfTouchesM + 1 - elseif 1 == nCurCase then - nNumberOfTouchesM = nNumberOfTouchesM + table.getn(tableArray) - end - end - - local function onTouchEnded(tableArray) - if 0 == nCurCase then - nNumberOfTouchesE = nNumberOfTouchesE + 1 - elseif 1 == nCurCase then - nNumberOfTouchesE = nNumberOfTouchesE + table.getn(tableArray) - end - end - - local function onTouchCancelled(tableArray) - if 0 == nCurCase then - nNumberOfTouchesC = nNumberOfTouchesC + 1 - elseif 1 == nCurCase then - nNumberOfTouchesC = nNumberOfTouchesC + table.getn(tableArray) - end + local function onTouchEnded(touch, event) + nNumberOfTouchesE = nNumberOfTouchesE + 1 end - local function onTouch(eventType,tableArray) - if eventType == "began" then - return onTouchBegan(tableArray) - elseif eventType == "moved" then - return onTouchMoved(tableArray) - elseif eventType == "ended" then - return onTouchEnded(tableArray) - elseif eventType == "cancelled" then - return onTouchCancelled(tableArray) - end + local function onTouchBegan(touch, event) + nNumberOfTouchesB = nNumberOfTouchesB + 1 + end + + local function onTouchMoved(touch, event) + nNumberOfTouchesM = nNumberOfTouchesM + 1 + end + + local function onTouchCancelled(touch, event) + nNumberOfTouchesC = nNumberOfTouchesC + 1 + end + + + local function onTouchesEnded(touches, event) + nNumberOfTouchesE = nNumberOfTouchesE + table.getn(touches) + end + + local function onTouchesBegan(touches, event) + nNumberOfTouchesB = nNumberOfTouchesB + table.getn(touches) + end + + local function onTouchesMoved(touches, event) + nNumberOfTouchesM = nNumberOfTouchesM + table.getn(touches) + end + + local function onTouchesCancelled(touches, event) + nNumberOfTouchesC= nNumberOfTouchesC + table.getn(touches) end local function InitLayer() @@ -1617,9 +1606,24 @@ local function runTouchesTest() nNumberOfTouchesM = 0 nNumberOfTouchesE = 0 nNumberOfTouchesC = 0 - pLayer:setTouchEnabled(true) - - pLayer:registerScriptTouchHandler(onTouch,true) + + if 0 == nCurCase then + local listener = cc.EventListenerTouchOneByOne:create() + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN ) + listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED ) + listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED ) + listener:registerScriptHandler(onTouchCancelled,cc.Handler.EVENT_TOUCH_CANCELLED ) + local eventDispatcher = pLayer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, pLayer) + elseif 1 == nCurCase then + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesBegan,cc.Handler.EVENT_TOUCHES_BEGAN ) + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + listener:registerScriptHandler(onTouchesEnded,cc.Handler.EVENT_TOUCHES_ENDED ) + listener:registerScriptHandler(onTouchesCancelled,cc.Handler.EVENT_TOUCHES_CANCELLED ) + local eventDispatcher = pLayer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, pLayer) + end end function ShowCurrentTest() diff --git a/samples/Lua/TestLua/Resources/luaScript/RenderTextureTest/RenderTextureTest.lua b/samples/Lua/TestLua/Resources/luaScript/RenderTextureTest/RenderTextureTest.lua index 6b731bd1c5..d44a4a677a 100644 --- a/samples/Lua/TestLua/Resources/luaScript/RenderTextureTest/RenderTextureTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/RenderTextureTest/RenderTextureTest.lua @@ -8,22 +8,21 @@ local function RenderTextureSave() local ret = createTestLayer("Touch the screen", "Press 'Save Image' to create an snapshot of the render texture") local s = cc.Director:getInstance():getWinSize() - local m_pTarget = nil - local m_pBrush = nil - local m_pTarget = nil + local target = nil local counter = 0 + local brushes = {} local function clearImage(tag, pSender) - m_pTarget:clear(math.random(), math.random(), math.random(), math.random()) + target:clear(math.random(), math.random(), math.random(), math.random()) end local function saveImage(tag, pSender) local png = string.format("image-%d.png", counter) local jpg = string.format("image-%d.jpg", counter) - m_pTarget:saveToFile(png, cc.IMAGE_FORMAT_PNG) - m_pTarget:saveToFile(jpg, cc.IMAGE_FORMAT_JPEG) + target:saveToFile(png, cc.IMAGE_FORMAT_PNG) + target:saveToFile(jpg, cc.IMAGE_FORMAT_JPEG) - local pImage = m_pTarget:newImage() + local pImage = target:newImage() local tex = cc.Director:getInstance():getTextureCache():addUIImage(pImage, png) @@ -42,8 +41,7 @@ local function RenderTextureSave() local function onNodeEvent(event) if event == "exit" then - m_pBrush:release() - m_pTarget:release() + target:release() cc.Director:getInstance():getTextureCache():removeUnusedTextures() end end @@ -51,69 +49,58 @@ local function RenderTextureSave() ret:registerScriptHandler(onNodeEvent) -- create a render texture, this is what we are going to draw into - m_pTarget = cc.RenderTexture:create(s.width, s.height, cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888) - m_pTarget:retain() - m_pTarget:setPosition(cc.p(s.width / 2, s.height / 2)) + target = cc.RenderTexture:create(s.width, s.height, cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888) + target:retain() + target:setPosition(cc.p(s.width / 2, s.height / 2)) -- note that the render texture is a cc.Node, and contains a sprite of its texture for convience, -- so we can just parent it to the scene like any other cc.Node - ret:addChild(m_pTarget, -1) + ret:addChild(target, -1) - -- create a brush image to draw into the texture with - m_pBrush = cc.Sprite:create("Images/fire.png") - m_pBrush:retain() - m_pBrush:setColor(cc.c3b(255, 0, 0)) - m_pBrush:setOpacity(20) + local function onTouchesMoved(touches, event) + local start = touches[1]:getLocation() + local ended = touches[1]:getPreviousLocation() + target:begin() - local prev = {x = 0, y = 0} - local function onTouchEvent(eventType, x, y) - if eventType == "began" then - prev.x = x - prev.y = y - return true - elseif eventType == "moved" then - local diffX = x - prev.x - local diffY = y - prev.y + local distance = cc.pGetDistance(start, ended) + if distance > 1 then + brushes = {} + local d = distance + local i = 0 - local startP = cc.p(x, y) - local endP = cc.p(prev.x, prev.y) - - -- begin drawing to the render texture - m_pTarget:begin() - - -- for extra points, we'll draw this smoothly from the last position and vary the sprite's - -- scale/rotation/offset - local distance = cc.pGetDistance(startP, endP) - if distance > 1 then - local d = distance - local i = 0 - for i = 0, d-1 do - local difx = endP.x - startP.x - local dify = endP.y - startP.y - local delta = i / distance - m_pBrush:setPosition(cc.p(startP.x + (difx * delta), startP.y + (dify * delta))) - m_pBrush:setRotation(math.random(0, 359)) - local r = math.random(0, 49) / 50.0 + 0.25 - m_pBrush:setScale(r) - - -- Use cc.RANDOM_0_1() will cause error when loading libtests.so on android, I don't know why. - m_pBrush:setColor(cc.c3b(math.random(0, 126) + 128, 255, 255)) - -- Call visit to draw the brush, don't call draw.. - m_pBrush:visit() - end + for i = 0,d -1 do + -- create a brush image to draw into the texture with + local sprite = cc.Sprite:create("Images/fire.png") + sprite:setColor(cc.c3b(255, 0, 0)) + sprite:setOpacity(20) + brushes[i + 1] = sprite end - -- finish drawing and return context back to the screen - m_pTarget:endToLua() + for i = 0,d -1 do + local difx = ended.x - start.x + local dify = ended.y - start.y + local delta = i / distance + brushes[i + 1]:setPosition(cc.p(start.x + (difx * delta), start.y + (dify * delta))) + brushes[i + 1]:setRotation(math.random(0, 359)) + local r = math.random(0, 49) / 50.0 + 0.25 + brushes[i + 1]:setScale(r) + + -- Use cc.RANDOM_0_1() will cause error when loading libtests.so on android, I don't know why. + brushes[i + 1]:setColor(cc.c3b(math.random(0, 126) + 128, 255, 255)) + -- Call visit to draw the brush, don't call draw.. + brushes[i + 1]:visit() + end end - prev.x = x - prev.y = y + -- finish drawing and return context back to the screen + target:endToLua() end - ret:setTouchEnabled(true) - ret:registerScriptTouchHandler(onTouchEvent) + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + local eventDispatcher = ret:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, ret) -- Save Image menu cc.MenuItemFont:setFontSize(16) local item1 = cc.MenuItemFont:create("Save Image") diff --git a/samples/Lua/TestLua/Resources/luaScript/SpriteTest/SpriteTest.lua b/samples/Lua/TestLua/Resources/luaScript/SpriteTest/SpriteTest.lua index 05f6ae2488..29c4dae6aa 100644 --- a/samples/Lua/TestLua/Resources/luaScript/SpriteTest/SpriteTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/SpriteTest/SpriteTest.lua @@ -55,12 +55,10 @@ function Sprite1.addNewSpriteWithCoords(layer, point) sprite:runAction( cc.RepeatForever:create(seq) ) end -function Sprite1.onTouch(event, x, y) - if event == "began" then - return true - elseif event == "ended" then - Sprite1.addNewSpriteWithCoords(Helper.currentLayer, cc.p(x,y)) - return true +function Sprite1.onTouchesEnd(touches, event) + for i = 1,table.getn(touches) do + local location = touches[i]:getLocation() + Sprite1.addNewSpriteWithCoords(Helper.currentLayer, location) end end @@ -69,8 +67,11 @@ function Sprite1.create() local layer = cc.Layer:create() Helper.initWithLayer(layer) Sprite1.addNewSpriteWithCoords(layer, cc.p(size.width/2, size.height/2)) - layer:setTouchEnabled(true) - layer:registerScriptTouchHandler(Sprite1.onTouch) + + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(Sprite1.onTouchesEnd,cc.Handler.EVENT_TOUCHES_ENDED ) + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) Helper.titleLabel:setString("Sprite (tap screen)") @@ -115,12 +116,10 @@ function SpriteBatchNode1.addNewSpriteWithCoords(layer, point) sprite:runAction( cc.RepeatForever:create(seq) ) end -function SpriteBatchNode1.onTouch(event, x, y) - if event == "began" then - return true - elseif event == "ended" then - SpriteBatchNode1.addNewSpriteWithCoords(Helper.currentLayer, cc.p(x,y)) - return true +function SpriteBatchNode1.onTouchesEnd(touches,event) + for i = 1,table.getn(touches) do + local location = touches[i]:getLocation() + SpriteBatchNode1.addNewSpriteWithCoords(Helper.currentLayer, location) end end @@ -132,8 +131,10 @@ function SpriteBatchNode1.create() SpriteBatchNode1.addNewSpriteWithCoords(layer, cc.p(size.width/2, size.height/2)) - layer:setTouchEnabled(true) - layer:registerScriptTouchHandler(SpriteBatchNode1.onTouch) + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(Sprite1.onTouchesEnd,cc.Handler.EVENT_TOUCHES_ENDED ) + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) Helper.titleLabel:setString("SpriteBatchNode (tap screen)") diff --git a/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua b/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua index 66fc8ffac1..69d394373a 100644 --- a/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/TileMapTest/TileMapTest.lua @@ -12,26 +12,18 @@ local function createTileDemoLayer(title, subtitle) Helper.titleLabel:setString(titleStr) Helper.subtitleLabel:setString(subTitleStr) - local prev = {x = 0, y = 0} - local function onTouchEvent(eventType, x, y) - if eventType == "began" then - prev.x = x - prev.y = y - return true - elseif eventType == "moved" then - local node = layer:getChildByTag(kTagTileMap) - local newX = node:getPositionX() - local newY = node:getPositionY() - local diffX = x - prev.x - local diffY = y - prev.y - - node:setPosition( cc.pAdd(cc.p(newX, newY), cc.p(diffX, diffY)) ) - prev.x = x - prev.y = y - end + local function onTouchesMoved(touches, event ) + local diff = touches[1]:getDelta() + local node = layer:getChildByTag(kTagTileMap) + local currentPosX, currentPosY= node:getPosition() + node:setPosition(cc.p(currentPosX + diff.x, currentPosY + diff.y)) end - layer:setTouchEnabled(true) - layer:registerScriptTouchHandler(onTouchEvent) + + local listener = cc.EventListenerTouchAllAtOnce:create() + listener:registerScriptHandler(onTouchesMoved,cc.Handler.EVENT_TOUCHES_MOVED ) + local eventDispatcher = layer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layer) + return layer end -------------------------------------------------------------------- diff --git a/samples/Lua/TestLua/Resources/luaScript/mainMenu.lua b/samples/Lua/TestLua/Resources/luaScript/mainMenu.lua index 17302973c2..4c47dc697f 100644 --- a/samples/Lua/TestLua/Resources/luaScript/mainMenu.lua +++ b/samples/Lua/TestLua/Resources/luaScript/mainMenu.lua @@ -170,14 +170,15 @@ function CreateTestMenu() menuLayer:addChild(MainMenu) -- handling touch events - local function onTouchBegan(x, y) - BeginPos = {x = x, y = y} + local function onTouchBegan(touch, event) + BeginPos = touch:getLocation() -- CCTOUCHBEGAN event must return true return true end - local function onTouchMoved(x, y) - local nMoveY = y - BeginPos.y + local function onTouchMoved(touch, event) + local location = touch:getLocation() + local nMoveY = location.y - BeginPos.y local curPosx, curPosy = MainMenu:getPosition() local nextPosy = curPosy + nMoveY local winSize = cc.Director:getInstance():getWinSize() @@ -192,20 +193,15 @@ function CreateTestMenu() end MainMenu:setPosition(curPosx, nextPosy) - BeginPos = {x = x, y = y} + BeginPos = {x = location.x, y = location.y} CurPos = {x = curPosx, y = nextPosy} end - local function onTouch(eventType, x, y) - if eventType == "began" then - return onTouchBegan(x, y) - elseif eventType == "moved" then - return onTouchMoved(x, y) - end - end - - menuLayer:setTouchEnabled(true) - menuLayer:registerScriptTouchHandler(onTouch) + local listener = cc.EventListenerTouchOneByOne:create() + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN ) + listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED ) + local eventDispatcher = menuLayer:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, menuLayer) return menuLayer end From 1ff51b67f0072d221313704bccb5d6ceed987292 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Fri, 24 Jan 2014 09:48:39 +0800 Subject: [PATCH 16/51] issue #3822:Update the hellolua using the `EventListenerTouchOneByOne` --- samples/Lua/HelloLua/Resources/hello.lua | 42 +++++++++++------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/samples/Lua/HelloLua/Resources/hello.lua b/samples/Lua/HelloLua/Resources/hello.lua index 607b7d7508..2ca4b8310f 100644 --- a/samples/Lua/HelloLua/Resources/hello.lua +++ b/samples/Lua/HelloLua/Resources/hello.lua @@ -103,43 +103,39 @@ local function main() -- handing touch events local touchBeginPoint = nil - - local function onTouchBegan(x, y) - cclog("onTouchBegan: %0.2f, %0.2f", x, y) - touchBeginPoint = {x = x, y = y} + local function onTouchBegan(touch, event) + local location = touch:getLocation() + cclog("onTouchBegan: %0.2f, %0.2f", location.x, location.y) + touchBeginPoint = {x = location.x, y = location.y} spriteDog.isPaused = true -- CCTOUCHBEGAN event must return true return true end - local function onTouchMoved(x, y) - cclog("onTouchMoved: %0.2f, %0.2f", x, y) + local function onTouchMoved(touch, event) + local location = touch:getLocation() + cclog("onTouchMoved: %0.2f, %0.2f", location.x, location.y) if touchBeginPoint then local cx, cy = layerFarm:getPosition() - layerFarm:setPosition(cx + x - touchBeginPoint.x, - cy + y - touchBeginPoint.y) - touchBeginPoint = {x = x, y = y} + layerFarm:setPosition(cx + location.x - touchBeginPoint.x, + cy + location.y - touchBeginPoint.y) + touchBeginPoint = {x = location.x, y = location.y} end end - local function onTouchEnded(x, y) - cclog("onTouchEnded: %0.2f, %0.2f", x, y) + local function onTouchEnded(touch, event) + local location = touch:getLocation() + cclog("onTouchEnded: %0.2f, %0.2f", location.x, location.y) touchBeginPoint = nil spriteDog.isPaused = false end - local function onTouch(eventType, x, y) - if eventType == "began" then - return onTouchBegan(x, y) - elseif eventType == "moved" then - return onTouchMoved(x, y) - else - return onTouchEnded(x, y) - end - end - - layerFarm:registerScriptTouchHandler(onTouch) - layerFarm:setTouchEnabled(true) + local listener = cc.EventListenerTouchOneByOne:create() + listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN ) + listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED ) + listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED ) + local eventDispatcher = layerFarm:getEventDispatcher() + eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layerFarm) return layerFarm end From 490c85a388d362cf855eb27aab9ec28210ba1e78 Mon Sep 17 00:00:00 2001 From: lm Date: Fri, 24 Jan 2014 09:50:40 +0800 Subject: [PATCH 17/51] [Jenkins] add missing double quotes in pull-request-builder.py --- tools/jenkins-scripts/pull-request-builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/jenkins-scripts/pull-request-builder.py b/tools/jenkins-scripts/pull-request-builder.py index a88a21ec00..ae973987ac 100755 --- a/tools/jenkins-scripts/pull-request-builder.py +++ b/tools/jenkins-scripts/pull-request-builder.py @@ -113,7 +113,7 @@ def main(): elif(platform.system() == 'Windows'): os.chdir("tools/jenkins-scripts") os.system("gen_jsb_win32.bat") - os.chdir("../..) + os.chdir("../..") #make temp dir print "current dir is" + os.environ['WORKSPACE'] From 4bc00ba47af0b5d8eb03759ee434df73659a74b2 Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Fri, 24 Jan 2014 10:03:49 +0800 Subject: [PATCH 18/51] fix:Update some description --- docs/RELEASE_NOTES.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/RELEASE_NOTES.md b/docs/RELEASE_NOTES.md index 6ac6e83c83..59b4664eaa 100644 --- a/docs/RELEASE_NOTES.md +++ b/docs/RELEASE_NOTES.md @@ -671,7 +671,7 @@ Only have to write an ini file for a module, don't have to write a lot of .pkg f ### Bind the classes with namespace to lua -In previous, the lua binding can not bind classes that have the same class name but different namespaces. In order to resolve this issue, now the metatable name of a class is changed. For example, it will changed from CCNode to cc.Node. This modification will affect somewhere as follows: +In previous, the lua binding can not bind classes that have the same class name but different namespaces. In order to resolve this issue, now the metatable name of a class is changed. For example, `CCNode` will be changed to `cc.Node`. This modification will affect some APIs as follows: | v2.x | v3.0 | | tolua_usertype(tolua_S,"CCNode") | tolua_usertype(tolua_S,"cc.Node") | @@ -701,10 +701,10 @@ ScriptHandlerMgr:getInstance():registerScriptHandler(menuItem, luafunction,cc.HA ``` ### Use "cc"、"ccs"、"ccui" and "sp" as module name -The classes in the cocos2d、cocos2d::extension、CocosDenshion and cocosbuilder namespace were bound to lua in the "cc" module; -The classes in the cocos2d::gui namespace were bound to lua in the "ccui" module; -The classes in the spine namespace were bound to lua in the "sp" module; -The classes in the cocostudio namespace were bound to lua in the "ccs" module. +The classes in the `cocos2d`、`cocos2d::extension`、`CocosDenshion` and `cocosbuilder` namespace were bound to lua in the `cc` module; +The classes in the `cocos2d::gui` namespace were bound to lua in the `ccui` module; +The classes in the `spine` namespace were bound to lua in the `sp` module; +The classes in the `cocostudio` namespace were bound to lua in the `ccs` module. The main differences in the script are as follows: ```lua From 43ff0c42cf71a029329684082098c832b808ca75 Mon Sep 17 00:00:00 2001 From: andyque Date: Fri, 24 Jan 2014 11:05:34 +0800 Subject: [PATCH 19/51] fix a potential bug of CCSkin. It will cause the display of CCSkin wrongly. --- cocos/editor-support/cocostudio/CCSkin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos/editor-support/cocostudio/CCSkin.cpp b/cocos/editor-support/cocostudio/CCSkin.cpp index 440ce92159..e68239b803 100644 --- a/cocos/editor-support/cocostudio/CCSkin.cpp +++ b/cocos/editor-support/cocostudio/CCSkin.cpp @@ -216,7 +216,7 @@ kmMat4 Skin::getNodeToWorldTransformAR() const displayTransform.mat[12] = anchorPoint.x; displayTransform.mat[13] = anchorPoint.y; - return TransformConcat(displayTransform, _bone->getArmature()->getNodeToWorldTransform()); + return TransformConcat( _bone->getArmature()->getNodeToWorldTransform(),displayTransform); } void Skin::draw() From 8aaeb99f17eb7aa9e6b31335c475a79e719f704e Mon Sep 17 00:00:00 2001 From: minggo Date: Fri, 24 Jan 2014 11:36:52 +0800 Subject: [PATCH 20/51] [ci skip] --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 28128a54bd..9ecff80417 100644 --- a/AUTHORS +++ b/AUTHORS @@ -511,6 +511,7 @@ Developers: Lee, Jae-Hong (pyrasis) Maintainer of tizen port. localStorageGetItem crashes when column text is NULL. + fix image bug on Android lumendes Updating spine-runtime to EsotericSoftware/spine-runtimes@5f90386. From dfbb68a9e1c7d70a81a1b077a13921933e78da6b Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 11:37:23 +0800 Subject: [PATCH 21/51] Update CHANGELOG [ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 082522fd19..43610591d1 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,6 +18,7 @@ cocos2d-x-3.0beta2 ?.? ? [FIX] Removes unused files for MAC platform after using glfw3 to create opengl context. [FIX] Wrong arithmetic of child's position in ParallaxNode::addChild() [FIX] CocoStudio: TestColliderDetector in ArmatureTest can't work. + [FIX] CocoStudio: The order of transform calculation Skin::getNodeToWorldTransform() is incorrect. [FIX] Crash if file doesn't exist when using FileUtils::getStringFromFile. [FIX] If setting a shorter string than before while using LabelAtlas, the effect will be wrong. [FIX] Label: Crash when using unknown characters. From afd11b43a402dc2379b20cbbd1dcc40baf173dfe Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 11:37:46 +0800 Subject: [PATCH 22/51] Update CHANGELOG [ci skip] --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 43610591d1..638937d41f 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -18,7 +18,7 @@ cocos2d-x-3.0beta2 ?.? ? [FIX] Removes unused files for MAC platform after using glfw3 to create opengl context. [FIX] Wrong arithmetic of child's position in ParallaxNode::addChild() [FIX] CocoStudio: TestColliderDetector in ArmatureTest can't work. - [FIX] CocoStudio: The order of transform calculation Skin::getNodeToWorldTransform() is incorrect. + [FIX] CocoStudio: The order of transform calculation in Skin::getNodeToWorldTransform() is incorrect. [FIX] Crash if file doesn't exist when using FileUtils::getStringFromFile. [FIX] If setting a shorter string than before while using LabelAtlas, the effect will be wrong. [FIX] Label: Crash when using unknown characters. From 3d113e17094954600d84f683f7dccc87f1b0eb35 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 11:42:23 +0800 Subject: [PATCH 23/51] Update CHANGELOG [ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 638937d41f..ed57f190f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ cocos2d-x-3.0beta2 ?.? ? [NEW] Renderer: Added BatchCommand. This command is not "batchable" with other commands, but improves performance in about 10% [NEW] LuaBindings: Bindings-generator supports to bind namespace for lua. + [FIX] Uses EventDispatcher to access event in LUA testcase. [FIX] Exposes SAXParser class to JS, it is used for parsing XML in JS. [FIX] Uses unified `desktop/CCEGLView.h/cpp` for desktop platforms (windows, mac, linux). [FIX] Bindings-generator supports Windows again and remove dependency of LLVM since we only need binary(libclang.so/dll). From c6e709327008acaed74d3dd84ba743b117962844 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 11:50:58 +0800 Subject: [PATCH 24/51] closed #3833: SceneTest of CocoStudio crashes --- cocos/editor-support/cocostudio/CCSSceneReader.cpp | 8 ++++---- cocos/editor-support/cocostudio/TriggerObj.cpp | 2 -- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cocos/editor-support/cocostudio/CCSSceneReader.cpp b/cocos/editor-support/cocostudio/CCSSceneReader.cpp index e33c4ad86a..ba7818826b 100644 --- a/cocos/editor-support/cocostudio/CCSSceneReader.cpp +++ b/cocos/editor-support/cocostudio/CCSSceneReader.cpp @@ -144,10 +144,10 @@ Node* SceneReader::createObject(const rapidjson::Value &dict, cocos2d::Node* par { gb->addComponent(com); } - else - { - CC_SAFE_RELEASE_NULL(com); - } + else + { + com = nullptr; + } } if(_fnSelector != nullptr) { diff --git a/cocos/editor-support/cocostudio/TriggerObj.cpp b/cocos/editor-support/cocostudio/TriggerObj.cpp index 83d7bdcfbc..ffdfdfe48c 100644 --- a/cocos/editor-support/cocostudio/TriggerObj.cpp +++ b/cocos/editor-support/cocostudio/TriggerObj.cpp @@ -178,7 +178,6 @@ void TriggerObj::serialize(const rapidjson::Value &val) CCASSERT(con != nullptr, ""); con->serialize(subDict); con->init(); - con->autorelease(); _cons.pushBack(con); } @@ -199,7 +198,6 @@ void TriggerObj::serialize(const rapidjson::Value &val) } act->serialize(subDict); act->init(); - act->autorelease(); _acts.pushBack(act); } From aa8cfb5f04efb4991243fc8a2a6e677b62df68ed Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 11:58:09 +0800 Subject: [PATCH 25/51] Update CHANGELOG [ci skip] --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index ed57f190f9..92420af5cc 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,7 @@ cocos2d-x-3.0beta2 ?.? ? [FIX] If setting a shorter string than before while using LabelAtlas, the effect will be wrong. [FIX] Label: Crash when using unknown characters. [FIX] Label: Missing line breaks and wrong alignment. + [FIX] Label: Color and opacity settings aren't applied when invoking Label::alignText. [FIX] Console: log(format, va_args) is private to prevent possible resolution errors [FIX] Configuration: dumpInfo() -> getInfo() [FIX] ControlSlider doesn't support to set selected thumb sprite. From 8cf54d835d1c3b64458a4cb7d0aac198cd05bb63 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 11:59:36 +0800 Subject: [PATCH 26/51] Update AUTHORS [ci skip] --- AUTHORS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS b/AUTHORS index 9ecff80417..493859c5be 100644 --- a/AUTHORS +++ b/AUTHORS @@ -730,6 +730,9 @@ Developers: pandamicro Exposed SAXParser to JS, it is used for parsing XML in JS. + + hanjukim + Fixed a bug that color and opacity settings were not applied when invoking Label::alignText. Retired Core Developers: WenSheng Yang From 780740513823092c1ca31d202bdebad2811ef3dd Mon Sep 17 00:00:00 2001 From: lm Date: Fri, 24 Jan 2014 12:05:31 +0800 Subject: [PATCH 27/51] [Jenkins] fix the url of build description --- tools/jenkins-scripts/pull-request-builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/jenkins-scripts/pull-request-builder.py b/tools/jenkins-scripts/pull-request-builder.py index ae973987ac..f3ba3c1e5f 100755 --- a/tools/jenkins-scripts/pull-request-builder.py +++ b/tools/jenkins-scripts/pull-request-builder.py @@ -58,7 +58,7 @@ def main(): jenkins_url = os.environ['JENKINS_URL'] job_name = os.environ['JOB_NAME'].split('/')[0] build_number = os.environ['BUILD_NUMBER'] - target_url = jenkins_url + 'job/' + job_name + '/' + build_number + target_url = jenkins_url + 'job/' + job_name + '/' + build_number + '/' set_description(pr_desc, target_url) From 771ed300c43b4f7dcb35a40bddc787e851c60276 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Fri, 24 Jan 2014 14:04:08 +0800 Subject: [PATCH 28/51] close #3642:fix bounding box of new label is incorrect. --- cocos/2d/CCFontAtlas.cpp | 2 +- cocos/2d/CCLabelTextFormatter.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cocos/2d/CCFontAtlas.cpp b/cocos/2d/CCFontAtlas.cpp index be871fe15b..9010956c3d 100644 --- a/cocos/2d/CCFontAtlas.cpp +++ b/cocos/2d/CCFontAtlas.cpp @@ -152,7 +152,7 @@ bool FontAtlas::prepareLetterDefinitions(unsigned short *utf16String) tempDef.width = tempRect.size.width + _letterPadding; tempDef.height = tempRect.size.height + _letterPadding; tempDef.offsetX = tempRect.origin.x + offsetAdjust; - tempDef.offsetY = tempRect.origin.y - offsetAdjust; + tempDef.offsetY = _commonLineHeight + tempRect.origin.y - offsetAdjust; } fontDefs[utf16String[i]] = tempDef; } diff --git a/cocos/2d/CCLabelTextFormatter.cpp b/cocos/2d/CCLabelTextFormatter.cpp index 3d3e042130..0ed58fbce2 100644 --- a/cocos/2d/CCLabelTextFormatter.cpp +++ b/cocos/2d/CCLabelTextFormatter.cpp @@ -335,7 +335,14 @@ bool LabelTextFormatter::createStringSprites(Label *theLabel) // If the last character processed has an xAdvance which is less that the width of the characters image, then we need // to adjust the width of the string to take this into account, or the character will overlap the end of the bounding // box - tmpSize.width = longestLine - charAdvance + lastCharWidth; + if(charAdvance < lastCharWidth) + { + tmpSize.width = longestLine - charAdvance + lastCharWidth; + } + else + { + tmpSize.width = longestLine; + } tmpSize.height = totalHeight; theLabel->setContentSize(CC_SIZE_PIXELS_TO_POINTS(tmpSize)); From dffad2acd8dee282450c3c2426d24ae4747ba15a Mon Sep 17 00:00:00 2001 From: minggo Date: Fri, 24 Jan 2014 14:13:17 +0800 Subject: [PATCH 29/51] remove unneeded codes to fix running error --- .../multi-platform-js/Classes/AppDelegate.cpp | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/template/multi-platform-js/Classes/AppDelegate.cpp b/template/multi-platform-js/Classes/AppDelegate.cpp index e409b974b5..8e35153453 100644 --- a/template/multi-platform-js/Classes/AppDelegate.cpp +++ b/template/multi-platform-js/Classes/AppDelegate.cpp @@ -52,26 +52,6 @@ bool AppDelegate::applicationDidFinishLaunching() return true; } -void handle_signal(int signal) { - static int internal_state = 0; - ScriptingCore* sc = ScriptingCore::getInstance(); - // should start everything back - Director* director = Director::getInstance(); - if (director->getRunningScene()) { - director->popToRootScene(); - } else { - PoolManager::sharedPoolManager()->finalize(); - if (internal_state == 0) { - //sc->dumpRoot(NULL, 0, NULL); - sc->start(); - internal_state = 1; - } else { - sc->runScript("hello.js"); - internal_state = 0; - } - } -} - // This function will be called when the app is inactive. When comes a phone call,it's be invoked too void AppDelegate::applicationDidEnterBackground() { From ecdd742f57506c4fab661a4f5e72ff2501fe172f Mon Sep 17 00:00:00 2001 From: andyque Date: Fri, 24 Jan 2014 14:26:34 +0800 Subject: [PATCH 30/51] change include header file Application.h to cocos2d.h --- template/multi-platform-js/Classes/AppDelegate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template/multi-platform-js/Classes/AppDelegate.h b/template/multi-platform-js/Classes/AppDelegate.h index df8f12f70f..9a158eae61 100644 --- a/template/multi-platform-js/Classes/AppDelegate.h +++ b/template/multi-platform-js/Classes/AppDelegate.h @@ -9,7 +9,7 @@ #ifndef _APP_DELEGATE_H_ #define _APP_DELEGATE_H_ -#include "CCApplication.h" +#include "cocos2d.h" /** @brief The cocos2d Application. From 58f2f19008ea64217d20c0efa506e030c6cb0519 Mon Sep 17 00:00:00 2001 From: minggo Date: Fri, 24 Jan 2014 14:26:35 +0800 Subject: [PATCH 31/51] pause schedule after 3 seconds --- samples/Cpp/TestCpp/Classes/SchedulerTest/SchedulerTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/Cpp/TestCpp/Classes/SchedulerTest/SchedulerTest.cpp b/samples/Cpp/TestCpp/Classes/SchedulerTest/SchedulerTest.cpp index 96b32461d0..a7b1f6da48 100644 --- a/samples/Cpp/TestCpp/Classes/SchedulerTest/SchedulerTest.cpp +++ b/samples/Cpp/TestCpp/Classes/SchedulerTest/SchedulerTest.cpp @@ -160,7 +160,7 @@ void SchedulerPauseResume::onEnter() schedule(schedule_selector(SchedulerPauseResume::tick1), 0.5f); schedule(schedule_selector(SchedulerPauseResume::tick2), 0.5f); - schedule(schedule_selector(SchedulerPauseResume::pause), 0.5f); + schedule(schedule_selector(SchedulerPauseResume::pause), 3.0f); } void SchedulerPauseResume::tick1(float dt) From 232194646d8b403dc25324ca3117f194a5cbc05c Mon Sep 17 00:00:00 2001 From: lm Date: Fri, 24 Jan 2014 14:40:15 +0800 Subject: [PATCH 32/51] [Jenkins] add win32 build in pull-request-builder.py --- tools/jenkins-scripts/pull-request-builder.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/jenkins-scripts/pull-request-builder.py b/tools/jenkins-scripts/pull-request-builder.py index f3ba3c1e5f..7e536dd0a0 100755 --- a/tools/jenkins-scripts/pull-request-builder.py +++ b/tools/jenkins-scripts/pull-request-builder.py @@ -10,6 +10,7 @@ import requests import sys import traceback import platform +import subprocess #set Jenkins build description using submitDescription to mock browser behavior #TODO: need to set parent build description @@ -142,8 +143,12 @@ def main(): #TODO: add ios build #TODO: add mac build #TODO: add win32 build + node_name = os.environ['NODE_NAME'] if(branch == 'develop'): - ret = os.system("python build/android-build.py -n -j10 all") + if(node_name == 'android_mac') or (node_name == 'android_win7'): + ret = os.system("python build/android-build.py -n -j10 all") + elif(node_name == 'win32_win7'): + ret = subprocess.call('"%VS110COMNTOOLS%..\IDE\devenv.com" "build\cocos2d-win32.vc2012.sln" /Build "Debug|Win32"', shell=True) elif(branch == 'master'): ret = os.system("samples/Cpp/TestCpp/proj.android/build_native.sh") From 3aedb8ec434117cd274395ab99cf324e8ca61918 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 14:46:06 +0800 Subject: [PATCH 33/51] issue #3713: Object::release() of debug version will check whether the object was in autorelease pool. --- cocos/base/CCAutoreleasePool.cpp | 43 ++++++++++++++++++++++++------ cocos/base/CCAutoreleasePool.h | 13 ++++++++- cocos/base/CCObject.cpp | 45 ++++++++++++++++++++++++++++++++ cocos/base/CCObject.h | 7 ++--- 4 files changed, 96 insertions(+), 12 deletions(-) diff --git a/cocos/base/CCAutoreleasePool.cpp b/cocos/base/CCAutoreleasePool.cpp index f841590f07..77cf41f0fe 100644 --- a/cocos/base/CCAutoreleasePool.cpp +++ b/cocos/base/CCAutoreleasePool.cpp @@ -28,14 +28,16 @@ THE SOFTWARE. NS_CC_BEGIN AutoreleasePool::AutoreleasePool() -:_name("") +: _name("") +, _isInClear(false) { _managedObjectArray.reserve(150); PoolManager::getInstance()->push(this); } AutoreleasePool::AutoreleasePool(const std::string &name) -:_name(name) +: _name(name) +, _isInClear(false) { _managedObjectArray.reserve(150); PoolManager::getInstance()->push(this); @@ -56,11 +58,26 @@ void AutoreleasePool::addObject(Object* object) void AutoreleasePool::clear() { + _isInClear = true; for (const auto &obj : _managedObjectArray) { obj->release(); } _managedObjectArray.clear(); + _isInClear = false; +} + +bool AutoreleasePool::contains(Object* object) const +{ + if (_isInClear) + return false; + + for (const auto& obj : _managedObjectArray) + { + if (obj == object) + return true; + } + return false; } void AutoreleasePool::dump() @@ -89,7 +106,7 @@ PoolManager* PoolManager::getInstance() s_singleInstance = new PoolManager(); // Add the first auto release pool s_singleInstance->_curReleasePool = new AutoreleasePool("cocos2d autorelease pool"); - s_singleInstance->_releasePoolStack.push(s_singleInstance->_curReleasePool); + s_singleInstance->_releasePoolStack.push_back(s_singleInstance->_curReleasePool); } return s_singleInstance; } @@ -110,8 +127,8 @@ PoolManager::~PoolManager() while (!_releasePoolStack.empty()) { - AutoreleasePool* pool = _releasePoolStack.top(); - _releasePoolStack.pop(); + AutoreleasePool* pool = _releasePoolStack.back(); + _releasePoolStack.pop_back(); delete pool; } @@ -123,9 +140,19 @@ AutoreleasePool* PoolManager::getCurrentPool() const return _curReleasePool; } +bool PoolManager::isObjectInPools(Object* obj) const +{ + for (const auto& pool : _releasePoolStack) + { + if (pool->contains(obj)) + return true; + } + return false; +} + void PoolManager::push(AutoreleasePool *pool) { - _releasePoolStack.push(pool); + _releasePoolStack.push_back(pool); _curReleasePool = pool; } @@ -134,12 +161,12 @@ void PoolManager::pop() // Can not pop the pool that created by engine CC_ASSERT(_releasePoolStack.size() >= 1); - _releasePoolStack.pop(); + _releasePoolStack.pop_back(); // Should update _curReleasePool if a temple pool is released if (_releasePoolStack.size() > 1) { - _curReleasePool = _releasePoolStack.top(); + _curReleasePool = _releasePoolStack.back(); } } diff --git a/cocos/base/CCAutoreleasePool.h b/cocos/base/CCAutoreleasePool.h index 0415eb713e..0146cbd962 100644 --- a/cocos/base/CCAutoreleasePool.h +++ b/cocos/base/CCAutoreleasePool.h @@ -81,6 +81,11 @@ public: */ void clear(); + /** + * Checks whether the pool contains the specified object. + */ + bool contains(Object* object) const; + /** * Dump the objects that are put into autorelease pool. It is used for debugging. * @@ -102,6 +107,11 @@ private: */ std::vector _managedObjectArray; std::string _name; + + /** + * The flag for checking whether Object::release() is invoked in AutoreleasePool::clear(). + */ + bool _isInClear; }; class CC_DLL PoolManager @@ -127,6 +137,7 @@ public: */ AutoreleasePool *getCurrentPool() const; + bool isObjectInPools(Object* obj) const; /** * @js NA * @lua NA @@ -142,7 +153,7 @@ private: static PoolManager* s_singleInstance; - std::stack _releasePoolStack; + std::deque _releasePoolStack; AutoreleasePool *_curReleasePool; }; diff --git a/cocos/base/CCObject.cpp b/cocos/base/CCObject.cpp index dcbf8a6b62..9e582d95bf 100644 --- a/cocos/base/CCObject.cpp +++ b/cocos/base/CCObject.cpp @@ -63,6 +63,51 @@ Object* Object::autorelease() return this; } + +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) +void Object::release() +{ + CCASSERT(_referenceCount > 0, "reference count should greater than 0"); + --_referenceCount; + + if (_referenceCount == 0) + { + if (PoolManager::getInstance()->isObjectInPools(this)) + { + // Trigger an assert if the reference count is 0 but the object is still in autorelease pool. + // This happens when 'autorelease/release' were not used in pairs with 'new/retain'. + // + // Wrong usage (1): + // + // auto obj = Node::create(); // Ref = 1, but it's an autorelease object which means it was in the autorelease pool. + // obj->autorelease(); // Wrong: If you wish to invoke autorelease several times, you should retain `obj` first. + // + // Wrong usage (2): + // + // auto obj = Node::create(); + // obj->release(); // Wrong: obj is an autorelease object, it will be released when clearing current pool. + // + // Correct usage (1): + // + // auto obj = Node::create(); + // |- new Node(); // `new` is the pair of the `autorelease` of next line + // |- autorelease(); // The pair of `new Node`. + // + // obj->retain(); + // obj->autorelease(); // This `autorelease` is the pair of `retain` of previous line. + // + // Corrent usage (2): + // + // auto obj = Node::create(); + // obj->retain(); + // obj->release(); // This `release` is the pair of `retain` of previous line. + CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool."); + } + delete this; + } +} +#endif + bool Object::isSingleReference() const { return _referenceCount == 1; diff --git a/cocos/base/CCObject.h b/cocos/base/CCObject.h index b9e1250cb7..01eb976e32 100644 --- a/cocos/base/CCObject.h +++ b/cocos/base/CCObject.h @@ -103,15 +103,16 @@ public: * @see retain, autorelease * @js NA */ +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) + void release(); +#else inline void release() { - CCASSERT(_referenceCount > 0, "reference count should greater than 0"); --_referenceCount; - if (_referenceCount == 0) delete this; } - +#endif /** * Retains the ownership. * From 0ec70678e0d382d1fa61bfd66ea2f1668d1a7f2a Mon Sep 17 00:00:00 2001 From: minggo Date: Fri, 24 Jan 2014 14:48:07 +0800 Subject: [PATCH 34/51] fix crash of PerformanceTest --- .../Cpp/TestCpp/Classes/PerformanceTest/PerformanceAllocTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceAllocTest.cpp b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceAllocTest.cpp index f14ca83fac..cf1f0a1859 100644 --- a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceAllocTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceAllocTest.cpp @@ -292,6 +292,7 @@ void NodeDeallocTest::update(float dt) for( int i=0; iretain(); } CC_PROFILER_START(this->profilerName()); From f1ffb0b753e66779d8f3caffc6c68b40c4b6763e Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 15:02:14 +0800 Subject: [PATCH 35/51] [JSB] cc.Node.setLocalZOrder -> cc.Node.setZOrder. --- tools/tojs/cocos2dx.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tojs/cocos2dx.ini b/tools/tojs/cocos2dx.ini index 3aaf19bdea..32ed7f22ff 100644 --- a/tools/tojs/cocos2dx.ini +++ b/tools/tojs/cocos2dx.ini @@ -119,7 +119,7 @@ rename_functions = SpriteFrameCache::[addSpriteFramesWithFile=addSpriteFrames ge LayerGradient::[initWithColor=init], LayerColor::[initWithColor=init], GLProgram::[initWithVertexShaderByteArray=initWithString initWithVertexShaderFilename=init programLog=getProgramLog setUniformLocationWith1i=setUniformLocationI32], - Node::[removeFromParentAndCleanup=removeFromParent removeAllChildrenWithCleanup=removeAllChildren getLocalZOrder=getZOrder], + Node::[removeFromParentAndCleanup=removeFromParent removeAllChildrenWithCleanup=removeAllChildren getLocalZOrder=getZOrder setLocalZOrder=setZOrder], LabelAtlas::[create=_create], Sprite::[initWithFile=init], SpriteBatchNode::[initWithFile=init removeAllChildrenWithCleanup=removeAllChildren], From 412e875446bb617065a47a3932a6a21e470f4b4c Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Fri, 24 Jan 2014 15:02:42 +0800 Subject: [PATCH 36/51] update label test case. --- .../TestCpp/Classes/LabelTest/LabelTest.cpp | 6 +- .../Classes/LabelTest/LabelTestNew.cpp | 183 ++++++++++++------ .../TestCpp/Classes/LabelTest/LabelTestNew.h | 17 ++ 3 files changed, 146 insertions(+), 60 deletions(-) diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp index e09dc7f4fc..416d928ea5 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTest.cpp @@ -419,7 +419,11 @@ Atlas3::Atlas3() label2->setAnchorPoint( Point(0.5f, 0.5f) ); label2->setColor( Color3B::RED ); addChild(label2, 0, kTagBitmapAtlas2); - label2->runAction( repeat->clone() ); + auto tint = Sequence::create(TintTo::create(1, 255, 0, 0), + TintTo::create(1, 0, 255, 0), + TintTo::create(1, 0, 0, 255), + NULL); + label2->runAction( RepeatForever::create(tint) ); auto label3 = LabelBMFont::create("Test", "fonts/bitmapFontTest2.fnt"); // testing anchors diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp index 432fb99cd1..e0ee9e3a5a 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.cpp @@ -68,6 +68,7 @@ static std::function createFunctions[] = CL(LabelTTFDistanceField), CL(LabelTTFDistanceFieldEffect), CL(LabelCharMapTest), + CL(LabelCharMapColorTest), CL(LabelCrashTest), CL(LabelTTFOldNew) }; @@ -165,17 +166,17 @@ LabelTTFAlignmentNew::LabelTTFAlignmentNew() auto ttf0 = Label::createWithTTF(config,"Alignment 0\nnew line",TextHAlignment::LEFT); ttf0->setPosition(Point(s.width/2,(s.height/6)*2 - 30)); - ttf0->setAnchorPoint(Point(0.5f,0.5f)); + ttf0->setAnchorPoint(Point::ANCHOR_MIDDLE); this->addChild(ttf0); auto ttf1 = Label::createWithTTF(config,"Alignment 1\nnew line",TextHAlignment::CENTER); ttf1->setPosition(Point(s.width/2,(s.height/6)*3 - 30)); - ttf1->setAnchorPoint(Point(0.5f,0.5f)); + ttf1->setAnchorPoint(Point::ANCHOR_MIDDLE); this->addChild(ttf1); auto ttf2 = Label::createWithTTF(config,"Alignment 2\nnew line",TextHAlignment::RIGHT); ttf2->setPosition(Point(s.width/2,(s.height/6)*4 - 30)); - ttf2->setAnchorPoint(Point(0.5f,0.5f)); + ttf2->setAnchorPoint(Point::ANCHOR_MIDDLE); this->addChild(ttf2); } @@ -207,10 +208,14 @@ LabelFNTColorAndOpacity::LabelFNTColorAndOpacity() label1->runAction(repeat); auto label2 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test"); - label2->setAnchorPoint( Point(0.5f, 0.5f) ); + label2->setAnchorPoint( Point::ANCHOR_MIDDLE ); label2->setColor( Color3B::RED ); addChild(label2, 0, kTagBitmapAtlas2); - label2->runAction( repeat->clone() ); + auto tint = Sequence::create(TintTo::create(1, 255, 0, 0), + TintTo::create(1, 0, 255, 0), + TintTo::create(1, 0, 0, 255), + NULL); + label2->runAction( RepeatForever::create(tint) ); auto label3 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Test"); label3->setAnchorPoint( Point(1,1) ); @@ -260,7 +265,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions() auto s = Director::getInstance()->getWinSize(); label->setPosition( Point(s.width/2, s.height/2) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ); + label->setAnchorPoint( Point::ANCHOR_MIDDLE ); auto BChar = (Sprite*) label->getLetter(0); @@ -294,6 +299,7 @@ LabelFNTSpriteActions::LabelFNTSpriteActions() auto label2 = Label::createWithBMFont("fonts/bitmapFontTest.fnt", "00.0"); addChild(label2, 0, kTagBitmapAtlas2); label2->setPosition( Point(s.width/2.0f, 80) ); + label2->setAnchorPoint( Point::ANCHOR_MIDDLE ); auto lastChar = (Sprite*) label2->getLetter(3); lastChar->runAction( rot_4ever->clone() ); @@ -349,7 +355,7 @@ LabelFNTPadding::LabelFNTPadding() auto s = Director::getInstance()->getWinSize(); label->setPosition( Point(s.width/2, s.height/2) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ); + label->setAnchorPoint( Point::ANCHOR_MIDDLE ); } std::string LabelFNTPadding::title() const @@ -370,17 +376,17 @@ LabelFNTOffset::LabelFNTOffset() label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "FaFeFiFoFu"); addChild(label); label->setPosition( Point(s.width/2, s.height/2+50) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ) ; + label->setAnchorPoint( Point::ANCHOR_MIDDLE ) ; label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "fafefifofu"); addChild(label); label->setPosition( Point(s.width/2, s.height/2) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ); + label->setAnchorPoint( Point::ANCHOR_MIDDLE ); label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "aeiou"); addChild(label); label->setPosition( Point(s.width/2, s.height/2-50) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ); + label->setAnchorPoint( Point::ANCHOR_MIDDLE ); } std::string LabelFNTOffset::title() const @@ -402,18 +408,18 @@ LabelFNTColor::LabelFNTColor() label->setColor( Color3B::BLUE ); addChild(label); label->setPosition( Point(s.width/2, s.height/4) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ); + label->setAnchorPoint( Point::ANCHOR_MIDDLE ); label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Red"); addChild(label); label->setPosition( Point(s.width/2, 2*s.height/4) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ); + label->setAnchorPoint( Point::ANCHOR_MIDDLE ); label->setColor( Color3B::RED ); label = Label::createWithBMFont("fonts/bitmapFontTest5.fnt", "Green"); addChild(label); label->setPosition( Point(s.width/2, 3*s.height/4) ); - label->setAnchorPoint( Point(0.5f, 0.5f) ); + label->setAnchorPoint( Point::ANCHOR_MIDDLE ); label->setColor( Color3B::GREEN ); label->setString("Green"); } @@ -442,7 +448,7 @@ LabelFNTHundredLabels::LabelFNTHundredLabels() auto p = Point( CCRANDOM_0_1() * s.width, CCRANDOM_0_1() * s.height); label->setPosition( p ); - label->setAnchorPoint(Point(0.5f, 0.5f)); + label->setAnchorPoint(Point::ANCHOR_MIDDLE); } } @@ -471,7 +477,7 @@ LabelFNTMultiLine::LabelFNTMultiLine() // Center auto label2 = Label::createWithBMFont( "fonts/bitmapFontTest3.fnt", "Multi line\nCenter"); - label2->setAnchorPoint(Point(0.5f, 0.5f)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label2, 0, kTagBitmapAtlas2); s= label2->getContentSize(); @@ -503,20 +509,24 @@ std::string LabelFNTMultiLine::subtitle() const LabelFNTandTTFEmpty::LabelFNTandTTFEmpty() { auto s = Director::getInstance()->getWinSize(); - float delta = s.height/4; // LabelBMFont auto label1 = Label::createWithBMFont("fonts/bitmapFontTest3.fnt", "", TextHAlignment::CENTER, s.width); addChild(label1, 0, kTagBitmapAtlas1); - label1->setAnchorPoint(Point(0.5f, 0.5f)); - label1->setPosition(Point(s.width/2, delta)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); + label1->setPosition(Point(s.width/2, s.height - 100)); // LabelTTF TTFConfig ttfConfig("fonts/arial.ttf",48); auto label2 = Label::createWithTTF(ttfConfig,"", TextHAlignment::CENTER,s.width); addChild(label2, 0, kTagBitmapAtlas2); - label2->setAnchorPoint(Point(0.5f, 0.5f)); - label2->setPosition(Point(s.width/2, delta * 2)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); + label2->setPosition(Point(s.width/2, s.height / 2)); + + auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' '); + label3->setAnchorPoint(Point::ANCHOR_MIDDLE); + addChild(label3, 0, kTagBitmapAtlas3); + label3->setPosition(Point(s.width/2, 100)); schedule(schedule_selector(LabelFNTandTTFEmpty::updateStrings), 1.0f); @@ -527,11 +537,13 @@ void LabelFNTandTTFEmpty::updateStrings(float dt) { auto label1 = static_cast( getChildByTag(kTagBitmapAtlas1) ); auto label2 = static_cast( getChildByTag(kTagBitmapAtlas2) ); + auto label3 = static_cast( getChildByTag(kTagBitmapAtlas3) ); if( ! setEmpty ) { label1->setString("not empty"); label2->setString("not empty"); + label3->setString("hi"); setEmpty = true; } @@ -539,6 +551,7 @@ void LabelFNTandTTFEmpty::updateStrings(float dt) { label1->setString(""); label2->setString(""); + label3->setString(""); setEmpty = false; } @@ -551,7 +564,7 @@ std::string LabelFNTandTTFEmpty::title() const std::string LabelFNTandTTFEmpty::subtitle() const { - return "2 empty labels: new Label + .FNT and new Label + .TTF"; + return "3 empty labels: new Label + FNT/TTF/CharMap"; } LabelFNTRetina::LabelFNTRetina() @@ -560,7 +573,7 @@ LabelFNTRetina::LabelFNTRetina() // LabelBMFont auto label1 = Label::createWithBMFont("fonts/konqa32.fnt", "TESTING RETINA DISPLAY"); - label1->setAnchorPoint(Point(0.5f, 0.5f)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); label1->setPosition(Point(s.width/2, s.height/2)); } @@ -584,7 +597,7 @@ LabelFNTGlyphDesigner::LabelFNTGlyphDesigner() // LabelBMFont auto label1 = Label::createWithBMFont("fonts/futura-48.fnt", "Testing Glyph Designer"); - label1->setAnchorPoint(Point(0.5f, 0.5f)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); label1->setPosition(Point(s.width/2, s.height/2)); } @@ -606,7 +619,7 @@ LabelTTFUnicodeChinese::LabelTTFUnicodeChinese() // like "Error 3 error C2146: syntax error : missing ')' before identifier 'label'"; TTFConfig ttfConfig("fonts/wt021.ttf",55,GlyphCollection::CUSTOM, "美好的一天啊"); auto label = Label::createWithTTF(ttfConfig,"美好的一天啊", TextHAlignment::CENTER, size.width); - label->setAnchorPoint(Point(0.5f, 0.5f)); + label->setAnchorPoint(Point::ANCHOR_MIDDLE); label->setPosition(Point(size.width / 2, size.height /2)); this->addChild(label); } @@ -625,7 +638,7 @@ LabelFNTUnicodeChinese::LabelFNTUnicodeChinese() { auto size = Director::getInstance()->getWinSize(); auto label = Label::createWithBMFont("fonts/bitmapFontChinese.fnt", "中国"); - label->setAnchorPoint(Point(0.5f, 0.5f)); + label->setAnchorPoint(Point::ANCHOR_MIDDLE); label->setPosition(Point(size.width / 2, size.height /2)); this->addChild(label); } @@ -674,7 +687,7 @@ LabelFNTMultiLineAlignment::LabelFNTMultiLineAlignment() // create and initialize a Label this->_labelShouldRetain = Label::createWithBMFont("fonts/markerFelt.fnt", LongSentencesExample, TextHAlignment::CENTER, size.width/1.5); - this->_labelShouldRetain->setAnchorPoint(Point(0.5f, 0.5f)); + this->_labelShouldRetain->setAnchorPoint(Point::ANCHOR_MIDDLE); this->_labelShouldRetain->retain(); this->_arrowsBarShouldRetain = Sprite::create("Images/arrowsBar.png"); @@ -858,22 +871,22 @@ LabelFNTUNICODELanguages::LabelFNTUNICODELanguages() auto label1 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", spanish, TextHAlignment::CENTER, 200); addChild(label1); - label1->setAnchorPoint(Point(0.5f, 0.5f)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); label1->setPosition(Point(s.width/2, s.height/5*3)); auto label2 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", chinese); addChild(label2); - label2->setAnchorPoint(Point(0.5f, 0.5f)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); label2->setPosition(Point(s.width/2, s.height/5*2.5)); auto label3 = Label::createWithBMFont("fonts/arial-26-en-ru.fnt", russian); addChild(label3); - label3->setAnchorPoint(Point(0.5f, 0.5f)); + label3->setAnchorPoint(Point::ANCHOR_MIDDLE); label3->setPosition(Point(s.width/2, s.height/5*2)); auto label4 = Label::createWithBMFont("fonts/arial-unicode-26.fnt", japanese); addChild(label4); - label4->setAnchorPoint(Point(0.5f, 0.5f)); + label4->setAnchorPoint(Point::ANCHOR_MIDDLE); label4->setPosition(Point(s.width/2, s.height/5*1.5)); } @@ -896,7 +909,7 @@ LabelFNTBounds::LabelFNTBounds() // LabelBMFont label1 = Label::createWithBMFont("fonts/boundsTestFont.fnt", "Testing Glyph Designer", TextHAlignment::CENTER, s.width); - label1->setAnchorPoint(Point(0.5f, 0.5f)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); label1->setPosition(Point(s.width/2, s.height/2)); } @@ -973,21 +986,21 @@ LabelTTFColor::LabelTTFColor() auto label1 = Label::createWithTTF(ttfConfig,"Green", TextHAlignment::CENTER, size.width); label1->setPosition( Point(size.width/2, size.height/5 * 1.5) ); label1->setColor( Color3B::GREEN ); - label1->setAnchorPoint(Point(0.5, 0.5)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); // Red auto label2 = Label::createWithTTF(ttfConfig,"Red", TextHAlignment::CENTER, size.width); label2->setPosition( Point(size.width/2, size.height/5 * 2.0) ); label2->setColor( Color3B::RED ); - label2->setAnchorPoint(Point(0.5, 0.5)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label2); // Blue auto label3 = Label::createWithTTF(ttfConfig,"Blue", TextHAlignment::CENTER, size.width); label3->setPosition( Point(size.width/2, size.height/5 * 2.5) ); label3->setColor( Color3B::BLUE ); - label3->setAnchorPoint(Point(0.5, 0.5)); + label3->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label3); } @@ -1007,7 +1020,7 @@ LabelTTFDynamicAlignment::LabelTTFDynamicAlignment() TTFConfig ttfConfig("fonts/arial.ttf", 45); _label = Label::createWithTTF(ttfConfig,LongSentencesExample, TextHAlignment::CENTER, size.width); _label->setPosition( Point(size.width/2, size.height/2) ); - _label->setAnchorPoint(Point(0.5, 0.5)); + _label->setAnchorPoint(Point::ANCHOR_MIDDLE); auto menu = Menu::create( MenuItemFont::create("Left", CC_CALLBACK_1(LabelTTFDynamicAlignment::setAlignmentLeft, this)), @@ -1079,13 +1092,13 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew() // Spanish auto label1 = Label::createWithTTF(ttfConfig,"Buen día, ¿cómo te llamas?", TextHAlignment::CENTER, size.width); label1->setPosition( Point(size.width/2, vSize - (vStep * 4.5)) ); - label1->setAnchorPoint(Point(0.5, 0.5)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); // German auto label2 = Label::createWithTTF(ttfConfig,"In welcher Straße haben Sie gelebt?", TextHAlignment::CENTER,size.width); label2->setPosition( Point(size.width/2, vSize - (vStep * 5.5)) ); - label2->setAnchorPoint(Point(0.5, 0.5)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label2); // chinese @@ -1094,7 +1107,7 @@ LabelTTFUnicodeNew::LabelTTFUnicodeNew() ttfConfig.customGlyphs = chinese.c_str(); auto label3 = Label::createWithTTF(ttfConfig,chinese, TextHAlignment::CENTER,size.width); label3->setPosition( Point(size.width/2, vSize - (vStep * 6.5)) ); - label3->setAnchorPoint(Point(0.5, 0.5)); + label3->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label3); } @@ -1131,7 +1144,7 @@ LabelTTFFontsTestNew::LabelTTFFontsTestNew() label->setPosition( Point(size.width/2, ((size.height * 0.6)/arraysize(ttfpaths) * i) + (size.height/5))); addChild(label); - label->setAnchorPoint(Point(0.5, 0.5)); + label->setAnchorPoint(Point::ANCHOR_MIDDLE); } else { log("ERROR: Cannot load: %s", ttfpaths[i]); } @@ -1154,7 +1167,7 @@ LabelBMFontTestNew::LabelBMFontTestNew() auto label1 = Label::createWithBMFont("fonts/bitmapFontTest2.fnt", "Hello World, this is testing the new Label using fnt file", TextHAlignment::CENTER, size.width); label1->setPosition( Point(size.width/2, size.height/2) ); - label1->setAnchorPoint(Point(0.5, 0.5)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); } @@ -1174,9 +1187,9 @@ LabelTTFDistanceField::LabelTTFDistanceField() TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true); auto label1 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width); - label1->setPosition( Point(size.width/2, size.height/2) ); + label1->setPosition( Point(size.width/2, size.height * 0.6f) ); label1->setColor( Color3B::GREEN ); - label1->setAnchorPoint(Point(0.5, 0.5)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); auto action = Sequence::create( @@ -1187,9 +1200,9 @@ LabelTTFDistanceField::LabelTTFDistanceField() label1->runAction(RepeatForever::create(action)); auto label2 = Label::createWithTTF(ttfConfig,"Distance Field",TextHAlignment::CENTER,size.width); - label2->setPosition( Point(size.width/2, size.height/5) ); + label2->setPosition( Point(size.width/2, size.height * 0.3f) ); label2->setColor( Color3B::RED ); - label2->setAnchorPoint(Point(0.5, 0.5)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label2); } @@ -1214,23 +1227,23 @@ LabelTTFDistanceFieldEffect::LabelTTFDistanceFieldEffect() TTFConfig ttfConfig("fonts/arial.ttf", 80, GlyphCollection::DYNAMIC,nullptr,true); auto label1 = Label::createWithTTF(ttfConfig,"Glow", TextHAlignment::CENTER, size.width); - label1->setPosition( Point(size.width/2, size.height*0.5) ); + label1->setPosition( Point(size.width/2, size.height*0.65) ); label1->setColor( Color3B::GREEN ); - label1->setAnchorPoint(Point(0.5, 0.5)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); label1->setLabelEffect(LabelEffect::GLOW,Color3B::YELLOW); addChild(label1); auto label2 = Label::createWithTTF(ttfConfig,"Outline", TextHAlignment::CENTER, size.width); - label2->setPosition( Point(size.width/2, size.height*0.375) ); + label2->setPosition( Point(size.width/2, size.height*0.5) ); label2->setColor( Color3B::RED ); - label2->setAnchorPoint(Point(0.5, 0.5)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); label2->setLabelEffect(LabelEffect::OUTLINE,Color3B::BLUE); addChild(label2); auto label3 = Label::createWithTTF(ttfConfig,"Shadow", TextHAlignment::CENTER, size.width); - label3->setPosition( Point(size.width/2, size.height*0.25f) ); + label3->setPosition( Point(size.width/2, size.height*0.35f) ); label3->setColor( Color3B::RED ); - label3->setAnchorPoint(Point(0.5, 0.5)); + label3->setAnchorPoint(Point::ANCHOR_MIDDLE); label3->setLabelEffect(LabelEffect::SHADOW,Color3B::BLACK); addChild(label3); @@ -1257,14 +1270,9 @@ LabelCharMapTest::LabelCharMapTest() auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.plist"); addChild(label2, 0, kTagSprite2); - label2->setPosition( Point(10,160) ); + label2->setPosition( Point(10,200) ); label2->setOpacity( 32 ); - auto label3 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' '); - label3->setString("123 Test"); - addChild(label3, 0, kTagSprite3); - label3->setPosition( Point(10,220) ); - schedule(schedule_selector(LabelCharMapTest::step)); } @@ -1292,6 +1300,63 @@ std::string LabelCharMapTest::subtitle() const return "Updating label should be fast."; } +//------------------------------------------------------------------ +// +// LabelCharMapColorTest +// +//------------------------------------------------------------------ +LabelCharMapColorTest::LabelCharMapColorTest() +{ + auto label1 = Label::createWithCharMap( "fonts/tuffy_bold_italic-charmap.png", 48, 64, ' '); + addChild(label1, 0, kTagSprite1); + label1->setPosition( Point(10,100) ); + label1->setOpacity( 200 ); + + auto label2 = Label::createWithCharMap("fonts/tuffy_bold_italic-charmap.png", 48, 64, ' '); + addChild(label2, 0, kTagSprite2); + label2->setPosition( Point(10,200) ); + label2->setColor( Color3B::RED ); + + auto fade = FadeOut::create(1.0f); + auto fade_in = fade->reverse(); + auto cb = CallFunc::create(CC_CALLBACK_0(LabelCharMapColorTest::actionFinishCallback, this)); + auto seq = Sequence::create(fade, fade_in, cb, NULL); + auto repeat = RepeatForever::create( seq ); + label2->runAction( repeat ); + + _time = 0; + + schedule( schedule_selector(LabelCharMapColorTest::step) ); //:@selector(step:)]; +} + +void LabelCharMapColorTest::actionFinishCallback() +{ + CCLOG("Action finished"); +} + +void LabelCharMapColorTest::step(float dt) +{ + _time += dt; + char string[12] = {0}; + sprintf(string, "%2.2f Test", _time); + auto label1 = (Label*)getChildByTag(kTagSprite1); + label1->setString(string); + + auto label2 = (Label*)getChildByTag(kTagSprite2); + sprintf(string, "%d", (int)_time); + label2->setString( string ); +} + +std::string LabelCharMapColorTest::title() const +{ + return "New Label + CharMap"; +} + +std::string LabelCharMapColorTest::subtitle() const +{ + return "Opacity + Color should work at the same time"; +} + LabelCrashTest::LabelCrashTest() { auto size = Director::getInstance()->getWinSize(); @@ -1300,7 +1365,7 @@ LabelCrashTest::LabelCrashTest() auto label1 = Label::createWithTTF(ttfConfig,"Test崩溃123", TextHAlignment::CENTER, size.width); label1->setPosition( Point(size.width/2, size.height/2) ); - label1->setAnchorPoint(Point(0.5, 0.5)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); addChild(label1); } @@ -1321,14 +1386,14 @@ LabelTTFOldNew::LabelTTFOldNew() auto label1 = LabelTTF::create("Cocos2d-x Label Test", "arial", 24); addChild(label1, 0, kTagBitmapAtlas1); - label1->setAnchorPoint(Point(0.5f, 0.5f)); + label1->setAnchorPoint(Point::ANCHOR_MIDDLE); label1->setPosition(Point(s.width/2, delta * 2)); label1->setColor(Color3B::RED); TTFConfig ttfConfig("fonts/arial.ttf", 48); auto label2 = Label::createWithTTF(ttfConfig, "Cocos2d-x Label Test"); addChild(label2, 0, kTagBitmapAtlas2); - label2->setAnchorPoint(Point(0.5f, 0.5f)); + label2->setAnchorPoint(Point::ANCHOR_MIDDLE); label2->setPosition(Point(s.width/2, delta * 2)); } diff --git a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h index ccd52f8d07..3d5e99f368 100644 --- a/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h +++ b/samples/Cpp/TestCpp/Classes/LabelTest/LabelTestNew.h @@ -363,6 +363,23 @@ private: float _time; }; +class LabelCharMapColorTest : public AtlasDemoNew +{ +public: + CREATE_FUNC(LabelCharMapColorTest); + + LabelCharMapColorTest(); + + virtual std::string title() const override; + virtual std::string subtitle() const override; + + void step(float dt); + void actionFinishCallback(); + +private: + float _time; +}; + class LabelCrashTest : public AtlasDemoNew { public: From ac59d259a1a30e268395112bb16127ea577841e0 Mon Sep 17 00:00:00 2001 From: "Huabing.Xu" Date: Fri, 24 Jan 2014 15:14:34 +0800 Subject: [PATCH 37/51] 3.0 Beta2 HotFix: remove Camera Zoom Test temporarily. --- samples/Cpp/TestCpp/Classes/NodeTest/NodeTest.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/samples/Cpp/TestCpp/Classes/NodeTest/NodeTest.cpp b/samples/Cpp/TestCpp/Classes/NodeTest/NodeTest.cpp index c4c1399b21..381b2728fc 100644 --- a/samples/Cpp/TestCpp/Classes/NodeTest/NodeTest.cpp +++ b/samples/Cpp/TestCpp/Classes/NodeTest/NodeTest.cpp @@ -63,7 +63,9 @@ static std::function createFunctions[] = CL(NodeToWorld3D), CL(SchedulerTest1), CL(CameraOrbitTest), - CL(CameraZoomTest), + //Camera has been removed from CCNode + //todo add new feature to support it + //CL(CameraZoomTest), CL(ConvertToNode), CL(NodeOpaqueTest), CL(NodeNonOpaqueTest), From 43ef9051a32c590ad7f0f5c83122118b893c2500 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Fri, 24 Jan 2014 15:37:32 +0800 Subject: [PATCH 38/51] close #3835:fix TMXMapInfo::startElement insert property to properties fail --- cocos/2d/CCTMXXMLParser.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cocos/2d/CCTMXXMLParser.h b/cocos/2d/CCTMXXMLParser.h index 621a197734..4c40f259ec 100644 --- a/cocos/2d/CCTMXXMLParser.h +++ b/cocos/2d/CCTMXXMLParser.h @@ -250,7 +250,8 @@ public: inline void setStoringCharacters(bool storingCharacters) { _storingCharacters = storingCharacters; }; /// properties - inline ValueMap getProperties() const { return _properties; }; + inline const ValueMap& getProperties() const { return _properties; } + inline ValueMap& getProperties() { return _properties; } inline void setProperties(ValueMap properties) { _properties = properties; }; From e19c6e2caaceae81e668ccad0ca7ad6fb7e39ea0 Mon Sep 17 00:00:00 2001 From: CocosRobot Date: Fri, 24 Jan 2014 07:38:34 +0000 Subject: [PATCH 39/51] [AUTO] : updating submodule reference to latest autogenerated bindings --- cocos/scripting/auto-generated | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos/scripting/auto-generated b/cocos/scripting/auto-generated index 37451f4ec2..c8375f61cc 160000 --- a/cocos/scripting/auto-generated +++ b/cocos/scripting/auto-generated @@ -1 +1 @@ -Subproject commit 37451f4ec2e2d01da9286ae97952582b81d02be8 +Subproject commit c8375f61ccc86b108dc3e57f2a593e30296daf7a From 6655ad79d748c2f55c6ab67b95f9ebbd933aa0e9 Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Fri, 24 Jan 2014 16:05:38 +0800 Subject: [PATCH 40/51] use const ValueMap& for setters. --- cocos/2d/CCTMXXMLParser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos/2d/CCTMXXMLParser.h b/cocos/2d/CCTMXXMLParser.h index 4c40f259ec..6d980b2c36 100644 --- a/cocos/2d/CCTMXXMLParser.h +++ b/cocos/2d/CCTMXXMLParser.h @@ -252,7 +252,7 @@ public: /// properties inline const ValueMap& getProperties() const { return _properties; } inline ValueMap& getProperties() { return _properties; } - inline void setProperties(ValueMap properties) { + inline void setProperties(const ValueMap& properties) { _properties = properties; }; From d1cf374459a06d7863c4f55a8eca7acc8146664b Mon Sep 17 00:00:00 2001 From: minggo Date: Fri, 24 Jan 2014 16:53:59 +0800 Subject: [PATCH 41/51] reset to default texture format after running test case --- .../Classes/PerformanceTest/PerformanceTextureTest.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTextureTest.cpp b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTextureTest.cpp index c420ac27ec..c46cb19c34 100644 --- a/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTextureTest.cpp +++ b/samples/Cpp/TestCpp/Classes/PerformanceTest/PerformanceTextureTest.cpp @@ -85,6 +85,8 @@ void TextureTest::performTestsPNG(const char* filename) struct timeval now; Texture2D *texture; auto cache = Director::getInstance()->getTextureCache(); + + Texture2D::PixelFormat defaultFormat = Texture2D::getDefaultAlphaPixelFormat(); log("RGBA 8888"); Texture2D::setDefaultAlphaPixelFormat(Texture2D::PixelFormat::RGBA8888); @@ -125,6 +127,8 @@ void TextureTest::performTestsPNG(const char* filename) else log(" ERROR"); cache->removeTexture(texture); + + Texture2D::setDefaultAlphaPixelFormat(defaultFormat); } void TextureTest::performTests() From 7ad2b95e7bcd24f17b617e75b429ae566b9fef2a Mon Sep 17 00:00:00 2001 From: Dhilan007 Date: Fri, 24 Jan 2014 17:12:59 +0800 Subject: [PATCH 42/51] fix save path not initialized. --- samples/Cpp/AssetsManagerTest/Classes/AppDelegate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/Cpp/AssetsManagerTest/Classes/AppDelegate.cpp b/samples/Cpp/AssetsManagerTest/Classes/AppDelegate.cpp index 3e9381a865..3d6ed9ec1a 100644 --- a/samples/Cpp/AssetsManagerTest/Classes/AppDelegate.cpp +++ b/samples/Cpp/AssetsManagerTest/Classes/AppDelegate.cpp @@ -141,6 +141,8 @@ bool UpdateLayer::init() { Layer::init(); + createDownloadedDir(); + /** Creates assets manager */ pAssetsManager = new AssetsManager("https://raw.github.com/minggo/AssetsManagerTest/master/package.zip", "https://raw.github.com/minggo/AssetsManagerTest/master/version", @@ -150,8 +152,6 @@ bool UpdateLayer::init() addChild(pAssetsManager); pAssetsManager->release(); - createDownloadedDir(); - auto size = Director::getInstance()->getWinSize(); pItemReset = MenuItemFont::create("reset", CC_CALLBACK_1(UpdateLayer::reset,this)); From 58eab72d2644799bed742cd329b17912a3320d5f Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Fri, 24 Jan 2014 17:24:10 +0800 Subject: [PATCH 43/51] issue:Add luasocket's support for lua --- .../project.pbxproj.REMOVED.git-id | 2 +- cocos/scripting/lua/bindings/Android.mk | 20 +- cocos/scripting/lua/bindings/CCLuaStack.cpp | 6 + cocos/scripting/lua/bindings/lua_extensions.c | 37 + cocos/scripting/lua/bindings/lua_extensions.h | 23 + .../scripting/lua/bindings/socket/auxiliar.c | 158 ++ .../scripting/lua/bindings/socket/auxiliar.h | 47 + cocos/scripting/lua/bindings/socket/except.c | 97 ++ cocos/scripting/lua/bindings/socket/except.h | 33 + cocos/scripting/lua/bindings/socket/inet.c | 528 ++++++ cocos/scripting/lua/bindings/socket/inet.h | 56 + .../scripting/lua/bindings/socket/luasocket.c | 116 ++ .../scripting/lua/bindings/socket/luasocket.h | 34 + .../lua/bindings/socket/luasocket_buffer.c | 276 ++++ .../lua/bindings/socket/luasocket_buffer.h | 45 + .../lua/bindings/socket/luasocket_io.c | 30 + .../lua/bindings/socket/luasocket_io.h | 65 + cocos/scripting/lua/bindings/socket/mime.c | 723 ++++++++ cocos/scripting/lua/bindings/socket/mime.h | 29 + cocos/scripting/lua/bindings/socket/options.c | 262 +++ cocos/scripting/lua/bindings/socket/options.h | 50 + cocos/scripting/lua/bindings/socket/select.c | 216 +++ cocos/scripting/lua/bindings/socket/select.h | 15 + cocos/scripting/lua/bindings/socket/serial.c | 183 ++ cocos/scripting/lua/bindings/socket/socket.h | 78 + .../socket/socket_scripts.c.REMOVED.git-id | 1 + .../lua/bindings/socket/socket_scripts.h | 32 + cocos/scripting/lua/bindings/socket/tcp.c | 475 ++++++ cocos/scripting/lua/bindings/socket/tcp.h | 35 + cocos/scripting/lua/bindings/socket/timeout.c | 217 +++ cocos/scripting/lua/bindings/socket/timeout.h | 28 + cocos/scripting/lua/bindings/socket/udp.c | 468 ++++++ cocos/scripting/lua/bindings/socket/udp.h | 32 + cocos/scripting/lua/bindings/socket/unix.c | 340 ++++ cocos/scripting/lua/bindings/socket/unix.h | 26 + cocos/scripting/lua/bindings/socket/usocket.c | 449 +++++ cocos/scripting/lua/bindings/socket/usocket.h | 43 + cocos/scripting/lua/bindings/socket/wsocket.c | 413 +++++ cocos/scripting/lua/bindings/socket/wsocket.h | 25 + .../HelloLua/Resources/Resources/.gitignore | 2 + .../Resources/background.mp3.REMOVED.git-id | 1 + samples/Lua/HelloLua/Resources/mobdebug.lua | 1465 +++++++++++++++++ .../HelloLua/proj.android/AndroidManifest.xml | 1 + 43 files changed, 7180 insertions(+), 2 deletions(-) create mode 100644 cocos/scripting/lua/bindings/lua_extensions.c create mode 100644 cocos/scripting/lua/bindings/lua_extensions.h create mode 100644 cocos/scripting/lua/bindings/socket/auxiliar.c create mode 100644 cocos/scripting/lua/bindings/socket/auxiliar.h create mode 100644 cocos/scripting/lua/bindings/socket/except.c create mode 100644 cocos/scripting/lua/bindings/socket/except.h create mode 100644 cocos/scripting/lua/bindings/socket/inet.c create mode 100644 cocos/scripting/lua/bindings/socket/inet.h create mode 100644 cocos/scripting/lua/bindings/socket/luasocket.c create mode 100644 cocos/scripting/lua/bindings/socket/luasocket.h create mode 100644 cocos/scripting/lua/bindings/socket/luasocket_buffer.c create mode 100644 cocos/scripting/lua/bindings/socket/luasocket_buffer.h create mode 100644 cocos/scripting/lua/bindings/socket/luasocket_io.c create mode 100644 cocos/scripting/lua/bindings/socket/luasocket_io.h create mode 100644 cocos/scripting/lua/bindings/socket/mime.c create mode 100644 cocos/scripting/lua/bindings/socket/mime.h create mode 100644 cocos/scripting/lua/bindings/socket/options.c create mode 100644 cocos/scripting/lua/bindings/socket/options.h create mode 100644 cocos/scripting/lua/bindings/socket/select.c create mode 100644 cocos/scripting/lua/bindings/socket/select.h create mode 100644 cocos/scripting/lua/bindings/socket/serial.c create mode 100644 cocos/scripting/lua/bindings/socket/socket.h create mode 100644 cocos/scripting/lua/bindings/socket/socket_scripts.c.REMOVED.git-id create mode 100644 cocos/scripting/lua/bindings/socket/socket_scripts.h create mode 100644 cocos/scripting/lua/bindings/socket/tcp.c create mode 100644 cocos/scripting/lua/bindings/socket/tcp.h create mode 100644 cocos/scripting/lua/bindings/socket/timeout.c create mode 100644 cocos/scripting/lua/bindings/socket/timeout.h create mode 100644 cocos/scripting/lua/bindings/socket/udp.c create mode 100644 cocos/scripting/lua/bindings/socket/udp.h create mode 100644 cocos/scripting/lua/bindings/socket/unix.c create mode 100644 cocos/scripting/lua/bindings/socket/unix.h create mode 100644 cocos/scripting/lua/bindings/socket/usocket.c create mode 100644 cocos/scripting/lua/bindings/socket/usocket.h create mode 100644 cocos/scripting/lua/bindings/socket/wsocket.c create mode 100644 cocos/scripting/lua/bindings/socket/wsocket.h create mode 100644 samples/Lua/HelloLua/Resources/Resources/.gitignore create mode 100644 samples/Lua/HelloLua/Resources/Resources/background.mp3.REMOVED.git-id create mode 100644 samples/Lua/HelloLua/Resources/mobdebug.lua diff --git a/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id b/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id index 93c759b563..2ee1321928 100644 --- a/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id +++ b/build/cocos2d_libs.xcodeproj/project.pbxproj.REMOVED.git-id @@ -1 +1 @@ -e706fcdbf8b76069d794bc03e3849a57932cdf0a \ No newline at end of file +cf66879460037639be60615c3aeeb56e799daaeb \ No newline at end of file diff --git a/cocos/scripting/lua/bindings/Android.mk b/cocos/scripting/lua/bindings/Android.mk index fa92938dd4..5261274e43 100644 --- a/cocos/scripting/lua/bindings/Android.mk +++ b/cocos/scripting/lua/bindings/Android.mk @@ -37,7 +37,25 @@ LOCAL_SRC_FILES := CCLuaBridge.cpp \ ../../../../external/lua/tolua/tolua_map.c \ ../../../../external/lua/tolua/tolua_push.c \ ../../../../external/lua/tolua/tolua_to.c \ - tolua_fix.c + tolua_fix.c \ + socket/auxiliar.c \ + socket/luasocket_buffer.c \ + socket/except.c \ + socket/inet.c \ + socket/luasocket_io.c \ + socket/luasocket.c \ + socket/mime.c \ + socket/options.c \ + socket/select.c \ + socket/serial.c \ + socket/socket_scripts.c \ + socket/tcp.c \ + socket/timeout.c \ + socket/udp.c \ + socket/unix.c \ + socket/usocket.c \ + lua_extensions.c + LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../../../external/lua/tolua \ $(LOCAL_PATH)/../../auto-generated/lua-bindings \ diff --git a/cocos/scripting/lua/bindings/CCLuaStack.cpp b/cocos/scripting/lua/bindings/CCLuaStack.cpp index 9661fb1cd8..fedbf3c7d1 100644 --- a/cocos/scripting/lua/bindings/CCLuaStack.cpp +++ b/cocos/scripting/lua/bindings/CCLuaStack.cpp @@ -31,6 +31,9 @@ extern "C" { #include "lualib.h" #include "lauxlib.h" #include "tolua_fix.h" +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) +#include "lua_extensions.h" +#endif } #include "Cocos2dxLuaLoader.h" @@ -146,6 +149,9 @@ bool LuaStack::init(void) {NULL, NULL} }; luaL_register(_state, "_G", global_functions); +#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) + luaopen_lua_extensions(_state); +#endif g_luaType.clear(); register_all_cocos2dx(_state); register_all_cocos2dx_extension(_state); diff --git a/cocos/scripting/lua/bindings/lua_extensions.c b/cocos/scripting/lua/bindings/lua_extensions.c new file mode 100644 index 0000000000..e3f62e42cd --- /dev/null +++ b/cocos/scripting/lua/bindings/lua_extensions.c @@ -0,0 +1,37 @@ + +#include "lua_extensions.h" + +#if __cplusplus +extern "C" { +#endif +// socket +#include "socket/luasocket.h" +#include "socket/mime.h" +#include "socket/socket_scripts.h" + +static luaL_Reg luax_exts[] = { + {"socket.core", luaopen_socket_core}, + {"mime.core", luaopen_mime_core}, + {NULL, NULL} +}; + +void luaopen_lua_extensions(lua_State *L) +{ + // load extensions + luaL_Reg* lib = luax_exts; + lua_getglobal(L, "package"); + lua_getfield(L, -1, "preload"); + for (; lib->func; lib++) + { + lua_pushcfunction(L, lib->func); + lua_setfield(L, -2, lib->name); + } + lua_pop(L, 2); + + // load extensions script + luaopen_socket_scripts(L); +} + +#if __cplusplus +} // extern "C" +#endif diff --git a/cocos/scripting/lua/bindings/lua_extensions.h b/cocos/scripting/lua/bindings/lua_extensions.h new file mode 100644 index 0000000000..67727f057f --- /dev/null +++ b/cocos/scripting/lua/bindings/lua_extensions.h @@ -0,0 +1,23 @@ + +#ifndef __LUA_EXTRA_H_ +#define __LUA_EXTRA_H_ + +#if defined(_USRDLL) + #define LUA_EXTENSIONS_DLL __declspec(dllexport) +#else /* use a DLL library */ + #define LUA_EXTENSIONS_DLL +#endif + +#if __cplusplus +extern "C" { +#endif + +#include "lauxlib.h" + +void LUA_EXTENSIONS_DLL luaopen_lua_extensions(lua_State *L); + +#if __cplusplus +} +#endif + +#endif /* __LUA_EXTRA_H_ */ diff --git a/cocos/scripting/lua/bindings/socket/auxiliar.c b/cocos/scripting/lua/bindings/socket/auxiliar.c new file mode 100644 index 0000000000..de625e9d74 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/auxiliar.c @@ -0,0 +1,158 @@ +/*=========================================================================*\ +* Auxiliar routines for class hierarchy manipulation +* LuaSocket toolkit +\*=========================================================================*/ +#include +#include + +#include "auxiliar.h" + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes the module +\*-------------------------------------------------------------------------*/ +int auxiliar_open(lua_State *L) { + (void) L; + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Creates a new class with given methods +* Methods whose names start with __ are passed directly to the metatable. +\*-------------------------------------------------------------------------*/ +void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) { + luaL_newmetatable(L, classname); /* mt */ + /* create __index table to place methods */ + lua_pushstring(L, "__index"); /* mt,"__index" */ + lua_newtable(L); /* mt,"__index",it */ + /* put class name into class metatable */ + lua_pushstring(L, "class"); /* mt,"__index",it,"class" */ + lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */ + lua_rawset(L, -3); /* mt,"__index",it */ + /* pass all methods that start with _ to the metatable, and all others + * to the index table */ + for (; func->name; func++) { /* mt,"__index",it */ + lua_pushstring(L, func->name); + lua_pushcfunction(L, func->func); + lua_rawset(L, func->name[0] == '_' ? -5: -3); + } + lua_rawset(L, -3); /* mt */ + lua_pop(L, 1); +} + +/*-------------------------------------------------------------------------*\ +* Prints the value of a class in a nice way +\*-------------------------------------------------------------------------*/ +int auxiliar_tostring(lua_State *L) { + char buf[32]; + if (!lua_getmetatable(L, 1)) goto error; + lua_pushstring(L, "__index"); + lua_gettable(L, -2); + if (!lua_istable(L, -1)) goto error; + lua_pushstring(L, "class"); + lua_gettable(L, -2); + if (!lua_isstring(L, -1)) goto error; + sprintf(buf, "%p", lua_touserdata(L, 1)); + lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf); + return 1; +error: + lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'"); + lua_error(L); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Insert class into group +\*-------------------------------------------------------------------------*/ +void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) { + luaL_getmetatable(L, classname); + lua_pushstring(L, groupname); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + lua_pop(L, 1); +} + +/*-------------------------------------------------------------------------*\ +* Make sure argument is a boolean +\*-------------------------------------------------------------------------*/ +int auxiliar_checkboolean(lua_State *L, int objidx) { + if (!lua_isboolean(L, objidx)) + auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); + return lua_toboolean(L, objidx); +} + +/*-------------------------------------------------------------------------*\ +* Return userdata pointer if object belongs to a given class, abort with +* error otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { + void *data = auxiliar_getclassudata(L, classname, objidx); + if (!data) { + char msg[45]; + sprintf(msg, "%.35s expected", classname); + luaL_argerror(L, objidx, msg); + } + return data; +} + +/*-------------------------------------------------------------------------*\ +* Return userdata pointer if object belongs to a given group, abort with +* error otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) { + void *data = auxiliar_getgroupudata(L, groupname, objidx); + if (!data) { + char msg[45]; + sprintf(msg, "%.35s expected", groupname); + luaL_argerror(L, objidx, msg); + } + return data; +} + +/*-------------------------------------------------------------------------*\ +* Set object class +\*-------------------------------------------------------------------------*/ +void auxiliar_setclass(lua_State *L, const char *classname, int objidx) { + luaL_getmetatable(L, classname); + if (objidx < 0) objidx--; + lua_setmetatable(L, objidx); +} + +/*-------------------------------------------------------------------------*\ +* Get a userdata pointer if object belongs to a given group. Return NULL +* otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) { + if (!lua_getmetatable(L, objidx)) + return NULL; + lua_pushstring(L, groupname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); + return NULL; + } else { + lua_pop(L, 2); + return lua_touserdata(L, objidx); + } +} + +/*-------------------------------------------------------------------------*\ +* Get a userdata pointer if object belongs to a given class. Return NULL +* otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { + return luaL_checkudata(L, objidx, classname); +} + +/*-------------------------------------------------------------------------*\ +* Throws error when argument does not have correct type. +* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2. +\*-------------------------------------------------------------------------*/ +int auxiliar_typeerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, + luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} + diff --git a/cocos/scripting/lua/bindings/socket/auxiliar.h b/cocos/scripting/lua/bindings/socket/auxiliar.h new file mode 100644 index 0000000000..ea9901333d --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/auxiliar.h @@ -0,0 +1,47 @@ +#ifndef AUXILIAR_H +#define AUXILIAR_H +/*=========================================================================*\ +* Auxiliar routines for class hierarchy manipulation +* LuaSocket toolkit (but completely independent of other LuaSocket modules) +* +* A LuaSocket class is a name associated with Lua metatables. A LuaSocket +* group is a name associated with a class. A class can belong to any number +* of groups. This module provides the functionality to: +* +* - create new classes +* - add classes to groups +* - set the class of objects +* - check if an object belongs to a given class or group +* - get the userdata associated to objects +* - print objects in a pretty way +* +* LuaSocket class names follow the convention {}. Modules +* can define any number of classes and groups. The module tcp.c, for +* example, defines the classes tcp{master}, tcp{client} and tcp{server} and +* the groups tcp{client,server} and tcp{any}. Module functions can then +* perform type-checking on their arguments by either class or group. +* +* LuaSocket metatables define the __index metamethod as being a table. This +* table has one field for each method supported by the class, and a field +* "class" with the class name. +* +* The mapping from class name to the corresponding metatable and the +* reverse mapping are done using lauxlib. +\*=========================================================================*/ + +#include "lua.h" +#include "lauxlib.h" + +int auxiliar_open(lua_State *L); +void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func); +void auxiliar_add2group(lua_State *L, const char *classname, const char *group); +void auxiliar_setclass(lua_State *L, const char *classname, int objidx); +void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); +void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); +void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); +void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); +int auxiliar_checkboolean(lua_State *L, int objidx); +int auxiliar_tostring(lua_State *L); +int auxiliar_typeerror(lua_State *L, int narg, const char *tname); + +#endif /* AUXILIAR_H */ diff --git a/cocos/scripting/lua/bindings/socket/except.c b/cocos/scripting/lua/bindings/socket/except.c new file mode 100644 index 0000000000..1d1ade0ee0 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/except.c @@ -0,0 +1,97 @@ +/*=========================================================================*\ +* Simple exception support +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "except.h" + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int global_protect(lua_State *L); +static int global_newtry(lua_State *L); +static int protected_(lua_State *L); +static int finalize(lua_State *L); +static int do_nothing(lua_State *L); + +/* except functions */ +static luaL_Reg func[] = { + {"newtry", global_newtry}, + {"protect", global_protect}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Try factory +\*-------------------------------------------------------------------------*/ +static void wrap(lua_State *L) { + lua_newtable(L); + lua_pushnumber(L, 1); + lua_pushvalue(L, -3); + lua_settable(L, -3); + lua_insert(L, -2); + lua_pop(L, 1); +} + +static int finalize(lua_State *L) { + if (!lua_toboolean(L, 1)) { + lua_pushvalue(L, lua_upvalueindex(1)); + lua_pcall(L, 0, 0, 0); + lua_settop(L, 2); + wrap(L); + lua_error(L); + return 0; + } else return lua_gettop(L); +} + +static int do_nothing(lua_State *L) { + (void) L; + return 0; +} + +static int global_newtry(lua_State *L) { + lua_settop(L, 1); + if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); + lua_pushcclosure(L, finalize, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Protect factory +\*-------------------------------------------------------------------------*/ +static int unwrap(lua_State *L) { + if (lua_istable(L, -1)) { + lua_pushnumber(L, 1); + lua_gettable(L, -2); + lua_pushnil(L); + lua_insert(L, -2); + return 1; + } else return 0; +} + +static int protected_(lua_State *L) { + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, 1); + if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) { + if (unwrap(L)) return 2; + else lua_error(L); + return 0; + } else return lua_gettop(L); +} + +static int global_protect(lua_State *L) { + lua_pushcclosure(L, protected_, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Init module +\*-------------------------------------------------------------------------*/ +int except_open(lua_State *L) { + luaL_openlib(L, NULL, func, 0); + return 0; +} diff --git a/cocos/scripting/lua/bindings/socket/except.h b/cocos/scripting/lua/bindings/socket/except.h new file mode 100644 index 0000000000..1e7a2455e7 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/except.h @@ -0,0 +1,33 @@ +#ifndef EXCEPT_H +#define EXCEPT_H +/*=========================================================================*\ +* Exception control +* LuaSocket toolkit (but completely independent from other modules) +* +* This provides support for simple exceptions in Lua. During the +* development of the HTTP/FTP/SMTP support, it became aparent that +* error checking was taking a substantial amount of the coding. These +* function greatly simplify the task of checking errors. +* +* The main idea is that functions should return nil as its first return +* value when it finds an error, and return an error message (or value) +* following nil. In case of success, as long as the first value is not nil, +* the other values don't matter. +* +* The idea is to nest function calls with the "try" function. This function +* checks the first value, and calls "error" on the second if the first is +* nil. Otherwise, it returns all values it received. +* +* The protect function returns a new function that behaves exactly like the +* function it receives, but the new function doesn't throw exceptions: it +* returns nil followed by the error message instead. +* +* With these two function, it's easy to write functions that throw +* exceptions on error, but that don't interrupt the user script. +\*=========================================================================*/ + +#include "lua.h" + +int except_open(lua_State *L); + +#endif diff --git a/cocos/scripting/lua/bindings/socket/inet.c b/cocos/scripting/lua/bindings/socket/inet.c new file mode 100644 index 0000000000..16f709387c --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/inet.c @@ -0,0 +1,528 @@ +/*=========================================================================*\ +* Internet domain functions +* LuaSocket toolkit +\*=========================================================================*/ +#include +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "inet.h" + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int inet_global_toip(lua_State *L); +static int inet_global_getaddrinfo(lua_State *L); +static int inet_global_tohostname(lua_State *L); +static int inet_global_getnameinfo(lua_State *L); +static void inet_pushresolved(lua_State *L, struct hostent *hp); +static int inet_global_gethostname(lua_State *L); + +/* DNS functions */ +static luaL_Reg func[] = { + { "toip", inet_global_toip}, + { "getaddrinfo", inet_global_getaddrinfo}, + { "tohostname", inet_global_tohostname}, + { "getnameinfo", inet_global_getnameinfo}, + { "gethostname", inet_global_gethostname}, + { NULL, NULL} +}; + +#ifdef _WINDOWS_ +/****luodx patch for windows xp start**/ +char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length) +{ + char* result = inet_ntoa(*(IN_ADDR*)src); + if (result != NULL){ + strcpy(dest, result); + } + return result; +} + +int win32xp_inet_pton(int family, const char* string, PVOID dest) { + return inet_aton(string, (IN_ADDR*)dest); +} +/****luodx patch for windows xp end**/ +#endif + + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int inet_open(lua_State *L) +{ + lua_pushstring(L, "dns"); + lua_newtable(L); + luaL_openlib(L, NULL, func, 0); + lua_settable(L, -3); + return 0; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_gethost(const char *address, struct hostent **hp) { + struct in_addr addr; + if (inet_aton(address, &addr)) + return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); + else + return socket_gethostbyname(address, hp); +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_tohostname(lua_State *L) { + const char *address = luaL_checkstring(L, 1); + struct hostent *hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, hp->h_name); + inet_pushresolved(L, hp); + return 2; +} + +static int inet_global_getnameinfo(lua_State *L) { + int i, ret; + char host[1024]; + char serv[32]; + struct addrinfo hints; + struct addrinfo *resolved, *iter; + const char *node = luaL_optstring(L, 1, NULL); + const char *service = luaL_optstring(L, 2, NULL); + + if (!(node || service)) + luaL_error(L, "You have to specify a hostname, a service, or both"); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + /* getaddrinfo must get a node and a service argument */ + ret = getaddrinfo(node ? node : "127.0.0.1", service ? service : "7", + &hints, &resolved); + if (ret != 0) { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + + lua_newtable(L); + for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { + getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, host, + node ? (socklen_t) sizeof(host) : 0, serv, service ? (socklen_t) sizeof(serv) : 0, 0); + + if (node) { + lua_pushnumber(L, i); + lua_pushstring(L, host); + lua_settable(L, -3); + } + } + freeaddrinfo(resolved); + + if (service) { + lua_pushstring(L, serv); + return 2; + } else { + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_toip(lua_State *L) +{ + const char *address = luaL_checkstring(L, 1); + struct hostent *hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); + inet_pushresolved(L, hp); + return 2; +} + +int inet_optfamily(lua_State* L, int narg, const char* def) +{ + static const char* optname[] = { "unspec", "inet", "inet6", NULL }; + static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 }; + + return optvalue[luaL_checkoption(L, narg, def, optname)]; +} + +int inet_optsocktype(lua_State* L, int narg, const char* def) +{ + static const char* optname[] = { "stream", "dgram", NULL }; + static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 }; + + return optvalue[luaL_checkoption(L, narg, def, optname)]; +} + +static int inet_global_getaddrinfo(lua_State *L) +{ + const char *hostname = luaL_checkstring(L, 1); + struct addrinfo *iterator = NULL, *resolved = NULL; + struct addrinfo hints; + int i = 1, ret = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + ret = getaddrinfo(hostname, NULL, &hints, &resolved); + if (ret != 0) { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + lua_newtable(L); + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; + getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, hbuf, + (socklen_t) sizeof(hbuf), sbuf, 0, NI_NUMERICHOST); + lua_pushnumber(L, i); + lua_newtable(L); + switch (iterator->ai_family) { + case AF_INET: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet"); + lua_settable(L, -3); + break; + case AF_INET6: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet6"); + lua_settable(L, -3); + break;; + } + lua_pushliteral(L, "addr"); + lua_pushstring(L, hbuf); + lua_settable(L, -3); + lua_settable(L, -3); + i++; + } + freeaddrinfo(resolved); + return 1; +} + + +/*-------------------------------------------------------------------------*\ +* Gets the host name +\*-------------------------------------------------------------------------*/ +static int inet_global_gethostname(lua_State *L) +{ + char name[257]; + name[256] = '\0'; + if (gethostname(name, 256) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } else { + lua_pushstring(L, name); + return 1; + } +} + + + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Retrieves socket peer name +\*-------------------------------------------------------------------------*/ +int inet_meth_getpeername(lua_State *L, p_socket ps, int family) +{ + switch (family) { + case PF_INET: { + struct sockaddr_in peer; + socklen_t peer_len = sizeof(peer); + char name[INET_ADDRSTRLEN]; + if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } else { + my_inet_ntop(family, &peer.sin_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(peer.sin_port)); + lua_pushliteral(L, "inet"); + return 3; + } + } + case PF_INET6: { + struct sockaddr_in6 peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } else { + my_inet_ntop(family, &peer.sin6_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(peer.sin6_port)); + lua_pushliteral(L, "inet6"); + return 3; + } + } + default: + lua_pushnil(L); + lua_pushfstring(L, "unknown family %d", family); + return 2; + } +} + +/*-------------------------------------------------------------------------*\ +* Retrieves socket local name +\*-------------------------------------------------------------------------*/ +int inet_meth_getsockname(lua_State *L, p_socket ps, int family) +{ + switch (family) { + case PF_INET: { + struct sockaddr_in local; + socklen_t local_len = sizeof(local); + char name[INET_ADDRSTRLEN]; + if (getsockname(*ps, (SA *) &local, &local_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } else { + my_inet_ntop(family, &local.sin_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(local.sin_port)); + lua_pushliteral(L, "inet"); + return 3; + } + } + case PF_INET6: { + struct sockaddr_in6 local; + socklen_t local_len = sizeof(local); + char name[INET6_ADDRSTRLEN]; + if (getsockname(*ps, (SA *) &local, &local_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } else { + my_inet_ntop(family, &local.sin6_addr, name, sizeof(name)); + lua_pushstring(L, name); + lua_pushnumber(L, ntohs(local.sin6_port)); + lua_pushliteral(L, "inet6"); + return 3; + } + } + default: + lua_pushnil(L); + lua_pushfstring(L, "unknown family %d", family); + return 2; + } +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Passes all resolver information to Lua as a table +\*-------------------------------------------------------------------------*/ +static void inet_pushresolved(lua_State *L, struct hostent *hp) +{ + char **alias; + struct in_addr **addr; + int i, resolved; + lua_newtable(L); resolved = lua_gettop(L); + lua_pushstring(L, "name"); + lua_pushstring(L, hp->h_name); + lua_settable(L, resolved); + lua_pushstring(L, "ip"); + lua_pushstring(L, "alias"); + i = 1; + alias = hp->h_aliases; + lua_newtable(L); + if (alias) { + while (*alias) { + lua_pushnumber(L, i); + lua_pushstring(L, *alias); + lua_settable(L, -3); + i++; alias++; + } + } + lua_settable(L, resolved); + i = 1; + lua_newtable(L); + addr = (struct in_addr **) hp->h_addr_list; + if (addr) { + while (*addr) { + lua_pushnumber(L, i); + lua_pushstring(L, inet_ntoa(**addr)); + lua_settable(L, -3); + i++; addr++; + } + } + lua_settable(L, resolved); +} + +/*-------------------------------------------------------------------------*\ +* Tries to create a new inet socket +\*-------------------------------------------------------------------------*/ +const char *inet_trycreate(p_socket ps, int family, int type) { + return socket_strerror(socket_create(ps, family, type, 0)); +} + +/*-------------------------------------------------------------------------*\ +* "Disconnects" a DGRAM socket +\*-------------------------------------------------------------------------*/ +const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) +{ + switch (family) { + case PF_INET: { + struct sockaddr_in sin; + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_UNSPEC; + sin.sin_addr.s_addr = INADDR_ANY; + return socket_strerror(socket_connect(ps, (SA *) &sin, + sizeof(sin), tm)); + } + case PF_INET6: { + struct sockaddr_in6 sin6; + struct in6_addr addrany = IN6ADDR_ANY_INIT; + memset((char *) &sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_UNSPEC; +fprintf(stderr, "disconnecting\n"); + sin6.sin6_addr = addrany; + return socket_strerror(socket_connect(ps, (SA *) &sin6, + sizeof(sin6), tm)); + } + } + return NULL; +} + +/*-------------------------------------------------------------------------*\ +* Tries to connect to remote address (address, port) +\*-------------------------------------------------------------------------*/ +const char *inet_tryconnect(p_socket ps, const char *address, + const char *serv, p_timeout tm, struct addrinfo *connecthints) +{ + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, + connecthints, &resolved)); + if (err != NULL) { + if (resolved) freeaddrinfo(resolved); + return err; + } + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + timeout_markstart(tm); + /* try connecting to remote address */ + err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, + (socklen_t) iterator->ai_addrlen, tm)); + /* if success, break out of loop */ + if (err == NULL) break; + } + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; +} + +/*-------------------------------------------------------------------------*\ +* Tries to accept a socket +\*-------------------------------------------------------------------------*/ +const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm) +{ + socklen_t len; + t_sockaddr_storage addr; + if (family == PF_INET6) { + len = sizeof(struct sockaddr_in6); + } else { + len = sizeof(struct sockaddr_in); + } + return socket_strerror(socket_accept(server, client, (SA *) &addr, &len, tm)); +} + +/*-------------------------------------------------------------------------*\ +* Tries to bind socket to (address, port) +\*-------------------------------------------------------------------------*/ +const char *inet_trybind(p_socket ps, const char *address, const char *serv, + struct addrinfo *bindhints) +{ + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + t_socket sock = *ps; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); + if (err) { + if (resolved) freeaddrinfo(resolved); + return err; + } + /* iterate over resolved addresses until one is good */ + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + if(sock == SOCKET_INVALID) { + err = socket_strerror(socket_create(&sock, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol)); + if(err) + continue; + } + /* try binding to local address */ + err = socket_strerror(socket_bind(&sock, + (SA *) iterator->ai_addr, + (socklen_t) iterator->ai_addrlen)); + + /* keep trying unless bind succeeded */ + if (err) { + if(sock != *ps) + socket_destroy(&sock); + } else { + /* remember what we connected to, particularly the family */ + *bindhints = *iterator; + break; + } + } + /* cleanup and return error */ + freeaddrinfo(resolved); + *ps = sock; + return err; +} + +/*-------------------------------------------------------------------------*\ +* Some systems do not provide this so that we provide our own. It's not +* marvelously fast, but it works just fine. +\*-------------------------------------------------------------------------*/ +#ifdef INET_ATON +int inet_aton(const char *cp, struct in_addr *inp) +{ + unsigned int a = 0, b = 0, c = 0, d = 0; + int n = 0, r; + unsigned long int addr = 0; + r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); + if (r == 0 || n == 0) return 0; + cp += n; + if (*cp) return 0; + if (a > 255 || b > 255 || c > 255 || d > 255) return 0; + if (inp) { + addr += a; addr <<= 8; + addr += b; addr <<= 8; + addr += c; addr <<= 8; + addr += d; + inp->s_addr = htonl(addr); + } + return 1; +} +#endif + + diff --git a/cocos/scripting/lua/bindings/socket/inet.h b/cocos/scripting/lua/bindings/socket/inet.h new file mode 100644 index 0000000000..9971002103 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/inet.h @@ -0,0 +1,56 @@ +#ifndef INET_H +#define INET_H +/*=========================================================================*\ +* Internet domain functions +* LuaSocket toolkit +* +* This module implements the creation and connection of internet domain +* sockets, on top of the socket.h interface, and the interface of with the +* resolver. +* +* The function inet_aton is provided for the platforms where it is not +* available. The module also implements the interface of the internet +* getpeername and getsockname functions as seen by Lua programs. +* +* The Lua functions toip and tohostname are also implemented here. +\*=========================================================================*/ +#include "lua.h" +#include "socket.h" +#include "timeout.h" + +#ifdef _WIN32 +#define INET_ATON +#endif + +int inet_open(lua_State *L); + +const char *inet_trycreate(p_socket ps, int family, int type); +const char *inet_tryconnect(p_socket ps, const char *address, + const char *serv, p_timeout tm, struct addrinfo *connecthints); +const char *inet_trybind(p_socket ps, const char *address, const char *serv, + struct addrinfo *bindhints); +const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm); +const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); + +int inet_meth_getpeername(lua_State *L, p_socket ps, int family); +int inet_meth_getsockname(lua_State *L, p_socket ps, int family); + +int inet_optfamily(lua_State* L, int narg, const char* def); +int inet_optsocktype(lua_State* L, int narg, const char* def); + +#ifdef INET_ATON +int inet_aton(const char *cp, struct in_addr *inp); +#endif + +#ifndef _WINDOWS_ +#define my_inet_ntop(a,b,c,d) inet_ntop(a,b,c,d) +#define my_inet_pton(a,b,c) inet_pton(a,b,c) +#else +int win32xp_inet_pton(int family, const char* string, PVOID dest); +char* win32xp_inet_ntop(int family, PVOID src, char* dest, size_t length); +#define my_inet_ntop(a,b,c,d) win32xp_inet_ntop(a,b,c,d) +#define my_inet_pton(a,b,c) win32xp_inet_pton(a,b,c) +#endif + + +#endif /* INET_H */ diff --git a/cocos/scripting/lua/bindings/socket/luasocket.c b/cocos/scripting/lua/bindings/socket/luasocket.c new file mode 100644 index 0000000000..c86a3e86b0 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/luasocket.c @@ -0,0 +1,116 @@ +/*=========================================================================*\ +* LuaSocket toolkit +* Networking support for the Lua language +* Diego Nehab +* 26/11/1999 +* +* This library is part of an effort to progressively increase the network +* connectivity of the Lua language. The Lua interface to networking +* functions follows the Sockets API closely, trying to simplify all tasks +* involved in setting up both client and server connections. The provided +* IO routines, however, follow the Lua style, being very similar to the +* standard Lua read and write functions. +\*=========================================================================*/ + +/*=========================================================================*\ +* Standard include files +\*=========================================================================*/ +#include "lua.h" +#include "lauxlib.h" + +#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) +#include "compat-5.1.h" +#endif + +/*=========================================================================*\ +* LuaSocket includes +\*=========================================================================*/ +#include "luasocket.h" +#include "auxiliar.h" +#include "except.h" +#include "timeout.h" +#include "luasocket_buffer.h" +#include "inet.h" +#include "tcp.h" +#include "udp.h" +#include "select.h" + +/*-------------------------------------------------------------------------*\ +* Internal function prototypes +\*-------------------------------------------------------------------------*/ +static int global_skip(lua_State *L); +static int global_unload(lua_State *L); +static int base_open(lua_State *L); + +/*-------------------------------------------------------------------------*\ +* Modules and functions +\*-------------------------------------------------------------------------*/ +static const luaL_Reg mod[] = { + {"auxiliar", auxiliar_open}, + {"except", except_open}, + {"timeout", timeout_open}, + {"buffer", buffer_open}, + {"inet", inet_open}, + {"tcp", tcp_open}, + {"udp", udp_open}, + {"select", select_open}, + {NULL, NULL} +}; + +static luaL_Reg func[] = { + {"skip", global_skip}, + {"__unload", global_unload}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Skip a few arguments +\*-------------------------------------------------------------------------*/ +static int global_skip(lua_State *L) { + int amount = luaL_checkint(L, 1); + int ret = lua_gettop(L) - amount - 1; + return ret >= 0 ? ret : 0; +} + +/*-------------------------------------------------------------------------*\ +* Unloads the library +\*-------------------------------------------------------------------------*/ +static int global_unload(lua_State *L) { + (void) L; + socket_close(); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Setup basic stuff. +\*-------------------------------------------------------------------------*/ +static int base_open(lua_State *L) { + if (socket_open()) { + /* export functions (and leave namespace table on top of stack) */ + luaL_openlib(L, "socket", func, 0); +#ifdef LUASOCKET_DEBUG + lua_pushstring(L, "_DEBUG"); + lua_pushboolean(L, 1); + lua_rawset(L, -3); +#endif + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, LUASOCKET_VERSION); + lua_rawset(L, -3); + return 1; + } else { + lua_pushstring(L, "unable to initialize library"); + lua_error(L); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Initializes all library modules. +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_core(lua_State *L) { + int i; + base_open(L); + for (i = 0; mod[i].name; i++) mod[i].func(L); + return 1; +} diff --git a/cocos/scripting/lua/bindings/socket/luasocket.h b/cocos/scripting/lua/bindings/socket/luasocket.h new file mode 100644 index 0000000000..f2ca3c159e --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/luasocket.h @@ -0,0 +1,34 @@ +#ifndef LUASOCKET_H +#define LUASOCKET_H +/*=========================================================================*\ +* LuaSocket toolkit +* Networking support for the Lua language +* Diego Nehab +* 9/11/1999 +\*=========================================================================*/ +#include "lua.h" + +/*-------------------------------------------------------------------------*\ +* Current socket library version +\*-------------------------------------------------------------------------*/ +#define LUASOCKET_VERSION "LuaSocket 2.1-rc1" +#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2012 Diego Nehab" +#define LUASOCKET_AUTHORS "Diego Nehab" + +/*-------------------------------------------------------------------------*\ +* This macro prefixes all exported API functions +\*-------------------------------------------------------------------------*/ +#ifndef LUASOCKET_API +#define LUASOCKET_API extern +#endif + +#if LUA_VERSION_NUM > 501 & !( defined LUA_COMPAT_MODULE) +# error Lua 5.2 requires LUA_COMPAT_MODULE defined for luaL_openlib +#endif + +/*-------------------------------------------------------------------------*\ +* Initializes the library. +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_core(lua_State *L); + +#endif /* LUASOCKET_H */ diff --git a/cocos/scripting/lua/bindings/socket/luasocket_buffer.c b/cocos/scripting/lua/bindings/socket/luasocket_buffer.c new file mode 100644 index 0000000000..13140bccc0 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/luasocket_buffer.c @@ -0,0 +1,276 @@ +/*=========================================================================*\ +* Input/Output interface for Lua programs +* LuaSocket toolkit +\*=========================================================================*/ +#include "lua.h" +#include "lauxlib.h" + +#include "luasocket_buffer.h" + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); +static int recvline(p_buffer buf, luaL_Buffer *b); +static int recvall(p_buffer buf, luaL_Buffer *b); +static int buffer_get(p_buffer buf, const char **data, size_t *count); +static void buffer_skip(p_buffer buf, size_t count); +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int buffer_open(lua_State *L) { + (void) L; + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Initializes C structure +\*-------------------------------------------------------------------------*/ +void buffer_init(p_buffer buf, p_io io, p_timeout tm) { + buf->first = buf->last = 0; + buf->io = io; + buf->tm = tm; + buf->received = buf->sent = 0; + buf->birthday = timeout_gettime(); +} + +/*-------------------------------------------------------------------------*\ +* object:getstats() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_getstats(lua_State *L, p_buffer buf) { + lua_pushnumber(L, (lua_Number) buf->received); + lua_pushnumber(L, (lua_Number) buf->sent); + lua_pushnumber(L, timeout_gettime() - buf->birthday); + return 3; +} + +/*-------------------------------------------------------------------------*\ +* object:setstats() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_setstats(lua_State *L, p_buffer buf) { + buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); + buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); + if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* object:send() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_send(lua_State *L, p_buffer buf) { + int top = lua_gettop(L); + int err = IO_DONE; + size_t size = 0, sent = 0; + const char *data = luaL_checklstring(L, 2, &size); + long start = (long) luaL_optnumber(L, 3, 1); + long end = (long) luaL_optnumber(L, 4, -1); +#ifdef LUASOCKET_DEBUG + p_timeout tm = timeout_markstart(buf->tm); +#endif + if (start < 0) start = (long) (size+start+1); + if (end < 0) end = (long) (size+end+1); + if (start < 1) start = (long) 1; + if (end > (long) size) end = (long) size; + if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); + /* check if there was an error */ + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushnumber(L, (lua_Number) (sent+start-1)); + } else { + lua_pushnumber(L, (lua_Number) (sent+start-1)); + lua_pushnil(L); + lua_pushnil(L); + } +#ifdef LUASOCKET_DEBUG + /* push time elapsed during operation as the last return value */ + lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* object:receive() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_receive(lua_State *L, p_buffer buf) { + int err = IO_DONE, top = lua_gettop(L); + luaL_Buffer b; + size_t size; + const char *part = luaL_optlstring(L, 3, "", &size); +#ifdef LUASOCKET_DEBUG + p_timeout tm = timeout_markstart(buf->tm); +#endif + /* initialize buffer with optional extra prefix + * (useful for concatenating previous partial results) */ + luaL_buffinit(L, &b); + luaL_addlstring(&b, part, size); + /* receive new patterns */ + if (!lua_isnumber(L, 2)) { + const char *p= luaL_optstring(L, 2, "*l"); + if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); + else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); + else luaL_argcheck(L, 0, 2, "invalid receive pattern"); + /* get a fixed number of bytes (minus what was already partially + * received) */ + } else { + double n = lua_tonumber(L, 2); + size_t wanted = (size_t) n; + luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); + if (size == 0 || wanted > size) + err = recvraw(buf, wanted-size, &b); + } + /* check if there was an error */ + if (err != IO_DONE) { + /* we can't push anyting in the stack before pushing the + * contents of the buffer. this is the reason for the complication */ + luaL_pushresult(&b); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushvalue(L, -2); + lua_pushnil(L); + lua_replace(L, -4); + } else { + luaL_pushresult(&b); + lua_pushnil(L); + lua_pushnil(L); + } +#ifdef LUASOCKET_DEBUG + /* push time elapsed during operation as the last return value */ + lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* Determines if there is any data in the read buffer +\*-------------------------------------------------------------------------*/ +int buffer_isempty(p_buffer buf) { + return buf->first >= buf->last; +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Sends a block of data (unbuffered) +\*-------------------------------------------------------------------------*/ +#define STEPSIZE 8192 +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { + p_io io = buf->io; + p_timeout tm = buf->tm; + size_t total = 0; + int err = IO_DONE; + while (total < count && err == IO_DONE) { + size_t done = 0; + size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; + err = io->send(io->ctx, data+total, step, &done, tm); + total += done; + } + *sent = total; + buf->sent += total; + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a fixed number of bytes (buffered) +\*-------------------------------------------------------------------------*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + size_t count; const char *data; + err = buffer_get(buf, &data, &count); + count = MIN(count, wanted - total); + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + total += count; + if (total >= wanted) break; + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads everything until the connection is closed (buffered) +\*-------------------------------------------------------------------------*/ +static int recvall(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + const char *data; size_t count; + err = buffer_get(buf, &data, &count); + total += count; + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + } + if (err == IO_CLOSED) { + if (total > 0) return IO_DONE; + else return IO_CLOSED; + } else return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF +* are not returned by the function and are discarded from the buffer +\*-------------------------------------------------------------------------*/ +static int recvline(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + while (err == IO_DONE) { + size_t count, pos; const char *data; + err = buffer_get(buf, &data, &count); + pos = 0; + while (pos < count && data[pos] != '\n') { + /* we ignore all \r's */ + if (data[pos] != '\r') luaL_addchar(b, data[pos]); + pos++; + } + if (pos < count) { /* found '\n' */ + buffer_skip(buf, pos+1); /* skip '\n' too */ + break; /* we are done */ + } else /* reached the end of the buffer */ + buffer_skip(buf, pos); + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Skips a given number of bytes from read buffer. No data is read from the +* transport layer +\*-------------------------------------------------------------------------*/ +static void buffer_skip(p_buffer buf, size_t count) { + buf->received += count; + buf->first += count; + if (buffer_isempty(buf)) + buf->first = buf->last = 0; +} + +/*-------------------------------------------------------------------------*\ +* Return any data available in buffer, or get more data from transport layer +* if buffer is empty +\*-------------------------------------------------------------------------*/ +static int buffer_get(p_buffer buf, const char **data, size_t *count) { + int err = IO_DONE; + p_io io = buf->io; + p_timeout tm = buf->tm; + if (buffer_isempty(buf)) { + size_t got; + err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); + buf->first = 0; + buf->last = got; + } + *count = buf->last - buf->first; + *data = buf->data + buf->first; + return err; +} diff --git a/cocos/scripting/lua/bindings/socket/luasocket_buffer.h b/cocos/scripting/lua/bindings/socket/luasocket_buffer.h new file mode 100644 index 0000000000..2456cd386b --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/luasocket_buffer.h @@ -0,0 +1,45 @@ +#ifndef BUF_H +#define BUF_H +/*=========================================================================*\ +* Input/Output interface for Lua programs +* LuaSocket toolkit +* +* Line patterns require buffering. Reading one character at a time involves +* too many system calls and is very slow. This module implements the +* LuaSocket interface for input/output on connected objects, as seen by +* Lua programs. +* +* Input is buffered. Output is *not* buffered because there was no simple +* way of making sure the buffered output data would ever be sent. +* +* The module is built on top of the I/O abstraction defined in io.h and the +* timeout management is done with the timeout.h interface. +\*=========================================================================*/ +#include "lua.h" + +#include "luasocket_io.h" +#include "timeout.h" + +/* buffer size in bytes */ +#define BUF_SIZE 8192 + +/* buffer control structure */ +typedef struct t_buffer_ { + double birthday; /* throttle support info: creation time, */ + size_t sent, received; /* bytes sent, and bytes received */ + p_io io; /* IO driver used for this buffer */ + p_timeout tm; /* timeout management for this buffer */ + size_t first, last; /* index of first and last bytes of stored data */ + char data[BUF_SIZE]; /* storage space for buffer data */ +} t_buffer; +typedef t_buffer *p_buffer; + +int buffer_open(lua_State *L); +void buffer_init(p_buffer buf, p_io io, p_timeout tm); +int buffer_meth_send(lua_State *L, p_buffer buf); +int buffer_meth_receive(lua_State *L, p_buffer buf); +int buffer_meth_getstats(lua_State *L, p_buffer buf); +int buffer_meth_setstats(lua_State *L, p_buffer buf); +int buffer_isempty(p_buffer buf); + +#endif /* BUF_H */ diff --git a/cocos/scripting/lua/bindings/socket/luasocket_io.c b/cocos/scripting/lua/bindings/socket/luasocket_io.c new file mode 100644 index 0000000000..74722a5abf --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/luasocket_io.c @@ -0,0 +1,30 @@ +/*=========================================================================*\ +* Input/Output abstraction +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket_io.h" + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes C structure +\*-------------------------------------------------------------------------*/ +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { + io->send = send; + io->recv = recv; + io->error = error; + io->ctx = ctx; +} + +/*-------------------------------------------------------------------------*\ +* I/O error strings +\*-------------------------------------------------------------------------*/ +const char *io_strerror(int err) { + switch (err) { + case IO_DONE: return NULL; + case IO_CLOSED: return "closed"; + case IO_TIMEOUT: return "timeout"; + default: return "unknown error"; + } +} diff --git a/cocos/scripting/lua/bindings/socket/luasocket_io.h b/cocos/scripting/lua/bindings/socket/luasocket_io.h new file mode 100644 index 0000000000..8cca08a860 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/luasocket_io.h @@ -0,0 +1,65 @@ +#ifndef IO_H +#define IO_H +/*=========================================================================*\ +* Input/Output abstraction +* LuaSocket toolkit +* +* This module defines the interface that LuaSocket expects from the +* transport layer for streamed input/output. The idea is that if any +* transport implements this interface, then the buffer.c functions +* automatically work on it. +* +* The module socket.h implements this interface, and thus the module tcp.h +* is very simple. +\*=========================================================================*/ +#include +#include "lua.h" + +#include "timeout.h" + +/* IO error codes */ +enum { + IO_DONE = 0, /* operation completed successfully */ + IO_TIMEOUT = -1, /* operation timed out */ + IO_CLOSED = -2, /* the connection has been closed */ + IO_UNKNOWN = -3 +}; + +/* interface to error message function */ +typedef const char *(*p_error) ( + void *ctx, /* context needed by send */ + int err /* error code */ +); + +/* interface to send function */ +typedef int (*p_send) ( + void *ctx, /* context needed by send */ + const char *data, /* pointer to buffer with data to send */ + size_t count, /* number of bytes to send from buffer */ + size_t *sent, /* number of bytes sent uppon return */ + p_timeout tm /* timeout control */ +); + +/* interface to recv function */ +typedef int (*p_recv) ( + void *ctx, /* context needed by recv */ + char *data, /* pointer to buffer where data will be writen */ + size_t count, /* number of bytes to receive into buffer */ + size_t *got, /* number of bytes received uppon return */ + p_timeout tm /* timeout control */ +); + +/* IO driver definition */ +typedef struct t_io_ { + void *ctx; /* context needed by send/recv */ + p_send send; /* send function pointer */ + p_recv recv; /* receive function pointer */ + p_error error; /* strerror function */ +} t_io; +typedef t_io *p_io; + +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); +const char *io_strerror(int err); + +#endif /* IO_H */ + diff --git a/cocos/scripting/lua/bindings/socket/mime.c b/cocos/scripting/lua/bindings/socket/mime.c new file mode 100644 index 0000000000..dddd3d66ea --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/mime.c @@ -0,0 +1,723 @@ +/*=========================================================================*\ +* MIME support functions +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lua.h" +#include "lauxlib.h" + +#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) +#include "compat-5.1.h" +#endif + +#include "mime.h" + +/*=========================================================================*\ +* Don't want to trust escape character constants +\*=========================================================================*/ +typedef unsigned char UC; +static const char CRLF[] = "\r\n"; +static const char EQCRLF[] = "=\r\n"; + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int mime_global_wrp(lua_State *L); +static int mime_global_b64(lua_State *L); +static int mime_global_unb64(lua_State *L); +static int mime_global_qp(lua_State *L); +static int mime_global_unqp(lua_State *L); +static int mime_global_qpwrp(lua_State *L); +static int mime_global_eol(lua_State *L); +static int mime_global_dot(lua_State *L); + +static size_t dot(int c, size_t state, luaL_Buffer *buffer); +static void b64setup(UC *base); +static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); + +static void qpsetup(UC *class, UC *unbase); +static void qpquote(UC c, luaL_Buffer *buffer); +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer); +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); + +/* code support functions */ +static luaL_Reg func[] = { + { "dot", mime_global_dot }, + { "b64", mime_global_b64 }, + { "eol", mime_global_eol }, + { "qp", mime_global_qp }, + { "qpwrp", mime_global_qpwrp }, + { "unb64", mime_global_unb64 }, + { "unqp", mime_global_unqp }, + { "wrp", mime_global_wrp }, + { NULL, NULL } +}; + +/*-------------------------------------------------------------------------*\ +* Quoted-printable globals +\*-------------------------------------------------------------------------*/ +static UC qpclass[256]; +static UC qpbase[] = "0123456789ABCDEF"; +static UC qpunbase[256]; +enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; + +/*-------------------------------------------------------------------------*\ +* Base64 globals +\*-------------------------------------------------------------------------*/ +static const UC b64base[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static UC b64unbase[256]; + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +MIME_API int luaopen_mime_core(lua_State *L) +{ + luaL_openlib(L, "mime", func, 0); + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, MIME_VERSION); + lua_rawset(L, -3); + /* initialize lookup tables */ + qpsetup(qpclass, qpunbase); + b64setup(b64unbase); + return 1; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Incrementaly breaks a string into lines. The string can have CRLF breaks. +* A, n = wrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +\*-------------------------------------------------------------------------*/ +static int mime_global_wrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end of input black-hole */ + if (!input) { + /* if last line has not been terminated, add a line break */ + if (left < length) lua_pushstring(L, CRLF); + /* otherwise, we are done */ + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + luaL_addstring(&buffer, CRLF); + left = length; + break; + default: + if (left <= 0) { + left = length; + luaL_addstring(&buffer, CRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Fill base64 decode map. +\*-------------------------------------------------------------------------*/ +static void b64setup(UC *unbase) +{ + int i; + for (i = 0; i <= 255; i++) unbase[i] = (UC) 255; + for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i; + unbase['='] = 0; +} + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 3 bytes are available. +* Translate the 3 bytes into Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64encode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + input[size++] = c; + if (size == 3) { + UC code[4]; + unsigned long value = 0; + value += input[0]; value <<= 8; + value += input[1]; value <<= 8; + value += input[2]; + code[3] = b64base[value & 0x3f]; value >>= 6; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + size = 0; + } + return size; +} + +/*-------------------------------------------------------------------------*\ +* Encodes the Base64 last 1 or 2 bytes and adds padding '=' +* Result, if any, is appended to buffer. +* Returns 0. +\*-------------------------------------------------------------------------*/ +static size_t b64pad(const UC *input, size_t size, + luaL_Buffer *buffer) +{ + unsigned long value = 0; + UC code[4] = {'=', '=', '=', '='}; + switch (size) { + case 1: + value = input[0] << 4; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + case 2: + value = input[0]; value <<= 8; + value |= input[1]; value <<= 2; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + default: + break; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 4 bytes are available. +* Translate the 4 bytes from Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64decode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + /* ignore invalid characters */ + if (b64unbase[c] > 64) return size; + input[size++] = c; + /* decode atom */ + if (size == 4) { + UC decoded[3]; + int valid, value = 0; + value = b64unbase[input[0]]; value <<= 6; + value |= b64unbase[input[1]]; value <<= 6; + value |= b64unbase[input[2]]; value <<= 6; + value |= b64unbase[input[3]]; + decoded[2] = (UC) (value & 0xff); value >>= 8; + decoded[1] = (UC) (value & 0xff); value >>= 8; + decoded[0] = (UC) value; + /* take care of paddding */ + valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; + luaL_addlstring(buffer, (char *) decoded, valid); + return 0; + /* need more data */ + } else return size; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies the Base64 transfer content encoding to a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 3. B has the remaining bytes of C .. D, *without* encoding. +* The easiest thing would be to concatenate the two strings and +* encode the result, but we can't afford that or Lua would dupplicate +* every chunk we received. +\*-------------------------------------------------------------------------*/ +static int mime_global_b64(lua_State *L) +{ + UC atom[3]; + size_t isize = 0, asize = 0; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + size_t osize = 0; + asize = b64pad(atom, asize, &buffer); + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process the second part */ + last = input + isize; + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally removes the Base64 transfer content encoding from a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 4. B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unb64(lua_State *L) +{ + UC atom[4]; + size_t isize = 0, asize = 0; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second is nil, we are done */ + if (!input) { + size_t osize = 0; + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise, process the rest of the input */ + last = input + isize; + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Quoted-printable encoding scheme +* all (except CRLF in text) can be =XX +* CLRL in not text must be =XX=XX +* 33 through 60 inclusive can be plain +* 62 through 126 inclusive can be plain +* 9 and 32 can be plain, unless in the end of a line, where must be =XX +* encoded lines must be no longer than 76 not counting CRLF +* soft line-break are =CRLF +* To encode one byte, we need to see the next two. +* Worst case is when we see a space, and wonder if a CRLF is comming +\*-------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------*\ +* Split quoted-printable characters into classes +* Precompute reverse map for encoding +\*-------------------------------------------------------------------------*/ +static void qpsetup(UC *cl, UC *unbase) +{ + int i; + for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; + for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; + for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN; + cl['\t'] = QP_IF_LAST; + cl[' '] = QP_IF_LAST; + cl['\r'] = QP_CR; + for (i = 0; i < 256; i++) unbase[i] = 255; + unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2; + unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5; + unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8; + unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10; + unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12; + unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13; + unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15; + unbase['f'] = 15; +} + +/*-------------------------------------------------------------------------*\ +* Output one character in form =XX +\*-------------------------------------------------------------------------*/ +static void qpquote(UC c, luaL_Buffer *buffer) +{ + luaL_addchar(buffer, '='); + luaL_addchar(buffer, qpbase[c >> 4]); + luaL_addchar(buffer, qpbase[c & 0x0F]); +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer) +{ + input[size++] = c; + /* deal with all characters we can have */ + while (size > 0) { + switch (qpclass[input[0]]) { + /* might be the CR of a CRLF sequence */ + case QP_CR: + if (size < 2) return size; + if (input[1] == '\n') { + luaL_addstring(buffer, marker); + return 0; + } else qpquote(input[0], buffer); + break; + /* might be a space and that has to be quoted if last in line */ + case QP_IF_LAST: + if (size < 3) return size; + /* if it is the last, quote it and we are done */ + if (input[1] == '\r' && input[2] == '\n') { + qpquote(input[0], buffer); + luaL_addstring(buffer, marker); + return 0; + } else luaL_addchar(buffer, input[0]); + break; + /* might have to be quoted always */ + case QP_QUOTED: + qpquote(input[0], buffer); + break; + /* might never have to be quoted */ + default: + luaL_addchar(buffer, input[0]); + break; + } + input[0] = input[1]; input[1] = input[2]; + size--; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Deal with the final characters +\*-------------------------------------------------------------------------*/ +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) +{ + size_t i; + for (i = 0; i < size; i++) { + if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]); + else qpquote(input[i], buffer); + } + if (size > 0) luaL_addstring(buffer, EQCRLF); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally converts a string to quoted-printable +* A, B = qp(C, D, marker) +* Marker is the text to be used to replace CRLF sequences found in A. +* A is the encoded version of the largest prefix of C .. D that +* can be encoded without doubts. +* B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_qp(lua_State *L) +{ + + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 3); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + asize = qppad(atom, asize, &buffer); + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output the to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { + int d; + input[size++] = c; + /* deal with all characters we can deal */ + switch (input[0]) { + /* if we have an escape character */ + case '=': + if (size < 3) return size; + /* eliminate soft line break */ + if (input[1] == '\r' && input[2] == '\n') return 0; + /* decode quoted representation */ + c = qpunbase[input[1]]; d = qpunbase[input[2]]; + /* if it is an invalid, do not decode */ + if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); + else luaL_addchar(buffer, (char) ((c << 4) + d)); + return 0; + case '\r': + if (size < 2) return size; + if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); + return 0; + default: + if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) + luaL_addchar(buffer, input[0]); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally decodes a string in quoted-printable +* A, B = qp(C, D) +* A is the decoded version of the largest prefix of C .. D that +* can be decoded without doubts. +* B has the remaining bytes of C .. D, *without* decoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unqp(lua_State *L) +{ + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + input = (UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally breaks a quoted-printed string into lines +* A, n = qpwrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +* There are two complications: lines can't be broken in the middle +* of an encoded =XX, and there might be line breaks already +\*-------------------------------------------------------------------------*/ +static int mime_global_qpwrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + if (left < length) lua_pushstring(L, EQCRLF); + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + left = length; + luaL_addstring(&buffer, CRLF); + break; + case '=': + if (left <= 3) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + default: + if (left <= 1) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Here is what we do: \n, and \r are considered candidates for line +* break. We issue *one* new line marker if any of them is seen alone, or +* followed by a different one. That is, \n\n and \r\r will issue two +* end of line markers each, but \r\n, \n\r etc will only issue *one* +* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as +* probably other more obscure conventions. +* +* c is the current character being processed +* last is the previous character +\*-------------------------------------------------------------------------*/ +#define eolcandidate(c) (c == '\r' || c == '\n') +static int eolprocess(int c, int last, const char *marker, + luaL_Buffer *buffer) +{ + if (eolcandidate(c)) { + if (eolcandidate(last)) { + if (c == last) luaL_addstring(buffer, marker); + return 0; + } else { + luaL_addstring(buffer, marker); + return c; + } + } else { + luaL_addchar(buffer, (char) c); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Converts a string to uniform EOL convention. +* A, n = eol(o, B, marker) +* A is the converted version of the largest prefix of B that can be +* converted unambiguously. 'o' is the context returned by the previous +* call. 'n' is the new context. +\*-------------------------------------------------------------------------*/ +static int mime_global_eol(lua_State *L) +{ + int ctx = luaL_checkint(L, 1); + size_t isize = 0; + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + luaL_buffinit(L, &buffer); + /* end of input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 0); + return 2; + } + /* process all input */ + while (input < last) + ctx = eolprocess(*input++, ctx, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, ctx); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Takes one byte and stuff it if needed. +\*-------------------------------------------------------------------------*/ +static size_t dot(int c, size_t state, luaL_Buffer *buffer) +{ + luaL_addchar(buffer, (char) c); + switch (c) { + case '\r': + return 1; + case '\n': + return (state == 1)? 2: 0; + case '.': + if (state == 2) + luaL_addchar(buffer, '.'); + default: + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies smtp stuffing to a string +* A, n = dot(l, D) +\*-------------------------------------------------------------------------*/ +static int mime_global_dot(lua_State *L) +{ + size_t isize = 0, state = (size_t) luaL_checknumber(L, 1); + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 2); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) + state = dot(*input++, state, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, (lua_Number) state); + return 2; +} + diff --git a/cocos/scripting/lua/bindings/socket/mime.h b/cocos/scripting/lua/bindings/socket/mime.h new file mode 100644 index 0000000000..150e7adf91 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/mime.h @@ -0,0 +1,29 @@ +#ifndef MIME_H +#define MIME_H +/*=========================================================================*\ +* Core MIME support +* LuaSocket toolkit +* +* This module provides functions to implement transfer content encodings +* and formatting conforming to RFC 2045. It is used by mime.lua, which +* provide a higher level interface to this functionality. +\*=========================================================================*/ +#include "lua.h" + +/*-------------------------------------------------------------------------*\ +* Current MIME library version +\*-------------------------------------------------------------------------*/ +#define MIME_VERSION "MIME 1.0.3-rc1" +#define MIME_COPYRIGHT "Copyright (C) 2004-2012 Diego Nehab" +#define MIME_AUTHORS "Diego Nehab" + +/*-------------------------------------------------------------------------*\ +* This macro prefixes all exported API functions +\*-------------------------------------------------------------------------*/ +#ifndef MIME_API +#define MIME_API extern +#endif + +MIME_API int luaopen_mime_core(lua_State *L); + +#endif /* MIME_H */ diff --git a/cocos/scripting/lua/bindings/socket/options.c b/cocos/scripting/lua/bindings/socket/options.c new file mode 100644 index 0000000000..6cae7eeb92 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/options.c @@ -0,0 +1,262 @@ +/*=========================================================================*\ +* Common option interface +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lauxlib.h" + +#include "auxiliar.h" +#include "options.h" +#include "inet.h" + +/*=========================================================================*\ +* Internal functions prototypes +\*=========================================================================*/ +static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); +static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); +static int opt_set(lua_State *L, p_socket ps, int level, int name, + void *val, int len); +static int opt_get(lua_State *L, p_socket ps, int level, int name, + void *val, int* len); + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Calls appropriate option handler +\*-------------------------------------------------------------------------*/ +int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps) +{ + const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) { + char msg[45]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); +} + +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) +{ + const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) { + char msg[45]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); +} + +/* enables reuse of local address */ +int opt_set_reuseaddr(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); +} + +int opt_get_reuseaddr(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); +} + +/* enables reuse of local port */ +int opt_set_reuseport(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); +} + +int opt_get_reuseport(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); +} + +/* disables the Naggle algorithm */ +int opt_set_tcp_nodelay(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); +} + +int opt_get_tcp_nodelay(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); +} + +int opt_set_keepalive(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); +} + +int opt_get_keepalive(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); +} + +int opt_set_dontroute(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); +} + +int opt_set_broadcast(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); +} + +int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +int opt_get_ip_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +int opt_set_linger(lua_State *L, p_socket ps) +{ + struct linger li; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "on"); + lua_gettable(L, 3); + if (!lua_isboolean(L, -1)) + luaL_argerror(L, 3, "boolean 'on' field expected"); + li.l_onoff = (u_short) lua_toboolean(L, -1); + lua_pushstring(L, "timeout"); + lua_gettable(L, 3); + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 3, "number 'timeout' field expected"); + li.l_linger = (u_short) lua_tonumber(L, -1); + return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); +} + +int opt_get_linger(lua_State *L, p_socket ps) +{ + struct linger li; /* obj, name */ + int len = sizeof(li); + int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len); + if (err) + return err; + lua_newtable(L); + lua_pushboolean(L, li.l_onoff); + lua_setfield(L, -2, "on"); + lua_pushinteger(L, li.l_linger); + lua_setfield(L, -2, "timeout"); + return 1; +} + +int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) +{ + int val = (int) luaL_checknumber(L, 3); /* obj, name, int */ + return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_TTL, + (char *) &val, sizeof(val)); +} + +int opt_set_ip_multicast_if(lua_State *L, p_socket ps) +{ + const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ + struct in_addr val; + val.s_addr = htonl(INADDR_ANY); + if (strcmp(address, "*") && !inet_aton(address, &val)) + luaL_argerror(L, 3, "ip expected"); + return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF, + (char *) &val, sizeof(val)); +} + +int opt_get_ip_multicast_if(lua_State *L, p_socket ps) +{ + struct in_addr val; + socklen_t len = sizeof(val); + if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + lua_pushstring(L, inet_ntoa(val)); + return 1; +} + +int opt_set_ip_add_membership(lua_State *L, p_socket ps) +{ + return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); +} + +int opt_set_ip_drop_membersip(lua_State *L, p_socket ps) +{ + return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); +} + +int opt_set_ip6_v6only(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); +} + +/*=========================================================================*\ +* Auxiliar functions +\*=========================================================================*/ +static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) +{ + struct ip_mreq val; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'multiaddr' field expected"); + if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'interface' field expected"); + val.imr_interface.s_addr = htonl(INADDR_ANY); + if (strcmp(lua_tostring(L, -1), "*") && + !inet_aton(lua_tostring(L, -1), &val.imr_interface)) + luaL_argerror(L, 3, "invalid 'interface' ip address"); + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + +static +int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) +{ + socklen_t socklen = *len; + if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + *len = socklen; + return 0; +} + +static +int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) +{ + if (setsockopt(*ps, level, name, (char *) val, len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) +{ + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char *) &val, &len); + if (err) + return err; + lua_pushboolean(L, val); + return 1; +} + +static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) +{ + int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + diff --git a/cocos/scripting/lua/bindings/socket/options.h b/cocos/scripting/lua/bindings/socket/options.h new file mode 100644 index 0000000000..55447f78f4 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/options.h @@ -0,0 +1,50 @@ +#ifndef OPTIONS_H +#define OPTIONS_H +/*=========================================================================*\ +* Common option interface +* LuaSocket toolkit +* +* This module provides a common interface to socket options, used mainly by +* modules UDP and TCP. +\*=========================================================================*/ + +#include "lua.h" +#include "socket.h" + +/* option registry */ +typedef struct t_opt { + const char *name; + int (*func)(lua_State *L, p_socket ps); +} t_opt; +typedef t_opt *p_opt; + +/* supported options for setoption */ +int opt_set_dontroute(lua_State *L, p_socket ps); +int opt_set_broadcast(lua_State *L, p_socket ps); +int opt_set_reuseaddr(lua_State *L, p_socket ps); +int opt_set_tcp_nodelay(lua_State *L, p_socket ps); +int opt_set_keepalive(lua_State *L, p_socket ps); +int opt_set_linger(lua_State *L, p_socket ps); +int opt_set_reuseaddr(lua_State *L, p_socket ps); +int opt_set_reuseport(lua_State *L, p_socket ps); +int opt_set_ip_multicast_if(lua_State *L, p_socket ps); +int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps); +int opt_set_ip_multicast_loop(lua_State *L, p_socket ps); +int opt_set_ip_add_membership(lua_State *L, p_socket ps); +int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); +int opt_set_ip6_v6only(lua_State *L, p_socket ps); + +/* supported options for getoption */ +int opt_get_reuseaddr(lua_State *L, p_socket ps); +int opt_get_tcp_nodelay(lua_State *L, p_socket ps); +int opt_get_keepalive(lua_State *L, p_socket ps); +int opt_get_linger(lua_State *L, p_socket ps); +int opt_get_reuseaddr(lua_State *L, p_socket ps); +int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); +int opt_get_ip_multicast_if(lua_State *L, p_socket ps); + +/* invokes the appropriate option handler */ +int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); + +#endif diff --git a/cocos/scripting/lua/bindings/socket/select.c b/cocos/scripting/lua/bindings/socket/select.c new file mode 100644 index 0000000000..51fb198611 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/select.c @@ -0,0 +1,216 @@ +/*=========================================================================*\ +* Select implementation +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "socket.h" +#include "timeout.h" +#include "select.h" + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static t_socket getfd(lua_State *L); +static int dirty(lua_State *L); +static void collect_fd(lua_State *L, int tab, int itab, + fd_set *set, t_socket *max_fd); +static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); +static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, + int itab, int tab, int start); +static void make_assoc(lua_State *L, int tab); +static int global_select(lua_State *L); + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"select", global_select}, + {NULL, NULL} +}; + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int select_open(lua_State *L) { + lua_pushstring(L, "_SETSIZE"); + lua_pushnumber(L, FD_SETSIZE); + lua_rawset(L, -3); + luaL_openlib(L, NULL, func, 0); + return 0; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Waits for a set of sockets until a condition is met or timeout. +\*-------------------------------------------------------------------------*/ +static int global_select(lua_State *L) { + int rtab, wtab, itab, ret, ndirty; + t_socket max_fd = SOCKET_INVALID; + fd_set rset, wset; + t_timeout tm; + double t = luaL_optnumber(L, 3, -1); + FD_ZERO(&rset); FD_ZERO(&wset); + lua_settop(L, 3); + lua_newtable(L); itab = lua_gettop(L); + lua_newtable(L); rtab = lua_gettop(L); + lua_newtable(L); wtab = lua_gettop(L); + collect_fd(L, 1, itab, &rset, &max_fd); + collect_fd(L, 2, itab, &wset, &max_fd); + ndirty = check_dirty(L, 1, rtab, &rset); + t = ndirty > 0? 0.0: t; + timeout_init(&tm, t, -1); + timeout_markstart(&tm); + ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); + if (ret > 0 || ndirty > 0) { + return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); + return_fd(L, &wset, max_fd+1, itab, wtab, 0); + make_assoc(L, rtab); + make_assoc(L, wtab); + return 2; + } else if (ret == 0) { + lua_pushstring(L, "timeout"); + return 3; + } else { + luaL_error(L, "select failed"); + return 3; + } +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +static t_socket getfd(lua_State *L) { + t_socket fd = SOCKET_INVALID; + lua_pushstring(L, "getfd"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + if (lua_isnumber(L, -1)) { + double numfd = lua_tonumber(L, -1); + fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID; + } + } + lua_pop(L, 1); + return fd; +} + +static int dirty(lua_State *L) { + int is = 0; + lua_pushstring(L, "dirty"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + is = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return is; +} + +static void collect_fd(lua_State *L, int tab, int itab, + fd_set *set, t_socket *max_fd) { + int i = 1, n = 0; + /* nil is the same as an empty table */ + if (lua_isnil(L, tab)) return; + /* otherwise we need it to be a table */ + luaL_checktype(L, tab, LUA_TTABLE); + for ( ;; ) { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + break; + } + /* getfd figures out if this is a socket */ + fd = getfd(L); + if (fd != SOCKET_INVALID) { + /* make sure we don't overflow the fd_set */ +#ifdef _WIN32 + if (n >= FD_SETSIZE) + luaL_argerror(L, tab, "too many sockets"); +#else + if (fd >= FD_SETSIZE) + luaL_argerror(L, tab, "descriptor too large for set size"); +#endif + FD_SET(fd, set); + n++; + /* keep track of the largest descriptor so far */ + if (*max_fd == SOCKET_INVALID || *max_fd < fd) + *max_fd = fd; + /* make sure we can map back from descriptor to the object */ + lua_pushnumber(L, (lua_Number) fd); + lua_pushvalue(L, -2); + lua_settable(L, itab); + } + lua_pop(L, 1); + i = i + 1; + } +} + +static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) { + int ndirty = 0, i = 1; + if (lua_isnil(L, tab)) + return 0; + for ( ;; ) { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + break; + } + fd = getfd(L); + if (fd != SOCKET_INVALID && dirty(L)) { + lua_pushnumber(L, ++ndirty); + lua_pushvalue(L, -2); + lua_settable(L, dtab); + FD_CLR(fd, set); + } + lua_pop(L, 1); + i = i + 1; + } + return ndirty; +} + +static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, + int itab, int tab, int start) { + t_socket fd; + for (fd = 0; fd < max_fd; fd++) { + if (FD_ISSET(fd, set)) { + lua_pushnumber(L, ++start); + lua_pushnumber(L, (lua_Number) fd); + lua_gettable(L, itab); + lua_settable(L, tab); + } + } +} + +static void make_assoc(lua_State *L, int tab) { + int i = 1, atab; + lua_newtable(L); atab = lua_gettop(L); + for ( ;; ) { + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (!lua_isnil(L, -1)) { + lua_pushnumber(L, i); + lua_pushvalue(L, -2); + lua_settable(L, atab); + lua_pushnumber(L, i); + lua_settable(L, atab); + } else { + lua_pop(L, 1); + break; + } + i = i+1; + } +} + diff --git a/cocos/scripting/lua/bindings/socket/select.h b/cocos/scripting/lua/bindings/socket/select.h new file mode 100644 index 0000000000..8750200395 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/select.h @@ -0,0 +1,15 @@ +#ifndef SELECT_H +#define SELECT_H +/*=========================================================================*\ +* Select implementation +* LuaSocket toolkit +* +* Each object that can be passed to the select function has to export +* method getfd() which returns the descriptor to be passed to the +* underlying select function. Another method, dirty(), should return +* true if there is data ready for reading (required for buffered input). +\*=========================================================================*/ + +int select_open(lua_State *L); + +#endif /* SELECT_H */ diff --git a/cocos/scripting/lua/bindings/socket/serial.c b/cocos/scripting/lua/bindings/socket/serial.c new file mode 100644 index 0000000000..5b09e76830 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/serial.c @@ -0,0 +1,183 @@ +/*=========================================================================*\ +* Serial stream +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "auxiliar.h" +#include "socket.h" +#include "options.h" +#include "unix.h" +#include + +/* +Reuses userdata definition from unix.h, since it is useful for all +stream-like objects. + +If we stored the serial path for use in error messages or userdata +printing, we might need our own userdata definition. + +Group usage is semi-inherited from unix.c, but unnecessary since we +have only one object type. +*/ + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int meth_send(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_close(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); + +/* serial object methods */ +static luaL_Reg serial_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"close", meth_close}, + {"dirty", meth_dirty}, + {"getfd", meth_getfd}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"settimeout", meth_settimeout}, + {NULL, NULL} +}; + +/* our socket creation function */ +static luaL_Reg func[] = { + {"serial", global_create}, + {NULL, NULL} +}; + + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_serial(lua_State *L) { + /* create classes */ + auxiliar_newclass(L, "serial{client}", serial_methods); + /* create class groups */ + auxiliar_add2group(L, "serial{client}", "serial{any}"); + /* make sure the function ends up in the package table */ + luaL_openlib(L, "socket", func, 0); + /* return the function instead of the 'socket' table */ + lua_pushstring(L, "serial"); + lua_gettable(L, -2); + return 1; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_send(L, &un->buf); +} + +static int meth_receive(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_receive(L, &un->buf); +} + +static int meth_getstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_getstats(L, &un->buf); +} + +static int meth_setstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "serial{client}", 1); + return buffer_meth_setstats(L, &un->buf); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + lua_pushnumber(L, (int) un->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + un->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + lua_pushboolean(L, !buffer_isempty(&un->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + socket_destroy(&un->sock); + lua_pushnumber(L, 1); + return 1; +} + + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1); + return timeout_meth_settimeout(L, &un->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ + + +/*-------------------------------------------------------------------------*\ +* Creates a serial object +\*-------------------------------------------------------------------------*/ +static int global_create(lua_State *L) { + const char* path = luaL_checkstring(L, 1); + + /* allocate unix object */ + p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + + /* open serial device */ + t_socket sock = open(path, O_NOCTTY|O_RDWR); + + /*printf("open %s on %d\n", path, sock);*/ + + if (sock < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + lua_pushnumber(L, errno); + return 3; + } + /* set its type as client object */ + auxiliar_setclass(L, "serial{client}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + un->sock = sock; + io_init(&un->io, (p_send) socket_write, (p_recv) socket_read, + (p_error) socket_ioerror, &un->sock); + timeout_init(&un->tm, -1, -1); + buffer_init(&un->buf, &un->io, &un->tm); + return 1; +} diff --git a/cocos/scripting/lua/bindings/socket/socket.h b/cocos/scripting/lua/bindings/socket/socket.h new file mode 100644 index 0000000000..03fa186b8a --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/socket.h @@ -0,0 +1,78 @@ +#ifndef SOCKET_H +#define SOCKET_H +/*=========================================================================*\ +* Socket compatibilization module +* LuaSocket toolkit +* +* BSD Sockets and WinSock are similar, but there are a few irritating +* differences. Also, not all *nix platforms behave the same. This module +* (and the associated usocket.h and wsocket.h) factor these differences and +* creates a interface compatible with the io.h module. +\*=========================================================================*/ +#include "luasocket_io.h" + +/*=========================================================================*\ +* Platform specific compatibilization +\*=========================================================================*/ +#ifdef _WIN32 +#include "wsocket.h" +#else +#include "usocket.h" +#endif + +/*=========================================================================*\ +* The connect and accept functions accept a timeout and their +* implementations are somewhat complicated. We chose to move +* the timeout control into this module for these functions in +* order to simplify the modules that use them. +\*=========================================================================*/ +#include "timeout.h" + +/* we are lazy... */ +typedef struct sockaddr SA; + +/*=========================================================================*\ +* Functions bellow implement a comfortable platform independent +* interface to sockets +\*=========================================================================*/ +int socket_open(void); +int socket_close(void); +void socket_destroy(p_socket ps); +void socket_shutdown(p_socket ps, int how); +int socket_sendto(p_socket ps, const char *data, size_t count, + size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm); +int socket_recvfrom(p_socket ps, char *data, size_t count, + size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm); + +void socket_setnonblocking(p_socket ps); +void socket_setblocking(p_socket ps); + +int socket_waitfd(p_socket ps, int sw, p_timeout tm); +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm); + +int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm); +int socket_create(p_socket ps, int domain, int type, int protocol); +int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); +int socket_listen(p_socket ps, int backlog); +int socket_accept(p_socket ps, p_socket pa, SA *addr, + socklen_t *addr_len, p_timeout tm); + +const char *socket_hoststrerror(int err); +const char *socket_gaistrerror(int err); +const char *socket_strerror(int err); + +/* these are perfect to use with the io abstraction module + and the buffered input module */ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm); +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); +int socket_write(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm); +int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); +const char *socket_ioerror(p_socket ps, int err); + +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); +int socket_gethostbyname(const char *addr, struct hostent **hp); + +#endif /* SOCKET_H */ diff --git a/cocos/scripting/lua/bindings/socket/socket_scripts.c.REMOVED.git-id b/cocos/scripting/lua/bindings/socket/socket_scripts.c.REMOVED.git-id new file mode 100644 index 0000000000..f8ab743b49 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/socket_scripts.c.REMOVED.git-id @@ -0,0 +1 @@ +e79358cdf4b02c66a50e684543e505002bdbcc91 \ No newline at end of file diff --git a/cocos/scripting/lua/bindings/socket/socket_scripts.h b/cocos/scripting/lua/bindings/socket/socket_scripts.h new file mode 100644 index 0000000000..939fcb2d03 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/socket_scripts.h @@ -0,0 +1,32 @@ + +/* socket_scripts.h */ + +#ifndef __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_ +#define __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_ + +#if __cplusplus +extern "C" { +#endif + +#include "lua.h" + +void luaopen_socket_scripts(lua_State* L); + +/* +int luaopen_lua_m_ltn12(lua_State* L); +int luaopen_lua_m_mime(lua_State* L); +int luaopen_lua_m_socket_ftp(lua_State* L); +int luaopen_lua_m_socket_headers(lua_State* L); +int luaopen_lua_m_socket_http(lua_State* L); +int luaopen_lua_m_socket_mbox(lua_State* L); +int luaopen_lua_m_socket_smtp(lua_State* L); +int luaopen_lua_m_socket_tp(lua_State* L); +int luaopen_lua_m_socket_url(lua_State* L); +int luaopen_lua_m_socket(lua_State* L); +*/ + +#if __cplusplus +} +#endif + +#endif /* __LUA_MODULES_E58C07CB2FBAF5B178B7E1836DC22849_H_ */ diff --git a/cocos/scripting/lua/bindings/socket/tcp.c b/cocos/scripting/lua/bindings/socket/tcp.c new file mode 100644 index 0000000000..6734dc0b49 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/tcp.c @@ -0,0 +1,475 @@ +/*=========================================================================*\ +* TCP object +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "auxiliar.h" +#include "socket.h" +#include "inet.h" +#include "options.h" +#include "tcp.h" + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int global_create6(lua_State *L); +static int global_connect(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_listen(lua_State *L); +static int meth_getfamily(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_shutdown(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_accept(lua_State *L); +static int meth_close(lua_State *L); +static int meth_getoption(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); + +/* tcp object methods */ +static luaL_Reg tcp_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"accept", meth_accept}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getoption", meth_getoption}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"listen", meth_listen}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"settimeout", meth_settimeout}, + {"shutdown", meth_shutdown}, + {NULL, NULL} +}; + +/* socket option handlers */ +static t_opt optget[] = { + {"keepalive", opt_get_keepalive}, + {"reuseaddr", opt_get_reuseaddr}, + {"tcp-nodelay", opt_get_tcp_nodelay}, + {"linger", opt_get_linger}, + {NULL, NULL} +}; + +static t_opt optset[] = { + {"keepalive", opt_set_keepalive}, + {"reuseaddr", opt_set_reuseaddr}, + {"tcp-nodelay", opt_set_tcp_nodelay}, + {"ipv6-v6only", opt_set_ip6_v6only}, + {"linger", opt_set_linger}, + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"tcp", global_create}, + {"tcp6", global_create6}, + {"connect", global_connect}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int tcp_open(lua_State *L) +{ + /* create classes */ + auxiliar_newclass(L, "tcp{master}", tcp_methods); + auxiliar_newclass(L, "tcp{client}", tcp_methods); + auxiliar_newclass(L, "tcp{server}", tcp_methods); + /* create class groups */ + auxiliar_add2group(L, "tcp{master}", "tcp{any}"); + auxiliar_add2group(L, "tcp{client}", "tcp{any}"); + auxiliar_add2group(L, "tcp{server}", "tcp{any}"); + /* define library functions */ + luaL_openlib(L, NULL, func, 0); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_send(L, &tcp->buf); +} + +static int meth_receive(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_receive(L, &tcp->buf); +} + +static int meth_getstats(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_getstats(L, &tcp->buf); +} + +static int meth_setstats(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_setstats(L, &tcp->buf); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_getoption(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_getoption(L, optget, &tcp->sock); +} + +static int meth_setoption(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_setoption(L, optset, &tcp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushnumber(L, (int) tcp->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + tcp->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushboolean(L, !buffer_isempty(&tcp->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Waits for and returns a client object attempting connection to the +* server object +\*-------------------------------------------------------------------------*/ +static int meth_accept(lua_State *L) +{ + p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); + p_timeout tm = timeout_markstart(&server->tm); + t_socket sock; + const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm); + /* if successful, push client socket */ + if (err == NULL) { + p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + auxiliar_setclass(L, "tcp{client}", -1); + /* initialize structure fields */ + memset(clnt, 0, sizeof(t_tcp)); + socket_setnonblocking(&sock); + clnt->sock = sock; + io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &clnt->sock); + timeout_init(&clnt->tm, -1, -1); + buffer_init(&clnt->buf, &clnt->io, &clnt->tm); + clnt->family = server->family; + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } +} + +/*-------------------------------------------------------------------------*\ +* Binds an object to an address +\*-------------------------------------------------------------------------*/ +static int meth_bind(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = tcp->family; + bindhints.ai_flags = AI_PASSIVE; + address = strcmp(address, "*")? address: NULL; + err = inet_trybind(&tcp->sock, address, port, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master tcp object into a client object. +\*-------------------------------------------------------------------------*/ +static int meth_connect(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->family; + timeout_markstart(&tcp->tm); + err = inet_tryconnect(&tcp->sock, address, port, &tcp->tm, &connecthints); + /* have to set the class even if it failed due to non-blocking connects */ + auxiliar_setclass(L, "tcp{client}", 1); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + socket_destroy(&tcp->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Returns family as string +\*-------------------------------------------------------------------------*/ +static int meth_getfamily(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + if (tcp->family == PF_INET6) { + lua_pushliteral(L, "inet6"); + return 1; + } else { + lua_pushliteral(L, "inet4"); + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Puts the sockt in listen mode +\*-------------------------------------------------------------------------*/ +static int meth_listen(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); + int backlog = (int) luaL_optnumber(L, 2, 32); + int err = socket_listen(&tcp->sock, backlog); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } + /* turn master object into a server object */ + auxiliar_setclass(L, "tcp{server}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Shuts the connection down partially +\*-------------------------------------------------------------------------*/ +static int meth_shutdown(lua_State *L) +{ + /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ + static const char* methods[] = { "receive", "send", "both", NULL }; + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + int how = luaL_checkoption(L, 2, "both", methods); + socket_shutdown(&tcp->sock, how); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call inet methods +\*-------------------------------------------------------------------------*/ +static int meth_getpeername(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getpeername(L, &tcp->sock, tcp->family); +} + +static int meth_getsockname(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getsockname(L, &tcp->sock, tcp->family); +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return timeout_meth_settimeout(L, &tcp->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master tcp object +\*-------------------------------------------------------------------------*/ +static int tcp_create(lua_State *L, int family) { + t_socket sock; + const char *err = inet_trycreate(&sock, family, SOCK_STREAM); + /* try to allocate a system socket */ + if (!err) { + /* allocate tcp object */ + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + memset(tcp, 0, sizeof(t_tcp)); + /* set its type as master object */ + auxiliar_setclass(L, "tcp{master}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + if (family == PF_INET6) { + int yes = 1; + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (void *)&yes, sizeof(yes)); + } + tcp->sock = sock; + io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + tcp->family = family; + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } +} + +static int global_create(lua_State *L) { + return tcp_create(L, AF_INET); +} + +static int global_create6(lua_State *L) { + return tcp_create(L, AF_INET6); +} + +static const char *tryconnect6(const char *remoteaddr, const char *remoteserv, + struct addrinfo *connecthints, p_tcp tcp) { + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv, + connecthints, &resolved)); + if (err != NULL) { + if (resolved) freeaddrinfo(resolved); + return err; + } + /* iterate over all returned addresses trying to connect */ + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + p_timeout tm = timeout_markstart(&tcp->tm); + /* create new socket if one wasn't created by the bind stage */ + if (tcp->sock == SOCKET_INVALID) { + err = socket_strerror(socket_create(&tcp->sock, + iterator->ai_family, iterator->ai_socktype, + iterator->ai_protocol)); + if (err != NULL) { + freeaddrinfo(resolved); + return err; + } + tcp->family = iterator->ai_family; + /* all sockets initially non-blocking */ + socket_setnonblocking(&tcp->sock); + } + /* finally try connecting to remote address */ + err = socket_strerror(socket_connect(&tcp->sock, + (SA *) iterator->ai_addr, + (socklen_t) iterator->ai_addrlen, tm)); + /* if success, break out of loop */ + if (err == NULL) break; + } + + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; +} + +static int global_connect(lua_State *L) { + const char *remoteaddr = luaL_checkstring(L, 1); + const char *remoteserv = luaL_checkstring(L, 2); + const char *localaddr = luaL_optstring(L, 3, NULL); + const char *localserv = luaL_optstring(L, 4, "0"); + int family = inet_optfamily(L, 5, "unspec"); + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + struct addrinfo bindhints, connecthints; + const char *err = NULL; + /* initialize tcp structure */ + memset(tcp, 0, sizeof(t_tcp)); + io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + tcp->sock = SOCKET_INVALID; + /* allow user to pick local address and port */ + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = family; + bindhints.ai_flags = AI_PASSIVE; + if (localaddr) { + err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + tcp->family = bindhints.ai_family; + } + /* try to connect to remote address and port */ + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = bindhints.ai_family; + err = tryconnect6(remoteaddr, remoteserv, &connecthints, tcp); + if (err) { + socket_destroy(&tcp->sock); + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "tcp{client}", -1); + return 1; +} diff --git a/cocos/scripting/lua/bindings/socket/tcp.h b/cocos/scripting/lua/bindings/socket/tcp.h new file mode 100644 index 0000000000..a8b9b6f2cf --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/tcp.h @@ -0,0 +1,35 @@ +#ifndef TCP_H +#define TCP_H +/*=========================================================================*\ +* TCP object +* LuaSocket toolkit +* +* The tcp.h module is basicly a glue that puts together modules buffer.h, +* timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET, +* SOCK_STREAM) support. +* +* Three classes are defined: master, client and server. The master class is +* a newly created tcp object, that has not been bound or connected. Server +* objects are tcp objects bound to some local address. Client objects are +* tcp objects either connected to some address or returned by the accept +* method of a server object. +\*=========================================================================*/ +#include "lua.h" + +#include "luasocket_buffer.h" +#include "timeout.h" +#include "socket.h" + +typedef struct t_tcp_ { + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; + int family; +} t_tcp; + +typedef t_tcp *p_tcp; + +int tcp_open(lua_State *L); + +#endif /* TCP_H */ diff --git a/cocos/scripting/lua/bindings/socket/timeout.c b/cocos/scripting/lua/bindings/socket/timeout.c new file mode 100644 index 0000000000..c7354b52f3 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/timeout.c @@ -0,0 +1,217 @@ +/*=========================================================================*\ +* Timeout management functions +* LuaSocket toolkit +\*=========================================================================*/ +#include +#include +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "auxiliar.h" +#include "timeout.h" + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int timeout_lua_gettime(lua_State *L); +static int timeout_lua_sleep(lua_State *L); + +static luaL_Reg func[] = { + { "gettime", timeout_lua_gettime }, + { "sleep", timeout_lua_sleep }, + { NULL, NULL } +}; + +/*=========================================================================*\ +* Exported functions. +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initialize structure +\*-------------------------------------------------------------------------*/ +void timeout_init(p_timeout tm, double block, double total) { + tm->block = block; + tm->total = total; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was successful +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +double timeout_get(p_timeout tm) { + if (tm->block < 0.0 && tm->total < 0.0) { + return -1; + } else if (tm->block < 0.0) { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else if (tm->total < 0.0) { + return tm->block; + } else { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } +} + +/*-------------------------------------------------------------------------*\ +* Returns time since start of operation +* Input +* tm: timeout control structure +* Returns +* start field of structure +\*-------------------------------------------------------------------------*/ +double timeout_getstart(p_timeout tm) { + return tm->start; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was a failure +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +double timeout_getretry(p_timeout tm) { + if (tm->block < 0.0 && tm->total < 0.0) { + return -1; + } else if (tm->block < 0.0) { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else if (tm->total < 0.0) { + double t = tm->block - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } +} + +/*-------------------------------------------------------------------------*\ +* Marks the operation start time in structure +* Input +* tm: timeout control structure +\*-------------------------------------------------------------------------*/ +p_timeout timeout_markstart(p_timeout tm) { + tm->start = timeout_gettime(); + return tm; +} + +/*-------------------------------------------------------------------------*\ +* Gets time in s, relative to January 1, 1970 (UTC) +* Returns +* time in s. +\*-------------------------------------------------------------------------*/ +#ifdef _WIN32 +double timeout_gettime(void) { + FILETIME ft; + double t; + GetSystemTimeAsFileTime(&ft); + /* Windows file time (time since January 1, 1601 (UTC)) */ + t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7); + /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ + return (t - 11644473600.0); +} +#else +double timeout_gettime(void) { + struct timeval v; + gettimeofday(&v, (struct timezone *) NULL); + /* Unix Epoch time (time since January 1, 1970 (UTC)) */ + return v.tv_sec + v.tv_usec/1.0e6; +} +#endif + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int timeout_open(lua_State *L) { + luaL_openlib(L, NULL, func, 0); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Sets timeout values for IO operations +* Lua Input: base, time [, mode] +* time: time out value in seconds +* mode: "b" for block timeout, "t" for total timeout. (default: b) +\*-------------------------------------------------------------------------*/ +int timeout_meth_settimeout(lua_State *L, p_timeout tm) { + double t = luaL_optnumber(L, 2, -1); + const char *mode = luaL_optstring(L, 3, "b"); + switch (*mode) { + case 'b': + tm->block = t; + break; + case 'r': case 't': + tm->total = t; + break; + default: + luaL_argcheck(L, 0, 3, "invalid timeout mode"); + break; + } + lua_pushnumber(L, 1); + return 1; +} + +/*=========================================================================*\ +* Test support functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Returns the time the system has been up, in secconds. +\*-------------------------------------------------------------------------*/ +static int timeout_lua_gettime(lua_State *L) +{ + lua_pushnumber(L, timeout_gettime()); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Sleep for n seconds. +\*-------------------------------------------------------------------------*/ +#ifdef _WIN32 +int timeout_lua_sleep(lua_State *L) +{ + double n = luaL_checknumber(L, 1); + if (n < 0.0) n = 0.0; + if (n < DBL_MAX/1000.0) n *= 1000.0; + if (n > INT_MAX) n = INT_MAX; + Sleep((int)n); + return 0; +} +#else +int timeout_lua_sleep(lua_State *L) +{ + double n = luaL_checknumber(L, 1); + struct timespec t, r; + if (n < 0.0) n = 0.0; + if (n > INT_MAX) n = INT_MAX; + t.tv_sec = (int) n; + n -= t.tv_sec; + t.tv_nsec = (int) (n * 1000000000); + if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999; + while (nanosleep(&t, &r) != 0) { + t.tv_sec = r.tv_sec; + t.tv_nsec = r.tv_nsec; + } + return 0; +} +#endif diff --git a/cocos/scripting/lua/bindings/socket/timeout.h b/cocos/scripting/lua/bindings/socket/timeout.h new file mode 100644 index 0000000000..6715ca70a1 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/timeout.h @@ -0,0 +1,28 @@ +#ifndef TIMEOUT_H +#define TIMEOUT_H +/*=========================================================================*\ +* Timeout management functions +* LuaSocket toolkit +\*=========================================================================*/ +#include "lua.h" + +/* timeout control structure */ +typedef struct t_timeout_ { + double block; /* maximum time for blocking calls */ + double total; /* total number of miliseconds for operation */ + double start; /* time of start of operation */ +} t_timeout; +typedef t_timeout *p_timeout; + +int timeout_open(lua_State *L); +void timeout_init(p_timeout tm, double block, double total); +double timeout_get(p_timeout tm); +double timeout_getretry(p_timeout tm); +p_timeout timeout_markstart(p_timeout tm); +double timeout_getstart(p_timeout tm); +double timeout_gettime(void); +int timeout_meth_settimeout(lua_State *L, p_timeout tm); + +#define timeout_iszero(tm) ((tm)->block == 0.0) + +#endif /* TIMEOUT_H */ diff --git a/cocos/scripting/lua/bindings/socket/udp.c b/cocos/scripting/lua/bindings/socket/udp.c new file mode 100644 index 0000000000..c51bd9ddd2 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/udp.c @@ -0,0 +1,468 @@ +/*=========================================================================*\ +* UDP object +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "auxiliar.h" +#include "socket.h" +#include "inet.h" +#include "options.h" +#include "udp.h" + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int global_create6(lua_State *L); +static int meth_send(lua_State *L); +static int meth_sendto(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_receivefrom(lua_State *L); +static int meth_getfamily(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_setsockname(lua_State *L); +static int meth_setpeername(lua_State *L); +static int meth_close(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_getoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); + +/* udp object methods */ +static luaL_Reg udp_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"close", meth_close}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"receive", meth_receive}, + {"receivefrom", meth_receivefrom}, + {"send", meth_send}, + {"sendto", meth_sendto}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"getoption", meth_getoption}, + {"setpeername", meth_setpeername}, + {"setsockname", meth_setsockname}, + {"settimeout", meth_settimeout}, + {NULL, NULL} +}; + +/* socket options for setoption */ +static t_opt optset[] = { + {"dontroute", opt_set_dontroute}, + {"broadcast", opt_set_broadcast}, + {"reuseaddr", opt_set_reuseaddr}, + {"reuseport", opt_set_reuseport}, + {"ip-multicast-if", opt_set_ip_multicast_if}, + {"ip-multicast-ttl", opt_set_ip_multicast_ttl}, + {"ip-multicast-loop", opt_set_ip_multicast_loop}, + {"ip-add-membership", opt_set_ip_add_membership}, + {"ip-drop-membership", opt_set_ip_drop_membersip}, + {"ipv6-v6only", opt_set_ip6_v6only}, + {NULL, NULL} +}; + +/* socket options for getoption */ +static t_opt optget[] = { + {"ip-multicast-if", opt_get_ip_multicast_if}, + {"ip-multicast-loop", opt_get_ip_multicast_loop}, + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"udp", global_create}, + {"udp6", global_create6}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int udp_open(lua_State *L) +{ + /* create classes */ + auxiliar_newclass(L, "udp{connected}", udp_methods); + auxiliar_newclass(L, "udp{unconnected}", udp_methods); + /* create class groups */ + auxiliar_add2group(L, "udp{connected}", "udp{any}"); + auxiliar_add2group(L, "udp{unconnected}", "udp{any}"); + auxiliar_add2group(L, "udp{connected}", "select{able}"); + auxiliar_add2group(L, "udp{unconnected}", "select{able}"); + /* define library functions */ + luaL_openlib(L, NULL, func, 0); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +const char *udp_strerror(int err) { + /* a 'closed' error on an unconnected means the target address was not + * accepted by the transport layer */ + if (err == IO_CLOSED) return "refused"; + else return socket_strerror(err); +} + +/*-------------------------------------------------------------------------*\ +* Send data through connected udp socket +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); + p_timeout tm = &udp->tm; + size_t count, sent = 0; + int err; + const char *data = luaL_checklstring(L, 2, &count); + timeout_markstart(tm); + err = socket_send(&udp->sock, data, count, &sent, tm); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Send data through unconnected udp socket +\*-------------------------------------------------------------------------*/ +static int meth_sendto(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + size_t count, sent = 0; + const char *data = luaL_checklstring(L, 2, &count); + const char *ip = luaL_checkstring(L, 3); + unsigned short port = (unsigned short) luaL_checknumber(L, 4); + p_timeout tm = &udp->tm; + int err; + switch (udp->family) { + case PF_INET: { + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + if (!my_inet_pton(AF_INET, ip, &addr.sin_addr)) + luaL_argerror(L, 3, "invalid ip address"); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + timeout_markstart(tm); + err = socket_sendto(&udp->sock, data, count, &sent, + (SA *) &addr, sizeof(addr), tm); + break; + } + case PF_INET6: { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + if (!my_inet_pton(AF_INET6, ip, &addr.sin6_addr)) + luaL_argerror(L, 3, "invalid ip address"); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(port); + timeout_markstart(tm); + err = socket_sendto(&udp->sock, data, count, &sent, + (SA *) &addr, sizeof(addr), tm); + break; + } + default: + lua_pushnil(L); + lua_pushfstring(L, "unknown family %d", udp->family); + return 2; + } + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Receives data from a UDP socket +\*-------------------------------------------------------------------------*/ +static int meth_receive(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + char buffer[UDP_DATAGRAMSIZE]; + size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); + int err; + p_timeout tm = &udp->tm; + count = MIN(count, sizeof(buffer)); + timeout_markstart(tm); + err = socket_recv(&udp->sock, buffer, count, &got, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err == IO_CLOSED) + err = IO_DONE; + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushlstring(L, buffer, got); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Receives data and sender from a UDP socket +\*-------------------------------------------------------------------------*/ +static int meth_receivefrom(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + char buffer[UDP_DATAGRAMSIZE]; + size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer)); + int err; + p_timeout tm = &udp->tm; + timeout_markstart(tm); + count = MIN(count, sizeof(buffer)); + switch (udp->family) { + case PF_INET: { + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + err = socket_recvfrom(&udp->sock, buffer, count, &got, + (SA *) &addr, &addr_len, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err == IO_CLOSED) + err = IO_DONE; + if (err == IO_DONE) { + char addrstr[INET_ADDRSTRLEN]; + lua_pushlstring(L, buffer, got); + if (!my_inet_ntop(AF_INET, &addr.sin_addr, + addrstr, sizeof(addrstr))) { + lua_pushnil(L); + lua_pushstring(L, "invalid source address"); + return 2; + } + lua_pushstring(L, addrstr); + lua_pushnumber(L, ntohs(addr.sin_port)); + return 3; + } + break; + } + case PF_INET6: { + struct sockaddr_in6 addr; + socklen_t addr_len = sizeof(addr); + err = socket_recvfrom(&udp->sock, buffer, count, &got, + (SA *) &addr, &addr_len, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err == IO_CLOSED) + err = IO_DONE; + if (err == IO_DONE) { + char addrstr[INET6_ADDRSTRLEN]; + lua_pushlstring(L, buffer, got); + if (!my_inet_ntop(AF_INET6, &addr.sin6_addr, + addrstr, sizeof(addrstr))) { + lua_pushnil(L); + lua_pushstring(L, "invalid source address"); + return 2; + } + lua_pushstring(L, addrstr); + lua_pushnumber(L, ntohs(addr.sin6_port)); + return 3; + } + break; + } + default: + lua_pushnil(L); + lua_pushfstring(L, "unknown family %d", udp->family); + return 2; + } + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Returns family as string +\*-------------------------------------------------------------------------*/ +static int meth_getfamily(lua_State *L) +{ + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + if (udp->family == PF_INET6) { + lua_pushliteral(L, "inet6"); + return 1; + } else { + lua_pushliteral(L, "inet4"); + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + lua_pushnumber(L, (int) udp->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + udp->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + (void) udp; + lua_pushboolean(L, 0); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call inet methods +\*-------------------------------------------------------------------------*/ +static int meth_getpeername(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); + return inet_meth_getpeername(L, &udp->sock, udp->family); +} + +static int meth_getsockname(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return inet_meth_getsockname(L, &udp->sock, udp->family); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_setoption(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_setoption(L, optset, &udp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_getoption(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_getoption(L, optget, &udp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return timeout_meth_settimeout(L, &udp->tm); +} + +/*-------------------------------------------------------------------------*\ +* Turns a master udp object into a client object. +\*-------------------------------------------------------------------------*/ +static int meth_setpeername(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + p_timeout tm = &udp->tm; + const char *address = luaL_checkstring(L, 2); + int connecting = strcmp(address, "*"); + const char *port = connecting? luaL_checkstring(L, 3): "0"; + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_DGRAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = udp->family; + if (connecting) { + err = inet_tryconnect(&udp->sock, address, port, tm, &connecthints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "udp{connected}", 1); + } else { + /* we ignore possible errors because Mac OS X always + * returns EAFNOSUPPORT */ + inet_trydisconnect(&udp->sock, udp->family, tm); + auxiliar_setclass(L, "udp{unconnected}", 1); + } + /* change class to connected or unconnected depending on address */ + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + socket_destroy(&udp->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master object into a server object +\*-------------------------------------------------------------------------*/ +static int meth_setsockname(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_DGRAM; + bindhints.ai_family = udp->family; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&udp->sock, address, port, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master udp object +\*-------------------------------------------------------------------------*/ +static int udp_create(lua_State *L, int family) { + t_socket sock; + const char *err = inet_trycreate(&sock, family, SOCK_DGRAM); + /* try to allocate a system socket */ + if (!err) { + /* allocate udp object */ + p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); + auxiliar_setclass(L, "udp{unconnected}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + if (family == PF_INET6) { + int yes = 1; + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (void *)&yes, sizeof(yes)); + } + udp->sock = sock; + timeout_init(&udp->tm, -1, -1); + udp->family = family; + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } +} + +static int global_create(lua_State *L) { + return udp_create(L, AF_INET); +} + +static int global_create6(lua_State *L) { + return udp_create(L, AF_INET6); +} diff --git a/cocos/scripting/lua/bindings/socket/udp.h b/cocos/scripting/lua/bindings/socket/udp.h new file mode 100644 index 0000000000..2b831a5371 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/udp.h @@ -0,0 +1,32 @@ +#ifndef UDP_H +#define UDP_H +/*=========================================================================*\ +* UDP object +* LuaSocket toolkit +* +* The udp.h module provides LuaSocket with support for UDP protocol +* (AF_INET, SOCK_DGRAM). +* +* Two classes are defined: connected and unconnected. UDP objects are +* originally unconnected. They can be "connected" to a given address +* with a call to the setpeername function. The same function can be used to +* break the connection. +\*=========================================================================*/ +#include "lua.h" + +#include "timeout.h" +#include "socket.h" + +/* can't be larger than wsocket.c MAXCHUNK!!! */ +#define UDP_DATAGRAMSIZE 8192 + +typedef struct t_udp_ { + t_socket sock; + t_timeout tm; + int family; +} t_udp; +typedef t_udp *p_udp; + +int udp_open(lua_State *L); + +#endif /* UDP_H */ diff --git a/cocos/scripting/lua/bindings/socket/unix.c b/cocos/scripting/lua/bindings/socket/unix.c new file mode 100644 index 0000000000..28d4cc7b84 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/unix.c @@ -0,0 +1,340 @@ +/*=========================================================================*\ +* Unix domain socket +* LuaSocket toolkit +\*=========================================================================*/ +#include + +#include "lua.h" +#include "lauxlib.h" + +#include "auxiliar.h" +#include "socket.h" +#include "options.h" +#include "unix.h" +#include + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_listen(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_shutdown(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_accept(lua_State *L); +static int meth_close(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); + +static const char *unix_tryconnect(p_unix un, const char *path); +static const char *unix_trybind(p_unix un, const char *path); + +/* unix object methods */ +static luaL_Reg unix_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"accept", meth_accept}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfd", meth_getfd}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"listen", meth_listen}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"settimeout", meth_settimeout}, + {"shutdown", meth_shutdown}, + {NULL, NULL} +}; + +/* socket option handlers */ +static t_opt optset[] = { + {"keepalive", opt_set_keepalive}, + {"reuseaddr", opt_set_reuseaddr}, + {"linger", opt_set_linger}, + {NULL, NULL} +}; + +/* our socket creation function */ +static luaL_Reg func[] = { + {"unix", global_create}, + {NULL, NULL} +}; + + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int luaopen_socket_unix(lua_State *L) { + /* create classes */ + auxiliar_newclass(L, "unix{master}", unix_methods); + auxiliar_newclass(L, "unix{client}", unix_methods); + auxiliar_newclass(L, "unix{server}", unix_methods); + /* create class groups */ + auxiliar_add2group(L, "unix{master}", "unix{any}"); + auxiliar_add2group(L, "unix{client}", "unix{any}"); + auxiliar_add2group(L, "unix{server}", "unix{any}"); + /* make sure the function ends up in the package table */ + luaL_openlib(L, "socket", func, 0); + /* return the function instead of the 'socket' table */ + lua_pushstring(L, "unix"); + lua_gettable(L, -2); + return 1; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_send(L, &un->buf); +} + +static int meth_receive(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_receive(L, &un->buf); +} + +static int meth_getstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_getstats(L, &un->buf); +} + +static int meth_setstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + return buffer_meth_setstats(L, &un->buf); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_setoption(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + return opt_meth_setoption(L, optset, &un->sock); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + lua_pushnumber(L, (int) un->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + un->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + lua_pushboolean(L, !buffer_isempty(&un->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Waits for and returns a client object attempting connection to the +* server object +\*-------------------------------------------------------------------------*/ +static int meth_accept(lua_State *L) { + p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1); + p_timeout tm = timeout_markstart(&server->tm); + t_socket sock; + int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); + /* if successful, push client socket */ + if (err == IO_DONE) { + p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + auxiliar_setclass(L, "unix{client}", -1); + /* initialize structure fields */ + socket_setnonblocking(&sock); + clnt->sock = sock; + io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv, + (p_error) socket_ioerror, &clnt->sock); + timeout_init(&clnt->tm, -1, -1); + buffer_init(&clnt->buf, &clnt->io, &clnt->tm); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } +} + +/*-------------------------------------------------------------------------*\ +* Binds an object to an address +\*-------------------------------------------------------------------------*/ +static const char *unix_trybind(p_unix un, const char *path) { + struct sockaddr_un local; + size_t len = strlen(path); + int err; + if (len >= sizeof(local.sun_path)) return "path too long"; + memset(&local, 0, sizeof(local)); + strcpy(local.sun_path, path); + local.sun_family = AF_UNIX; +#ifdef UNIX_HAS_SUN_LEN + local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len) + + len + 1; + err = socket_bind(&un->sock, (SA *) &local, local.sun_len); + +#else + err = socket_bind(&un->sock, (SA *) &local, + (socklen_t)(sizeof(local.sun_family) + len)); +#endif + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_bind(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unix_trybind(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master unix object into a client object. +\*-------------------------------------------------------------------------*/ +static const char *unix_tryconnect(p_unix un, const char *path) +{ + struct sockaddr_un remote; + int err; + size_t len = strlen(path); + if (len >= sizeof(remote.sun_path)) return "path too long"; + memset(&remote, 0, sizeof(remote)); + strcpy(remote.sun_path, path); + remote.sun_family = AF_UNIX; + timeout_markstart(&un->tm); +#ifdef UNIX_HAS_SUN_LEN + remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len) + + len + 1; + err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm); +#else + err = socket_connect(&un->sock, (SA *) &remote, + (socklen_t)(sizeof(remote.sun_family) + len), &un->tm); +#endif + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_connect(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unix_tryconnect(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + /* turn master object into a client object */ + auxiliar_setclass(L, "unix{client}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + socket_destroy(&un->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Puts the sockt in listen mode +\*-------------------------------------------------------------------------*/ +static int meth_listen(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1); + int backlog = (int) luaL_optnumber(L, 2, 32); + int err = socket_listen(&un->sock, backlog); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } + /* turn master object into a server object */ + auxiliar_setclass(L, "unix{server}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Shuts the connection down partially +\*-------------------------------------------------------------------------*/ +static int meth_shutdown(lua_State *L) +{ + /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ + static const char* methods[] = { "receive", "send", "both", NULL }; + p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); + int how = luaL_checkoption(L, 2, "both", methods); + socket_shutdown(&tcp->sock, how); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1); + return timeout_meth_settimeout(L, &un->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master unix object +\*-------------------------------------------------------------------------*/ +static int global_create(lua_State *L) { + t_socket sock; + int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0); + /* try to allocate a system socket */ + if (err == IO_DONE) { + /* allocate unix object */ + p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + /* set its type as master object */ + auxiliar_setclass(L, "unix{master}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + un->sock = sock; + io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &un->sock); + timeout_init(&un->tm, -1, -1); + buffer_init(&un->buf, &un->io, &un->tm); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } +} diff --git a/cocos/scripting/lua/bindings/socket/unix.h b/cocos/scripting/lua/bindings/socket/unix.h new file mode 100644 index 0000000000..86a961b747 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/unix.h @@ -0,0 +1,26 @@ +#ifndef UNIX_H +#define UNIX_H +/*=========================================================================*\ +* Unix domain object +* LuaSocket toolkit +* +* This module is just an example of how to extend LuaSocket with a new +* domain. +\*=========================================================================*/ +#include "lua.h" +#include "luasocket.h" +#include "luasocket_buffer.h" +#include "timeout.h" +#include "socket.h" + +typedef struct t_unix_ { + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; +} t_unix; +typedef t_unix *p_unix; + +LUASOCKET_API int luaopen_socket_unix(lua_State *L); + +#endif /* UNIX_H */ diff --git a/cocos/scripting/lua/bindings/socket/usocket.c b/cocos/scripting/lua/bindings/socket/usocket.c new file mode 100644 index 0000000000..096ecd00b6 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/usocket.c @@ -0,0 +1,449 @@ +/*=========================================================================*\ +* Socket compatibilization module for Unix +* LuaSocket toolkit +* +* The code is now interrupt-safe. +* The penalty of calling select to avoid busy-wait is only paid when +* the I/O call fail in the first place. +\*=========================================================================*/ +#include +#include + +#include "socket.h" + +/*-------------------------------------------------------------------------*\ +* Wait for readable/writable/connected socket with timeout +\*-------------------------------------------------------------------------*/ +#ifndef SOCKET_SELECT +#include + +#define WAITFD_R POLLIN +#define WAITFD_W POLLOUT +#define WAITFD_C (POLLIN|POLLOUT) +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + struct pollfd pfd; + pfd.fd = *ps; + pfd.events = sw; + pfd.revents = 0; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + do { + int t = (int)(timeout_getretry(tm)*1e3); + ret = poll(&pfd, 1, t >= 0? t: -1); + } while (ret == -1 && errno == EINTR); + if (ret == -1) return errno; + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED; + return IO_DONE; +} +#else + +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_C (WAITFD_R|WAITFD_W) + +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + fd_set rfds, wfds, *rp, *wp; + struct timeval tv, *tp; + double t; + if (*ps >= FD_SETSIZE) return EINVAL; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + do { + /* must set bits within loop, because select may have modifed them */ + rp = wp = NULL; + if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; } + if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } + t = timeout_getretry(tm); + tp = NULL; + if (t >= 0.0) { + tv.tv_sec = (int)t; + tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); + tp = &tv; + } + ret = select(*ps+1, rp, wp, NULL, tp); + } while (ret == -1 && errno == EINTR); + if (ret == -1) return errno; + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED; + return IO_DONE; +} +#endif + + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int socket_open(void) { + /* instals a handler to ignore sigpipe or it will crash us */ + signal(SIGPIPE, SIG_IGN); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close module +\*-------------------------------------------------------------------------*/ +int socket_close(void) { + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close and inutilize socket +\*-------------------------------------------------------------------------*/ +void socket_destroy(p_socket ps) { + if (*ps != SOCKET_INVALID) { + socket_setblocking(ps); + close(*ps); + *ps = SOCKET_INVALID; + } +} + +/*-------------------------------------------------------------------------*\ +* Select with timeout control +\*-------------------------------------------------------------------------*/ +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm) { + int ret; + do { + struct timeval tv; + double t = timeout_getretry(tm); + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); + /* timeout = 0 means no wait */ + ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL); + } while (ret < 0 && errno == EINTR); + return ret; +} + +/*-------------------------------------------------------------------------*\ +* Creates and sets up a socket +\*-------------------------------------------------------------------------*/ +int socket_create(p_socket ps, int domain, int type, int protocol) { + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) return IO_DONE; + else return errno; +} + +/*-------------------------------------------------------------------------*\ +* Binds or returns error message +\*-------------------------------------------------------------------------*/ +int socket_bind(p_socket ps, SA *addr, socklen_t len) { + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) err = errno; + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +int socket_listen(p_socket ps, int backlog) { + int err = IO_DONE; + socket_setblocking(ps); + if (listen(*ps, backlog)) err = errno; + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +void socket_shutdown(p_socket ps, int how) { + socket_setblocking(ps); + shutdown(*ps, how); + socket_setnonblocking(ps); +} + +/*-------------------------------------------------------------------------*\ +* Connects or returns error message +\*-------------------------------------------------------------------------*/ +int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { + int err; + /* avoid calling on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* call connect until done or failed without being interrupted */ + do if (connect(*ps, addr, len) == 0) return IO_DONE; + while ((err = errno) == EINTR); + /* if connection failed immediately, return error code */ + if (err != EINPROGRESS && err != EAGAIN) return err; + /* zero timeout case optimization */ + if (timeout_iszero(tm)) return IO_TIMEOUT; + /* wait until we have the result of the connection attempt or timeout */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) { + if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; + else return errno; + } else return err; +} + +/*-------------------------------------------------------------------------*\ +* Accept with timeout +\*-------------------------------------------------------------------------*/ +int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) { + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int err; + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; + err = errno; + if (err == EINTR) continue; + if (err != EAGAIN && err != ECONNABORTED) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Send with timeout +\*-------------------------------------------------------------------------*/ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + long put = (long) send(*ps, data, count, 0); + /* if we sent anything, we are done */ + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + /* EPIPE means the connection was closed */ + if (err == EPIPE) return IO_CLOSED; + /* we call was interrupted, just try again */ + if (err == EINTR) continue; + /* if failed fatal reason, report error */ + if (err != EAGAIN) return err; + /* wait until we can send something or we timeout */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Sendto with timeout +\*-------------------------------------------------------------------------*/ +int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, + SA *addr, socklen_t len, p_timeout tm) +{ + int err; + *sent = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long put = (long) sendto(*ps, data, count, 0, addr, len); + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + if (err == EPIPE) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Receive with timeout +\*-------------------------------------------------------------------------*/ +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) recv(*ps, data, count, 0); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Recvfrom with timeout +\*-------------------------------------------------------------------------*/ +int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, + SA *addr, socklen_t *len, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) recvfrom(*ps, data, count, 0, addr, len); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + + +/*-------------------------------------------------------------------------*\ +* Write with timeout +* +* socket_read and socket_write are cut-n-paste of socket_send and socket_recv, +* with send/recv replaced with write/read. We can't just use write/read +* in the socket version, because behaviour when size is zero is different. +\*-------------------------------------------------------------------------*/ +int socket_write(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + long put = (long) write(*ps, data, count); + /* if we sent anything, we are done */ + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + /* EPIPE means the connection was closed */ + if (err == EPIPE) return IO_CLOSED; + /* we call was interrupted, just try again */ + if (err == EINTR) continue; + /* if failed fatal reason, report error */ + if (err != EAGAIN) return err; + /* wait until we can send something or we timeout */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Read with timeout +* See note for socket_write +\*-------------------------------------------------------------------------*/ +int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) read(*ps, data, count); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Put socket into blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setblocking(p_socket ps) { + int flags = fcntl(*ps, F_GETFL, 0); + flags &= (~(O_NONBLOCK)); + fcntl(*ps, F_SETFL, flags); +} + +/*-------------------------------------------------------------------------*\ +* Put socket into non-blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setnonblocking(p_socket ps) { + int flags = fcntl(*ps, F_GETFL, 0); + flags |= O_NONBLOCK; + fcntl(*ps, F_SETFL, flags); +} + +/*-------------------------------------------------------------------------*\ +* DNS helpers +\*-------------------------------------------------------------------------*/ +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) return IO_DONE; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; +} + +int socket_gethostbyname(const char *addr, struct hostent **hp) { + *hp = gethostbyname(addr); + if (*hp) return IO_DONE; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Error translation functions +* Make sure important error messages are standard +\*-------------------------------------------------------------------------*/ +const char *socket_hoststrerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case HOST_NOT_FOUND: return "host not found"; + default: return hstrerror(err); + } +} + +const char *socket_strerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case EADDRINUSE: return "address already in use"; + case EISCONN: return "already connected"; + case EACCES: return "permission denied"; + case ECONNREFUSED: return "connection refused"; + case ECONNABORTED: return "closed"; + case ECONNRESET: return "closed"; + case ETIMEDOUT: return "timeout"; + default: return strerror(err); + } +} + +const char *socket_ioerror(p_socket ps, int err) { + (void) ps; + return socket_strerror(err); +} + +const char *socket_gaistrerror(int err) { + if (err == 0) return NULL; + switch (err) { + case EAI_AGAIN: return "temporary failure in name resolution"; + case EAI_BADFLAGS: return "invalid value for ai_flags"; +#ifdef EAI_BADHINTS + case EAI_BADHINTS: return "invalid value for hints"; +#endif + case EAI_FAIL: return "non-recoverable failure in name resolution"; + case EAI_FAMILY: return "ai_family not supported"; + case EAI_MEMORY: return "memory allocation failure"; + case EAI_NONAME: + return "host or service not provided, or not known"; + case EAI_OVERFLOW: return "argument buffer overflow"; +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: return "resolved protocol is unknown"; +#endif + case EAI_SERVICE: return "service not supported for socket type"; + case EAI_SOCKTYPE: return "ai_socktype not supported"; + case EAI_SYSTEM: return strerror(errno); + default: return gai_strerror(err); + } +} + diff --git a/cocos/scripting/lua/bindings/socket/usocket.h b/cocos/scripting/lua/bindings/socket/usocket.h new file mode 100644 index 0000000000..8b3241bf3c --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/usocket.h @@ -0,0 +1,43 @@ +#ifndef USOCKET_H +#define USOCKET_H +/*=========================================================================*\ +* Socket compatibilization module for Unix +* LuaSocket toolkit +\*=========================================================================*/ + +/*=========================================================================*\ +* BSD include files +\*=========================================================================*/ +/* error codes */ +#include +/* close function */ +#include +/* fnctnl function and associated constants */ +#include +/* struct sockaddr */ +#include +/* socket function */ +#include +/* struct timeval */ +#include +/* gethostbyname and gethostbyaddr functions */ +#include +/* sigpipe handling */ +#include +/* IP stuff*/ +#include +#include +/* TCP options (nagle algorithm disable) */ +#include + +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +typedef int t_socket; +typedef t_socket *p_socket; +typedef struct sockaddr_storage t_sockaddr_storage; + +#define SOCKET_INVALID (-1) + +#endif /* USOCKET_H */ diff --git a/cocos/scripting/lua/bindings/socket/wsocket.c b/cocos/scripting/lua/bindings/socket/wsocket.c new file mode 100644 index 0000000000..19b3f11b37 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/wsocket.c @@ -0,0 +1,413 @@ +/*=========================================================================*\ +* Socket compatibilization module for Win32 +* LuaSocket toolkit +* +* The penalty of calling select to avoid busy-wait is only paid when +* the I/O call fail in the first place. +\*=========================================================================*/ +#include + +#include "socket.h" + +/* WinSock doesn't have a strerror... */ +static const char *wstrerror(int err); + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int socket_open(void) { + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + int err = WSAStartup(wVersionRequested, &wsaData ); + if (err != 0) return 0; + if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) && + (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) { + WSACleanup(); + return 0; + } + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close module +\*-------------------------------------------------------------------------*/ +int socket_close(void) { + WSACleanup(); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Wait for readable/writable/connected socket with timeout +\*-------------------------------------------------------------------------*/ +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_E 4 +#define WAITFD_C (WAITFD_E|WAITFD_W) + +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; + struct timeval tv, *tp = NULL; + double t; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + if (sw & WAITFD_R) { + FD_ZERO(&rfds); + FD_SET(*ps, &rfds); + rp = &rfds; + } + if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } + if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; } + if ((t = timeout_get(tm)) >= 0.0) { + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6); + tp = &tv; + } + ret = select(0, rp, wp, ep, tp); + if (ret == -1) return WSAGetLastError(); + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED; + return IO_DONE; +} + +/*-------------------------------------------------------------------------*\ +* Select with int timeout in ms +\*-------------------------------------------------------------------------*/ +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm) { + struct timeval tv; + double t = timeout_get(tm); + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); + if (n <= 0) { + Sleep((DWORD) (1000*t)); + return 0; + } else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL); +} + +/*-------------------------------------------------------------------------*\ +* Close and inutilize socket +\*-------------------------------------------------------------------------*/ +void socket_destroy(p_socket ps) { + if (*ps != SOCKET_INVALID) { + socket_setblocking(ps); /* close can take a long time on WIN32 */ + closesocket(*ps); + *ps = SOCKET_INVALID; + } +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +void socket_shutdown(p_socket ps, int how) { + socket_setblocking(ps); + shutdown(*ps, how); + socket_setnonblocking(ps); +} + +/*-------------------------------------------------------------------------*\ +* Creates and sets up a socket +\*-------------------------------------------------------------------------*/ +int socket_create(p_socket ps, int domain, int type, int protocol) { + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) return IO_DONE; + else return WSAGetLastError(); +} + +/*-------------------------------------------------------------------------*\ +* Connects or returns error message +\*-------------------------------------------------------------------------*/ +int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { + int err; + /* don't call on closed socket */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* ask system to connect */ + if (connect(*ps, addr, len) == 0) return IO_DONE; + /* make sure the system is trying to connect */ + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err; + /* zero timeout case optimization */ + if (timeout_iszero(tm)) return IO_TIMEOUT; + /* we wait until something happens */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) { + int len = sizeof(err); + /* give windows time to set the error (yes, disgusting) */ + Sleep(10); + /* find out why we failed */ + getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); + /* we KNOW there was an error. if 'why' is 0, we will return + * "unknown error", but it's not really our fault */ + return err > 0? err: IO_UNKNOWN; + } else return err; + +} + +/*-------------------------------------------------------------------------*\ +* Binds or returns error message +\*-------------------------------------------------------------------------*/ +int socket_bind(p_socket ps, SA *addr, socklen_t len) { + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +int socket_listen(p_socket ps, int backlog) { + int err = IO_DONE; + socket_setblocking(ps); + if (listen(*ps, backlog) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* Accept with timeout +\*-------------------------------------------------------------------------*/ +int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, + p_timeout tm) { + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int err; + /* try to get client socket */ + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; + /* find out why we failed */ + err = WSAGetLastError(); + /* if we failed because there was no connectoin, keep trying */ + if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; + /* call select to avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Send with timeout +* On windows, if you try to send 10MB, the OS will buffer EVERYTHING +* this can take an awful lot of time and we will end up blocked. +* Therefore, whoever calls this function should not pass a huge buffer. +\*-------------------------------------------------------------------------*/ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + /* try to send something */ + int put = send(*ps, data, (int) count, 0); + /* if we sent something, we are done */ + if (put > 0) { + *sent = put; + return IO_DONE; + } + /* deal with failure */ + err = WSAGetLastError(); + /* we can only proceed if there was no serious error */ + if (err != WSAEWOULDBLOCK) return err; + /* avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Sendto with timeout +\*-------------------------------------------------------------------------*/ +int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, + SA *addr, socklen_t len, p_timeout tm) +{ + int err; + *sent = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int put = sendto(*ps, data, (int) count, 0, addr, len); + if (put > 0) { + *sent = put; + return IO_DONE; + } + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK) return err; + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Receive with timeout +\*-------------------------------------------------------------------------*/ +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int taken = recv(*ps, data, (int) count, 0); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Recvfrom with timeout +\*-------------------------------------------------------------------------*/ +int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, + SA *addr, socklen_t *len, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int taken = recvfrom(*ps, data, (int) count, 0, addr, len); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Put socket into blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setblocking(p_socket ps) { + u_long argp = 0; + ioctlsocket(*ps, FIONBIO, &argp); +} + +/*-------------------------------------------------------------------------*\ +* Put socket into non-blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setnonblocking(p_socket ps) { + u_long argp = 1; + ioctlsocket(*ps, FIONBIO, &argp); +} + +/*-------------------------------------------------------------------------*\ +* DNS helpers +\*-------------------------------------------------------------------------*/ +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) return IO_DONE; + else return WSAGetLastError(); +} + +int socket_gethostbyname(const char *addr, struct hostent **hp) { + *hp = gethostbyname(addr); + if (*hp) return IO_DONE; + else return WSAGetLastError(); +} + +/*-------------------------------------------------------------------------*\ +* Error translation functions +\*-------------------------------------------------------------------------*/ +const char *socket_hoststrerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case WSAHOST_NOT_FOUND: return "host not found"; + default: return wstrerror(err); + } +} + +const char *socket_strerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case WSAEADDRINUSE: return "address already in use"; + case WSAECONNREFUSED: return "connection refused"; + case WSAEISCONN: return "already connected"; + case WSAEACCES: return "permission denied"; + case WSAECONNABORTED: return "closed"; + case WSAECONNRESET: return "closed"; + case WSAETIMEDOUT: return "timeout"; + default: return wstrerror(err); + } +} + +const char *socket_ioerror(p_socket ps, int err) { + (void) ps; + return socket_strerror(err); +} + +static const char *wstrerror(int err) { + switch (err) { + case WSAEINTR: return "Interrupted function call"; + case WSAEACCES: return "Permission denied"; + case WSAEFAULT: return "Bad address"; + case WSAEINVAL: return "Invalid argument"; + case WSAEMFILE: return "Too many open files"; + case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; + case WSAEINPROGRESS: return "Operation now in progress"; + case WSAEALREADY: return "Operation already in progress"; + case WSAENOTSOCK: return "Socket operation on nonsocket"; + case WSAEDESTADDRREQ: return "Destination address required"; + case WSAEMSGSIZE: return "Message too long"; + case WSAEPROTOTYPE: return "Protocol wrong type for socket"; + case WSAENOPROTOOPT: return "Bad protocol option"; + case WSAEPROTONOSUPPORT: return "Protocol not supported"; + case WSAESOCKTNOSUPPORT: return "Socket type not supported"; + case WSAEOPNOTSUPP: return "Operation not supported"; + case WSAEPFNOSUPPORT: return "Protocol family not supported"; + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family"; + case WSAEADDRINUSE: return "Address already in use"; + case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; + case WSAENETDOWN: return "Network is down"; + case WSAENETUNREACH: return "Network is unreachable"; + case WSAENETRESET: return "Network dropped connection on reset"; + case WSAECONNABORTED: return "Software caused connection abort"; + case WSAECONNRESET: return "Connection reset by peer"; + case WSAENOBUFS: return "No buffer space available"; + case WSAEISCONN: return "Socket is already connected"; + case WSAENOTCONN: return "Socket is not connected"; + case WSAESHUTDOWN: return "Cannot send after socket shutdown"; + case WSAETIMEDOUT: return "Connection timed out"; + case WSAECONNREFUSED: return "Connection refused"; + case WSAEHOSTDOWN: return "Host is down"; + case WSAEHOSTUNREACH: return "No route to host"; + case WSAEPROCLIM: return "Too many processes"; + case WSASYSNOTREADY: return "Network subsystem is unavailable"; + case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range"; + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performed"; + case WSAEDISCON: return "Graceful shutdown in progress"; + case WSAHOST_NOT_FOUND: return "Host not found"; + case WSATRY_AGAIN: return "Nonauthoritative host not found"; + case WSANO_RECOVERY: return "Nonrecoverable name lookup error"; + case WSANO_DATA: return "Valid name, no data record of requested type"; + default: return "Unknown error"; + } +} + +const char *socket_gaistrerror(int err) { + if (err == 0) return NULL; + switch (err) { + case EAI_AGAIN: return "temporary failure in name resolution"; + case EAI_BADFLAGS: return "invalid value for ai_flags"; +#ifdef EAI_BADHINTS + case EAI_BADHINTS: return "invalid value for hints"; +#endif + case EAI_FAIL: return "non-recoverable failure in name resolution"; + case EAI_FAMILY: return "ai_family not supported"; + case EAI_MEMORY: return "memory allocation failure"; + case EAI_NONAME: + return "host or service not provided, or not known"; +// case EAI_OVERFLOW: return "argument buffer overflow"; +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: return "resolved protocol is unknown"; +#endif + case EAI_SERVICE: return "service not supported for socket type"; + case EAI_SOCKTYPE: return "ai_socktype not supported"; +// case EAI_SYSTEM: return strerror(errno); + default: return gai_strerrorA(err); + } +} + diff --git a/cocos/scripting/lua/bindings/socket/wsocket.h b/cocos/scripting/lua/bindings/socket/wsocket.h new file mode 100644 index 0000000000..0783b00d84 --- /dev/null +++ b/cocos/scripting/lua/bindings/socket/wsocket.h @@ -0,0 +1,25 @@ +#ifndef WSOCKET_H +#define WSOCKET_H +/*=========================================================================*\ +* Socket compatibilization module for Win32 +* LuaSocket toolkit +\*=========================================================================*/ + +/*=========================================================================*\ +* WinSock include files +\*=========================================================================*/ +#include +#include + +typedef int socklen_t; +typedef SOCKADDR_STORAGE t_sockaddr_storage; +typedef SOCKET t_socket; +typedef t_socket *p_socket; + +#define SOCKET_INVALID (INVALID_SOCKET) + +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +#endif /* WSOCKET_H */ diff --git a/samples/Lua/HelloLua/Resources/Resources/.gitignore b/samples/Lua/HelloLua/Resources/Resources/.gitignore new file mode 100644 index 0000000000..1d65afe366 --- /dev/null +++ b/samples/Lua/HelloLua/Resources/Resources/.gitignore @@ -0,0 +1,2 @@ +#Do now ignore Marmalade icf files +!*.icf diff --git a/samples/Lua/HelloLua/Resources/Resources/background.mp3.REMOVED.git-id b/samples/Lua/HelloLua/Resources/Resources/background.mp3.REMOVED.git-id new file mode 100644 index 0000000000..cfc16a8a4e --- /dev/null +++ b/samples/Lua/HelloLua/Resources/Resources/background.mp3.REMOVED.git-id @@ -0,0 +1 @@ +aec1c0a8c8068377fddca5ddd32084d8c3c3c419 \ No newline at end of file diff --git a/samples/Lua/HelloLua/Resources/mobdebug.lua b/samples/Lua/HelloLua/Resources/mobdebug.lua new file mode 100644 index 0000000000..31ef8af06b --- /dev/null +++ b/samples/Lua/HelloLua/Resources/mobdebug.lua @@ -0,0 +1,1465 @@ +-- +-- MobDebug 0.542 +-- Copyright 2011-13 Paul Kulchenko +-- Based on RemDebug 1.0 Copyright Kepler Project 2005 +-- + +local mobdebug = { + _NAME = "mobdebug", + _VERSION = 0.542, + _COPYRIGHT = "Paul Kulchenko", + _DESCRIPTION = "Mobile Remote Debugger for the Lua programming language", + port = os and os.getenv and os.getenv("MOBDEBUG_PORT") or 8172, + checkcount = 200, + yieldtimeout = 0.02, +} + +local coroutine = coroutine +local error = error +local getfenv = getfenv +local setfenv = setfenv +local loadstring = loadstring or load -- "load" replaced "loadstring" in Lua 5.2 +local io = io +local os = os +local pairs = pairs +local require = require +local setmetatable = setmetatable +local string = string +local tonumber = tonumber +local unpack = table.unpack or unpack +local rawget = rawget + +-- if strict.lua is used, then need to avoid referencing some global +-- variables, as they can be undefined; +-- use rawget to to avoid complaints from strict.lua at run-time. +-- it's safe to do the initialization here as all these variables +-- should get defined values (of any) before the debugging starts. +-- there is also global 'wx' variable, which is checked as part of +-- the debug loop as 'wx' can be loaded at any time during debugging. +local genv = _G or _ENV +local jit = rawget(genv, "jit") +local MOAICoroutine = rawget(genv, "MOAICoroutine") + +if not setfenv then -- Lua 5.2 + -- based on http://lua-users.org/lists/lua-l/2010-06/msg00314.html + -- this assumes f is a function + local function findenv(f) + local level = 1 + repeat + local name, value = debug.getupvalue(f, level) + if name == '_ENV' then return level, value end + level = level + 1 + until name == nil + return nil end + getfenv = function (f) return(select(2, findenv(f)) or _G) end + setfenv = function (f, t) + local level = findenv(f) + if level then debug.setupvalue(f, level, t) end + return f end +end + +-- check for OS and convert file names to lower case on windows +-- (its file system is case insensitive, but case preserving), as setting a +-- breakpoint on x:\Foo.lua will not work if the file was loaded as X:\foo.lua. +-- OSX and Windows behave the same way (case insensitive, but case preserving) +local iscasepreserving = os and os.getenv and (os.getenv('WINDIR') + or (os.getenv('OS') or ''):match('[Ww]indows') + or os.getenv('DYLD_LIBRARY_PATH')) + or not io.open("/proc") + +-- turn jit off based on Mike Pall's comment in this discussion: +-- http://www.freelists.org/post/luajit/Debug-hooks-and-JIT,2 +-- "You need to turn it off at the start if you plan to receive +-- reliable hook calls at any later point in time." +if jit and jit.off then jit.off() end + +local socket = require "socket" +local debug = require "debug" +local coro_debugger +local coro_debugee +local coroutines = {}; setmetatable(coroutines, {__mode = "k"}) -- "weak" keys +local events = { BREAK = 1, WATCH = 2, RESTART = 3, STACK = 4 } +local breakpoints = {} +local watches = {} +local lastsource +local lastfile +local watchescnt = 0 +local abort -- default value is nil; this is used in start/loop distinction +local seen_hook = false +local checkcount = 0 +local step_into = false +local step_over = false +local step_level = 0 +local stack_level = 0 +local server +local buf +local outputs = {} +local iobase = {print = print} +local basedir = "" +local deferror = "execution aborted at default debugee" +local debugee = function () + local a = 1 + for _ = 1, 10 do a = a + 1 end + error(deferror) +end +local function q(s) return s:gsub('([%(%)%.%%%+%-%*%?%[%^%$%]])','%%%1') end + +local serpent = (function() ---- include Serpent module for serialization +local n, v = "serpent", 0.25 -- (C) 2012-13 Paul Kulchenko; MIT License +local c, d = "Paul Kulchenko", "Lua serializer and pretty printer" +local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'} +local badtype = {thread = true, userdata = true, cdata = true} +local keyword, globals, G = {}, {}, (_G or _ENV) +for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false', + 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', + 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end +for k,v in pairs(G) do globals[v] = k end -- build func to name mapping +for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do + for k,v in pairs(G[g]) do globals[v] = g..'.'..k end end + +local function s(t, opts) + local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum + local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge + local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge) + local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge) + local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0 + local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)", + -- tostring(val) is needed because __tostring may return a non-string value + function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return syms[s] end)) end + local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or s) + or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026 + or ("%q"):format(s):gsub("\010","n"):gsub("\026","\\026") end + local function comment(s,l) return comm and (l or 0) < comm and ' --[['..tostring(s)..']]' or '' end + local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal + and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end + local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r'] + local n = name == nil and '' or name + local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n] + local safe = plain and n or '['..safestr(n)..']' + return (path or '')..(plain and path and '.' or '')..safe, safe end + local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding + local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'} + local function padnum(d) return ("%0"..maxn.."d"):format(d) end + table.sort(k, function(a,b) + -- sort numeric keys first: k[key] is non-nil for numeric keys + return (k[a] and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum)) + < (k[b] and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end + local function val2str(t, name, indent, insref, path, plainindex, level) + local ttype, level, mt = type(t), (level or 0), getmetatable(t) + local spath, sname = safename(path, name) + local tag = plainindex and + ((type(name) == "number") and '' or name..space..'='..space) or + (name ~= nil and sname..space..'='..space or '') + if seen[t] then -- already seen this element + sref[#sref+1] = spath..space..'='..space..seen[t] + return tag..'nil'..comment('ref', level) end + if type(mt) == 'table' and (mt.__serialize or mt.__tostring) then -- knows how to serialize itself + seen[t] = insref or spath + if mt.__serialize then t = mt.__serialize(t) else t = tostring(t) end + ttype = type(t) end -- new value falls through to be serialized + if ttype == "table" then + if level >= maxl then return tag..'{}'..comment('max', level) end + seen[t] = insref or spath + if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty + local maxn, o, out = math.min(#t, maxnum or #t), {}, {} + for key = 1, maxn do o[key] = key end + if not maxnum or #o < maxnum then + local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables + for key in pairs(t) do if o[key] ~= key then n = n + 1; o[n] = key end end end + if maxnum and #o > maxnum then o[maxnum+1] = nil end + if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end + local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output) + for n, key in ipairs(o) do + local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse + if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing + or opts.keyallow and not opts.keyallow[key] + or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types + or sparse and value == nil then -- skipping nils; do nothing + elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then + if not seen[key] and not globals[key] then + sref[#sref+1] = 'placeholder' + local sname = safename(iname, gensym(key)) -- iname is table for local variables + sref[#sref] = val2str(key,sname,indent,sname,iname,true) end + sref[#sref+1] = 'placeholder' + local path = seen[t]..'['..(seen[key] or globals[key] or gensym(key))..']' + sref[#sref] = path..space..'='..space..(seen[value] or val2str(value,nil,indent,path)) + else + out[#out+1] = val2str(value,key,indent,insref,seen[t],plainindex,level+1) + end + end + local prefix = string.rep(indent or '', level) + local head = indent and '{\n'..prefix..indent or '{' + local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space)) + local tail = indent and "\n"..prefix..'}' or '}' + return (custom and custom(tag,head,body,tail) or tag..head..body..tail)..comment(t, level) + elseif badtype[ttype] then + seen[t] = insref or spath + return tag..globerr(t, level) + elseif ttype == 'function' then + seen[t] = insref or spath + local ok, res = pcall(string.dump, t) + local func = ok and ((opts.nocode and "function() --[[..skipped..]] end" or + "loadstring("..safestr(res)..",'@serialized')")..comment(t, level)) + return tag..(func or globerr(t, level)) + else return tag..safestr(t) end -- handle all other types + end + local sepr = indent and "\n" or ";"..space + local body = val2str(t, name, indent) -- this call also populates sref + local tail = #sref>1 and table.concat(sref, sepr)..sepr or '' + local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or '' + return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end" +end + +local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end +return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s, + dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end, + line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end, + block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end } +end)() ---- end of Serpent module + +local function removebasedir(path, basedir) + if iscasepreserving then + -- check if the lowercased path matches the basedir + -- if so, return substring of the original path (to not lowercase it) + return path:lower():find('^'..q(basedir:lower())) + and path:sub(#basedir+1) or path + else + return string.gsub(path, '^'..q(basedir), '') + end +end + +local function stack(start) + local function vars(f) + local func = debug.getinfo(f, "f").func + local i = 1 + local locals = {} + while true do + local name, value = debug.getlocal(f, i) + if not name then break end + if string.sub(name, 1, 1) ~= '(' then locals[name] = {value, tostring(value)} end + i = i + 1 + end + i = 1 + local ups = {} + while func and true do -- check for func as it may be nil for tail calls + local name, value = debug.getupvalue(func, i) + if not name then break end + ups[name] = {value, tostring(value)} + i = i + 1 + end + return locals, ups + end + + local stack = {} + for i = (start or 0), 100 do + local source = debug.getinfo(i, "Snl") + if not source then break end + + local src = source.source + if src:find("@") == 1 then + src = src:sub(2):gsub("\\", "/") + if src:find("%./") == 1 then src = src:sub(3) end + end + + table.insert(stack, { -- remove basedir from source + {source.name, removebasedir(src, basedir), source.linedefined, + source.currentline, source.what, source.namewhat, source.short_src}, + vars(i+1)}) + if source.what == 'main' then break end + end + return stack +end + +local function set_breakpoint(file, line) + if file == '-' and lastfile then file = lastfile + elseif iscasepreserving then file = string.lower(file) end + if not breakpoints[line] then breakpoints[line] = {} end + breakpoints[line][file] = true +end + +local function remove_breakpoint(file, line) + if file == '-' and lastfile then file = lastfile + elseif iscasepreserving then file = string.lower(file) end + if breakpoints[line] then breakpoints[line][file] = nil end +end + +local function has_breakpoint(file, line) + return breakpoints[line] + and breakpoints[line][iscasepreserving and string.lower(file) or file] +end + +local function restore_vars(vars) + if type(vars) ~= 'table' then return end + + -- locals need to be processed in the reverse order, starting from + -- the inner block out, to make sure that the localized variables + -- are correctly updated with only the closest variable with + -- the same name being changed + -- first loop find how many local variables there is, while + -- the second loop processes them from i to 1 + local i = 1 + while true do + local name = debug.getlocal(3, i) + if not name then break end + i = i + 1 + end + i = i - 1 + local written_vars = {} + while i > 0 do + local name = debug.getlocal(3, i) + if not written_vars[name] then + if string.sub(name, 1, 1) ~= '(' then + debug.setlocal(3, i, rawget(vars, name)) + end + written_vars[name] = true + end + i = i - 1 + end + + i = 1 + local func = debug.getinfo(3, "f").func + while true do + local name = debug.getupvalue(func, i) + if not name then break end + if not written_vars[name] then + if string.sub(name, 1, 1) ~= '(' then + debug.setupvalue(func, i, rawget(vars, name)) + end + written_vars[name] = true + end + i = i + 1 + end +end + +local function capture_vars(level) + local vars = {} + local func = debug.getinfo(level or 3, "f").func + local i = 1 + while true do + local name, value = debug.getupvalue(func, i) + if not name then break end + if string.sub(name, 1, 1) ~= '(' then vars[name] = value end + i = i + 1 + end + i = 1 + while true do + local name, value = debug.getlocal(level or 3, i) + if not name then break end + if string.sub(name, 1, 1) ~= '(' then vars[name] = value end + i = i + 1 + end + -- returned 'vars' table plays a dual role: (1) it captures local values + -- and upvalues to be restored later (in case they are modified in "eval"), + -- and (2) it provides an environment for evaluated chunks. + -- getfenv(func) is needed to provide proper environment for functions, + -- including access to globals, but this causes vars[name] to fail in + -- restore_vars on local variables or upvalues with `nil` values when + -- 'strict' is in effect. To avoid this `rawget` is used in restore_vars. + setmetatable(vars, { __index = getfenv(func), __newindex = getfenv(func) }) + return vars +end + +local function stack_depth(start_depth) + for i = start_depth, 0, -1 do + if debug.getinfo(i, "l") then return i+1 end + end + return start_depth +end + +local function is_safe(stack_level) + -- the stack grows up: 0 is getinfo, 1 is is_safe, 2 is debug_hook, 3 is user function + if stack_level == 3 then return true end + for i = 3, stack_level do + -- return if it is not safe to abort + local info = debug.getinfo(i, "S") + if not info then return true end + if info.what == "C" then return false end + end + return true +end + +local function in_debugger() + local this = debug.getinfo(1, "S").source + -- only need to check few frames as mobdebug frames should be close + for i = 3, 7 do + local info = debug.getinfo(i, "S") + if not info then return false end + if info.source == this then return true end + end + return false +end + +local function is_pending(peer) + -- if there is something already in the buffer, skip check + if not buf and checkcount >= mobdebug.checkcount then + peer:settimeout(0) -- non-blocking + buf = peer:receive(1) + peer:settimeout() -- back to blocking + checkcount = 0 + end + return buf +end + +local function debug_hook(event, line) + -- (1) LuaJIT needs special treatment. Because debug_hook is set for + -- *all* coroutines, and not just the one being debugged as in regular Lua + -- (http://lua-users.org/lists/lua-l/2011-06/msg00513.html), + -- need to avoid debugging mobdebug's own code as LuaJIT doesn't + -- always correctly generate call/return hook events (there are more + -- calls than returns, which breaks stack depth calculation and + -- 'step' and 'step over' commands stop working; possibly because + -- 'tail return' events are not generated by LuaJIT). + -- the next line checks if the debugger is run under LuaJIT and if + -- one of debugger methods is present in the stack, it simply returns. + if jit then + -- when luajit is compiled with LUAJIT_ENABLE_LUA52COMPAT, + -- coroutine.running() returns non-nil for the main thread. + local coro, main = coroutine.running() + if not coro or main then coro = 'main' end + local disabled = coroutines[coro] == false + or coroutines[coro] == nil and coro ~= (coro_debugee or 'main') + if coro_debugee and disabled or not coro_debugee and (disabled or in_debugger()) + then return end + end + + -- (2) check if abort has been requested and it's safe to abort + if abort and is_safe(stack_level) then error(abort) end + + -- (3) also check if this debug hook has not been visited for any reason. + -- this check is needed to avoid stepping in too early + -- (for example, when coroutine.resume() is executed inside start()). + if not seen_hook and in_debugger() then return end + + if event == "call" then + stack_level = stack_level + 1 + elseif event == "return" or event == "tail return" then + stack_level = stack_level - 1 + elseif event == "line" then + -- may need to fall through because of the following: + -- (1) step_into + -- (2) step_over and stack_level <= step_level (need stack_level) + -- (3) breakpoint; check for line first as it's known; then for file + -- (4) socket call (only do every Xth check) + -- (5) at least one watch is registered + if not ( + step_into or step_over or breakpoints[line] or watchescnt > 0 + or is_pending(server) + ) then checkcount = checkcount + 1; return end + + checkcount = mobdebug.checkcount -- force check on the next command + + -- this is needed to check if the stack got shorter or longer. + -- unfortunately counting call/return calls is not reliable. + -- the discrepancy may happen when "pcall(load, '')" call is made + -- or when "error()" is called in a function. + -- in either case there are more "call" than "return" events reported. + -- this validation is done for every "line" event, but should be "cheap" + -- as it checks for the stack to get shorter (or longer by one call). + -- start from one level higher just in case we need to grow the stack. + -- this may happen after coroutine.resume call to a function that doesn't + -- have any other instructions to execute. it triggers three returns: + -- "return, tail return, return", which needs to be accounted for. + stack_level = stack_depth(stack_level+1) + + local caller = debug.getinfo(2, "S") + + -- grab the filename and fix it if needed + local file = lastfile + if (lastsource ~= caller.source) then + file, lastsource = caller.source, caller.source + -- technically, users can supply names that may not use '@', + -- for example when they call loadstring('...', 'filename.lua'). + -- Unfortunately, there is no reliable/quick way to figure out + -- what is the filename and what is the source code. + -- The following will work if the supplied filename uses Unix path. + if file:find("^@") then + file = file:gsub("^@", ""):gsub("\\", "/") + -- need this conversion to be applied to relative and absolute + -- file names as you may write "require 'Foo'" to + -- load "foo.lua" (on a case insensitive file system) and breakpoints + -- set on foo.lua will not work if not converted to the same case. + if iscasepreserving then file = string.lower(file) end + if file:find("%./") == 1 then file = file:sub(3) + else file = file:gsub('^'..q(basedir), '') end + -- some file systems allow newlines in file names; remove these. + file = file:gsub("\n", ' ') + else + -- this is either a file name coming from loadstring("chunk", "file"), + -- or the actual source code that needs to be serialized (as it may + -- include newlines); assume it's a file name if it's all on one line. + file = file:find("[\r\n]") and serpent.line(file) or file + end + + -- set to true if we got here; this only needs to be done once per + -- session, so do it here to at least avoid setting it for every line. + seen_hook = true + lastfile = file + end + + local vars, status, res + if (watchescnt > 0) then + vars = capture_vars() + for index, value in pairs(watches) do + setfenv(value, vars) + local ok, fired = pcall(value) + if ok and fired then + status, res = coroutine.resume(coro_debugger, events.WATCH, vars, file, line, index) + break -- any one watch is enough; don't check multiple times + end + end + end + + -- need to get into the "regular" debug handler, but only if there was + -- no watch that was fired. If there was a watch, handle its result. + local getin = (status == nil) and + (step_into + or (step_over and stack_level <= step_level) + or has_breakpoint(file, line) + or is_pending(server)) + + if getin then + vars = vars or capture_vars() + step_into = false + step_over = false + status, res = coroutine.resume(coro_debugger, events.BREAK, vars, file, line) + end + + -- handle 'stack' command that provides stack() information to the debugger + if status and res == 'stack' then + while status and res == 'stack' do + -- resume with the stack trace and variables + if vars then restore_vars(vars) end -- restore vars so they are reflected in stack values + -- this may fail if __tostring method fails at run-time + local ok, snapshot = pcall(stack, 4) + status, res = coroutine.resume(coro_debugger, ok and events.STACK or events.BREAK, snapshot, file, line) + end + end + + -- need to recheck once more as resume after 'stack' command may + -- return something else (for example, 'exit'), which needs to be handled + if status and res and res ~= 'stack' then + if abort == nil and res == "exit" then os.exit(1); return end + abort = res + -- only abort if safe; if not, there is another (earlier) check inside + -- debug_hook, which will abort execution at the first safe opportunity + if is_safe(stack_level) then error(abort) end + elseif not status and res then + error(res, 2) -- report any other (internal) errors back to the application + end + + if vars then restore_vars(vars) end + end +end + +local function stringify_results(status, ...) + if not status then return status, ... end -- on error report as it + + local t = {...} + for i,v in pairs(t) do -- stringify each of the returned values + local ok, res = pcall(serpent.line, v, {nocode = true, comment = 1}) + t[i] = ok and res or ("%q"):format(res):gsub("\010","n"):gsub("\026","\\026") + end + -- stringify table with all returned values + -- this is done to allow each returned value to be used (serialized or not) + -- intependently and to preserve "original" comments + return pcall(serpent.dump, t, {sparse = false}) +end + +local function debugger_loop(sev, svars, sfile, sline) + local command + local app, osname + local eval_env = svars or {} + local function emptyWatch () return false end + local loaded = {} + for k in pairs(package.loaded) do loaded[k] = true end + + while true do + local line, err + local wx = rawget(genv, "wx") -- use rawread to make strict.lua happy + if (wx or mobdebug.yield) and server.settimeout then server:settimeout(mobdebug.yieldtimeout) end + while true do + line, err = server:receive() + if not line and err == "timeout" then + -- yield for wx GUI applications if possible to avoid "busyness" + app = app or (wx and wx.wxGetApp and wx.wxGetApp()) + if app then + local win = app:GetTopWindow() + local inloop = app:IsMainLoopRunning() + osname = osname or wx.wxPlatformInfo.Get():GetOperatingSystemFamilyName() + if win and not inloop then + -- process messages in a regular way + -- and exit as soon as the event loop is idle + if osname == 'Unix' then wx.wxTimer(app):Start(10, true) end + local exitLoop = function() + win:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_IDLE) + win:Disconnect(wx.wxID_ANY, wx.wxID_ANY, wx.wxEVT_TIMER) + app:ExitMainLoop() + end + win:Connect(wx.wxEVT_IDLE, exitLoop) + win:Connect(wx.wxEVT_TIMER, exitLoop) + app:MainLoop() + end + elseif mobdebug.yield then mobdebug.yield() + end + elseif not line and err == "closed" then + error("Debugger connection unexpectedly closed", 0) + else + -- if there is something in the pending buffer, prepend it to the line + if buf then line = buf .. line; buf = nil end + break + end + end + if server.settimeout then server:settimeout() end -- back to blocking + command = string.sub(line, string.find(line, "^[A-Z]+")) + if command == "SETB" then + local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$") + if file and line then + set_breakpoint(file, tonumber(line)) + server:send("200 OK\n") + else + server:send("400 Bad Request\n") + end + elseif command == "DELB" then + local _, _, _, file, line = string.find(line, "^([A-Z]+)%s+(.-)%s+(%d+)%s*$") + if file and line then + remove_breakpoint(file, tonumber(line)) + server:send("200 OK\n") + else + server:send("400 Bad Request\n") + end + elseif command == "EXEC" then + local _, _, chunk = string.find(line, "^[A-Z]+%s+(.+)$") + if chunk then + local func, res = loadstring(chunk) + local status + if func then + setfenv(func, eval_env) + status, res = stringify_results(pcall(func)) + end + if status then + server:send("200 OK " .. #res .. "\n") + server:send(res) + else + server:send("401 Error in Expression " .. #res .. "\n") + server:send(res) + end + else + server:send("400 Bad Request\n") + end + elseif command == "LOAD" then + local _, _, size, name = string.find(line, "^[A-Z]+%s+(%d+)%s+(%S.-)%s*$") + size = tonumber(size) + + if abort == nil then -- no LOAD/RELOAD allowed inside start() + if size > 0 then server:receive(size) end + if sfile and sline then + server:send("201 Started " .. sfile .. " " .. sline .. "\n") + else + server:send("200 OK 0\n") + end + else + -- reset environment to allow required modules to load again + -- remove those packages that weren't loaded when debugger started + for k in pairs(package.loaded) do + if not loaded[k] then package.loaded[k] = nil end + end + + if size == 0 and name == '-' then -- RELOAD the current script being debugged + server:send("200 OK 0\n") + coroutine.yield("load") + else + -- receiving 0 bytes blocks (at least in luasocket 2.0.2), so skip reading + local chunk = size == 0 and "" or server:receive(size) + if chunk then -- LOAD a new script for debugging + local func, res = loadstring(chunk, "@"..name) + if func then + server:send("200 OK 0\n") + debugee = func + coroutine.yield("load") + else + server:send("401 Error in Expression " .. #res .. "\n") + server:send(res) + end + else + server:send("400 Bad Request\n") + end + end + end + elseif command == "SETW" then + local _, _, exp = string.find(line, "^[A-Z]+%s+(.+)%s*$") + if exp then + local func, res = loadstring("return(" .. exp .. ")") + if func then + watchescnt = watchescnt + 1 + local newidx = #watches + 1 + watches[newidx] = func + server:send("200 OK " .. newidx .. "\n") + else + server:send("401 Error in Expression " .. #res .. "\n") + server:send(res) + end + else + server:send("400 Bad Request\n") + end + elseif command == "DELW" then + local _, _, index = string.find(line, "^[A-Z]+%s+(%d+)%s*$") + index = tonumber(index) + if index > 0 and index <= #watches then + watchescnt = watchescnt - (watches[index] ~= emptyWatch and 1 or 0) + watches[index] = emptyWatch + server:send("200 OK\n") + else + server:send("400 Bad Request\n") + end + elseif command == "RUN" then + server:send("200 OK\n") + + local ev, vars, file, line, idx_watch = coroutine.yield() + eval_env = vars + if ev == events.BREAK then + server:send("202 Paused " .. file .. " " .. line .. "\n") + elseif ev == events.WATCH then + server:send("203 Paused " .. file .. " " .. line .. " " .. idx_watch .. "\n") + elseif ev == events.RESTART then + -- nothing to do + else + server:send("401 Error in Execution " .. #file .. "\n") + server:send(file) + end + elseif command == "STEP" then + server:send("200 OK\n") + step_into = true + + local ev, vars, file, line, idx_watch = coroutine.yield() + eval_env = vars + if ev == events.BREAK then + server:send("202 Paused " .. file .. " " .. line .. "\n") + elseif ev == events.WATCH then + server:send("203 Paused " .. file .. " " .. line .. " " .. idx_watch .. "\n") + elseif ev == events.RESTART then + -- nothing to do + else + server:send("401 Error in Execution " .. #file .. "\n") + server:send(file) + end + elseif command == "OVER" or command == "OUT" then + server:send("200 OK\n") + step_over = true + + -- OVER and OUT are very similar except for + -- the stack level value at which to stop + if command == "OUT" then step_level = stack_level - 1 + else step_level = stack_level end + + local ev, vars, file, line, idx_watch = coroutine.yield() + eval_env = vars + if ev == events.BREAK then + server:send("202 Paused " .. file .. " " .. line .. "\n") + elseif ev == events.WATCH then + server:send("203 Paused " .. file .. " " .. line .. " " .. idx_watch .. "\n") + elseif ev == events.RESTART then + -- nothing to do + else + server:send("401 Error in Execution " .. #file .. "\n") + server:send(file) + end + elseif command == "BASEDIR" then + local _, _, dir = string.find(line, "^[A-Z]+%s+(.+)%s*$") + if dir then + basedir = iscasepreserving and string.lower(dir) or dir + -- reset cached source as it may change with basedir + lastsource = nil + server:send("200 OK\n") + else + server:send("400 Bad Request\n") + end + elseif command == "SUSPEND" then + -- do nothing; it already fulfilled its role + elseif command == "STACK" then + -- first check if we can execute the stack command + -- as it requires yielding back to debug_hook it cannot be executed + -- if we have not seen the hook yet as happens after start(). + -- in this case we simply return an empty result + local vars, ev = {} + if seen_hook then + ev, vars = coroutine.yield("stack") + end + if ev and ev ~= events.STACK then + server:send("401 Error in Execution " .. #vars .. "\n") + server:send(vars) + else + local ok, res = pcall(serpent.dump, vars, {nocode = true, sparse = false}) + if ok then + server:send("200 OK " .. res .. "\n") + else + server:send("401 Error in Execution " .. #res .. "\n") + server:send(res) + end + end + elseif command == "OUTPUT" then + local _, _, stream, mode = string.find(line, "^[A-Z]+%s+(%w+)%s+([dcr])%s*$") + if stream and mode and stream == "stdout" then + -- assign "print" in the global environment + genv.print = mode == 'd' and iobase.print or coroutine.wrap(function(...) + -- wrapping into coroutine.wrap protects this function from + -- being stepped through in the debugger + local tbl = {...} + while true do + if mode == 'c' then iobase.print(unpack(tbl)) end + for n = 1, #tbl do + tbl[n] = select(2, pcall(serpent.line, tbl[n], {nocode = true, comment = false})) end + local file = table.concat(tbl, "\t").."\n" + server:send("204 Output " .. stream .. " " .. #file .. "\n" .. file) + tbl = {coroutine.yield()} + end + end) + server:send("200 OK\n") + else + server:send("400 Bad Request\n") + end + elseif command == "EXIT" then + server:send("200 OK\n") + coroutine.yield("exit") + else + server:send("400 Bad Request\n") + end + end +end + +local function connect(controller_host, controller_port) + return (socket.connect4 or socket.connect)(controller_host, controller_port) +end + +local function isrunning() + return coro_debugger and coroutine.status(coro_debugger) == 'suspended' +end + +local lasthost, lastport + +-- Starts a debug session by connecting to a controller +local function start(controller_host, controller_port) + -- only one debugging session can be run (as there is only one debug hook) + if isrunning() then return end + + lasthost = controller_host or lasthost + lastport = controller_port or lastport + + controller_host = lasthost or "localhost" + controller_port = lastport or mobdebug.port + + local err + server, err = (socket.connect4 or socket.connect)(controller_host, controller_port) + if server then + -- correct stack depth which already has some calls on it + -- so it doesn't go into negative when those calls return + -- as this breaks subsequence checks in stack_depth(). + -- start from 16th frame, which is sufficiently large for this check. + stack_level = stack_depth(16) + + -- provide our own traceback function to report the error remotely + do + local dtraceback = debug.traceback + debug.traceback = function (...) + if select('#', ...) >= 1 then + local err, lvl = ... + if err and type(err) ~= 'thread' then + local trace = dtraceback(err, (lvl or 2)+1) + if genv.print == iobase.print then -- no remote redirect + return trace + else + genv.print(trace) -- report the error remotely + return -- don't report locally to avoid double reporting + end + end + end + -- direct call to debug.traceback: return the original. + -- debug.traceback(nil, level) doesn't work in Lua 5.1 + -- (http://lua-users.org/lists/lua-l/2011-06/msg00574.html), so + -- simply remove first frame from the stack trace + return (dtraceback(...):gsub("(stack traceback:\n)[^\n]*\n", "%1")) + end + end + coro_debugger = coroutine.create(debugger_loop) + debug.sethook(debug_hook, "lcr") + seen_hook = nil -- reset in case the last start() call was refused + step_into = true -- start with step command + return true + else + print(("Could not connect to %s:%s: %s") + :format(controller_host, controller_port, err or "unknown error")) + end +end + +local function controller(controller_host, controller_port, scratchpad) + -- only one debugging session can be run (as there is only one debug hook) + if isrunning() then return end + + lasthost = controller_host or lasthost + lastport = controller_port or lastport + + controller_host = lasthost or "localhost" + controller_port = lastport or mobdebug.port + + local exitonerror = not scratchpad + local err + server, err = (socket.connect4 or socket.connect)(controller_host, controller_port) + if server then + local function report(trace, err) + local msg = err .. "\n" .. trace + server:send("401 Error in Execution " .. #msg .. "\n") + server:send(msg) + return err + end + + seen_hook = true -- allow to accept all commands + coro_debugger = coroutine.create(debugger_loop) + + while true do + step_into = true -- start with step command + abort = false -- reset abort flag from the previous loop + if scratchpad then checkcount = mobdebug.checkcount end -- force suspend right away + + coro_debugee = coroutine.create(debugee) + debug.sethook(coro_debugee, debug_hook, "lcr") + local status, err = coroutine.resume(coro_debugee) + + -- was there an error or is the script done? + -- 'abort' state is allowed here; ignore it + if abort then + if tostring(abort) == 'exit' then break end + else + if status then -- normal execution is done + break + elseif err and not tostring(err):find(deferror) then + -- report the error back + -- err is not necessarily a string, so convert to string to report + report(debug.traceback(coro_debugee), tostring(err)) + if exitonerror then break end + -- resume once more to clear the response the debugger wants to send + -- need to use capture_vars(2) as three would be the level of + -- the caller for controller(), but because of the tail call, + -- the caller may not exist; + -- This is not entirely safe as the user may see the local + -- variable from console, but they will be reset anyway. + -- This functionality is used when scratchpad is paused to + -- gain access to remote console to modify global variables. + local status, err = coroutine.resume(coro_debugger, events.RESTART, capture_vars(2)) + if not status or status and err == "exit" then break end + end + end + end + else + print(("Could not connect to %s:%s: %s") + :format(controller_host, controller_port, err or "unknown error")) + return false + end + return true +end + +local function scratchpad(controller_host, controller_port) + return controller(controller_host, controller_port, true) +end + +local function loop(controller_host, controller_port) + return controller(controller_host, controller_port, false) +end + +local function on() + if not (isrunning() and server) then return end + + -- main is set to true under Lua5.2 for the "main" chunk. + -- Lua5.1 returns co as `nil` in that case. + local co, main = coroutine.running() + if main then co = nil end + if co then + coroutines[co] = true + debug.sethook(co, debug_hook, "lcr") + else + if jit then coroutines.main = true end + debug.sethook(debug_hook, "lcr") + end +end + +local function off() + if not (isrunning() and server) then return end + + -- main is set to true under Lua5.2 for the "main" chunk. + -- Lua5.1 returns co as `nil` in that case. + local co, main = coroutine.running() + if main then co = nil end + + -- don't remove coroutine hook under LuaJIT as there is only one (global) hook + if co then + coroutines[co] = false + if not jit then debug.sethook(co) end + else + if jit then coroutines.main = false end + if not jit then debug.sethook() end + end + + -- check if there is any thread that is still being debugged under LuaJIT; + -- if not, turn the debugging off + if jit then + local remove = true + for co, debugged in pairs(coroutines) do + if debugged then remove = false; break end + end + if remove then debug.sethook() end + end +end + +-- Handles server debugging commands +local function handle(params, client, options) + local _, _, command = string.find(params, "^([a-z]+)") + local file, line, watch_idx + if command == "run" or command == "step" or command == "out" + or command == "over" or command == "exit" then + client:send(string.upper(command) .. "\n") + client:receive() -- this should consume the first '200 OK' response + while true do + local done = true + local breakpoint = client:receive() + if not breakpoint then + print("Program finished") + os.exit() + return -- use return here for those cases where os.exit() is not wanted + end + local _, _, status = string.find(breakpoint, "^(%d+)") + if status == "200" then + -- don't need to do anything + elseif status == "202" then + _, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$") + if file and line then + print("Paused at file " .. file .. " line " .. line) + end + elseif status == "203" then + _, _, file, line, watch_idx = string.find(breakpoint, "^203 Paused%s+(.-)%s+(%d+)%s+(%d+)%s*$") + if file and line and watch_idx then + print("Paused at file " .. file .. " line " .. line .. " (watch expression " .. watch_idx .. ": [" .. watches[watch_idx] .. "])") + end + elseif status == "204" then + local _, _, stream, size = string.find(breakpoint, "^204 Output (%w+) (%d+)$") + if stream and size then + local msg = client:receive(tonumber(size)) + print(msg) + if outputs[stream] then outputs[stream](msg) end + -- this was just the output, so go back reading the response + done = false + end + elseif status == "401" then + local _, _, size = string.find(breakpoint, "^401 Error in Execution (%d+)$") + if size then + local msg = client:receive(tonumber(size)) + print("Error in remote application: " .. msg) + os.exit(1) + return nil, nil, msg -- use return here for those cases where os.exit() is not wanted + end + else + print("Unknown error") + os.exit(1) + -- use return here for those cases where os.exit() is not wanted + return nil, nil, "Debugger error: unexpected response '" .. breakpoint .. "'" + end + if done then break end + end + elseif command == "setb" then + _, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$") + if file and line then + -- if this is a file name, and not a file source + if not file:find('^".*"$') then + file = string.gsub(file, "\\", "/") -- convert slash + file = removebasedir(file, basedir) + end + client:send("SETB " .. file .. " " .. line .. "\n") + if client:receive() == "200 OK" then + set_breakpoint(file, line) + else + print("Error: breakpoint not inserted") + end + else + print("Invalid command") + end + elseif command == "setw" then + local _, _, exp = string.find(params, "^[a-z]+%s+(.+)$") + if exp then + client:send("SETW " .. exp .. "\n") + local answer = client:receive() + local _, _, watch_idx = string.find(answer, "^200 OK (%d+)%s*$") + if watch_idx then + watches[watch_idx] = exp + print("Inserted watch exp no. " .. watch_idx) + else + local _, _, size = string.find(answer, "^401 Error in Expression (%d+)$") + if size then + local err = client:receive(tonumber(size)):gsub(".-:%d+:%s*","") + print("Error: watch expression not set: " .. err) + else + print("Error: watch expression not set") + end + end + else + print("Invalid command") + end + elseif command == "delb" then + _, _, _, file, line = string.find(params, "^([a-z]+)%s+(.-)%s+(%d+)%s*$") + if file and line then + -- if this is a file name, and not a file source + if not file:find('^".*"$') then + file = string.gsub(file, "\\", "/") -- convert slash + file = removebasedir(file, basedir) + end + client:send("DELB " .. file .. " " .. line .. "\n") + if client:receive() == "200 OK" then + remove_breakpoint(file, line) + else + print("Error: breakpoint not removed") + end + else + print("Invalid command") + end + elseif command == "delallb" then + for line, breaks in pairs(breakpoints) do + for file, _ in pairs(breaks) do + client:send("DELB " .. file .. " " .. line .. "\n") + if client:receive() == "200 OK" then + remove_breakpoint(file, line) + else + print("Error: breakpoint at file " .. file .. " line " .. line .. " not removed") + end + end + end + elseif command == "delw" then + local _, _, index = string.find(params, "^[a-z]+%s+(%d+)%s*$") + if index then + client:send("DELW " .. index .. "\n") + if client:receive() == "200 OK" then + watches[index] = nil + else + print("Error: watch expression not removed") + end + else + print("Invalid command") + end + elseif command == "delallw" then + for index, exp in pairs(watches) do + client:send("DELW " .. index .. "\n") + if client:receive() == "200 OK" then + watches[index] = nil + else + print("Error: watch expression at index " .. index .. " [" .. exp .. "] not removed") + end + end + elseif command == "eval" or command == "exec" + or command == "load" or command == "loadstring" + or command == "reload" then + local _, _, exp = string.find(params, "^[a-z]+%s+(.+)$") + if exp or (command == "reload") then + if command == "eval" or command == "exec" then + exp = (exp:gsub("%-%-%[(=*)%[.-%]%1%]", "") -- remove comments + :gsub("%-%-.-\n", " ") -- remove line comments + :gsub("\n", " ")) -- convert new lines + if command == "eval" then exp = "return " .. exp end + client:send("EXEC " .. exp .. "\n") + elseif command == "reload" then + client:send("LOAD 0 -\n") + elseif command == "loadstring" then + local _, _, _, file, lines = string.find(exp, "^([\"'])(.-)%1%s+(.+)") + if not file then + _, _, file, lines = string.find(exp, "^(%S+)%s+(.+)") + end + client:send("LOAD " .. #lines .. " " .. file .. "\n") + client:send(lines) + else + local file = io.open(exp, "r") + if not file and pcall(require, "winapi") then + -- if file is not open and winapi is there, try with a short path; + -- this may be needed for unicode paths on windows + winapi.set_encoding(winapi.CP_UTF8) + file = io.open(winapi.short_path(exp), "r") + end + if not file then error("Cannot open file " .. exp) end + -- read the file and remove the shebang line as it causes a compilation error + local lines = file:read("*all"):gsub("^#!.-\n", "\n") + file:close() + + local file = string.gsub(exp, "\\", "/") -- convert slash + file = removebasedir(file, basedir) + client:send("LOAD " .. #lines .. " " .. file .. "\n") + if #lines > 0 then client:send(lines) end + end + while true do + local params, err = client:receive() + if not params then + return nil, nil, "Debugger connection " .. (err or "error") + end + local done = true + local _, _, status, len = string.find(params, "^(%d+).-%s+(%d+)%s*$") + if status == "200" then + len = tonumber(len) + if len > 0 then + local status, res + local str = client:receive(len) + -- handle serialized table with results + local func, err = loadstring(str) + if func then + status, res = pcall(func) + if not status then err = res + elseif type(res) ~= "table" then + err = "received "..type(res).." instead of expected 'table'" + end + end + if err then + print("Error in processing results: " .. err) + return nil, nil, "Error in processing results: " .. err + end + print(unpack(res)) + return res[1], res + end + elseif status == "201" then + _, _, file, line = string.find(params, "^201 Started%s+(.-)%s+(%d+)%s*$") + elseif status == "202" or params == "200 OK" then + -- do nothing; this only happens when RE/LOAD command gets the response + -- that was for the original command that was aborted + elseif status == "204" then + local _, _, stream, size = string.find(params, "^204 Output (%w+) (%d+)$") + if stream and size then + local msg = client:receive(tonumber(size)) + print(msg) + if outputs[stream] then outputs[stream](msg) end + -- this was just the output, so go back reading the response + done = false + end + elseif status == "401" then + len = tonumber(len) + local res = client:receive(len) + print("Error in expression: " .. res) + return nil, nil, res + else + print("Unknown error") + return nil, nil, "Debugger error: unexpected response after EXEC/LOAD '" .. params .. "'" + end + if done then break end + end + else + print("Invalid command") + end + elseif command == "listb" then + for l, v in pairs(breakpoints) do + for f in pairs(v) do + print(f .. ": " .. l) + end + end + elseif command == "listw" then + for i, v in pairs(watches) do + print("Watch exp. " .. i .. ": " .. v) + end + elseif command == "suspend" then + client:send("SUSPEND\n") + elseif command == "stack" then + client:send("STACK\n") + local resp = client:receive() + local _, _, status, res = string.find(resp, "^(%d+)%s+%w+%s+(.+)%s*$") + if status == "200" then + local func, err = loadstring(res) + if func == nil then + print("Error in stack information: " .. err) + return nil, nil, err + end + local ok, stack = pcall(func) + if not ok then + print("Error in stack information: " .. stack) + return nil, nil, stack + end + for _,frame in ipairs(stack) do + print(serpent.line(frame[1], {comment = false})) + end + return stack + elseif status == "401" then + local _, _, len = string.find(resp, "%s+(%d+)%s*$") + len = tonumber(len) + local res = len > 0 and client:receive(len) or "Invalid stack information." + print("Error in expression: " .. res) + return nil, nil, res + else + print("Unknown error") + return nil, nil, "Debugger error: unexpected response after STACK" + end + elseif command == "output" then + local _, _, stream, mode = string.find(params, "^[a-z]+%s+(%w+)%s+([dcr])%s*$") + if stream and mode then + client:send("OUTPUT "..stream.." "..mode.."\n") + local resp = client:receive() + local _, _, status = string.find(resp, "^(%d+)%s+%w+%s*$") + if status == "200" then + print("Stream "..stream.." redirected") + outputs[stream] = type(options) == 'table' and options.handler or nil + else + print("Unknown error") + return nil, nil, "Debugger error: can't redirect "..stream + end + else + print("Invalid command") + end + elseif command == "basedir" then + local _, _, dir = string.find(params, "^[a-z]+%s+(.+)$") + if dir then + dir = string.gsub(dir, "\\", "/") -- convert slash + if not string.find(dir, "/$") then dir = dir .. "/" end + + local remdir = dir:match("\t(.+)") + if remdir then dir = dir:gsub("/?\t.+", "/") end + basedir = dir + + client:send("BASEDIR "..(remdir or dir).."\n") + local resp = client:receive() + local _, _, status = string.find(resp, "^(%d+)%s+%w+%s*$") + if status == "200" then + print("New base directory is " .. basedir) + else + print("Unknown error") + return nil, nil, "Debugger error: unexpected response after BASEDIR" + end + else + print(basedir) + end + elseif command == "help" then + print("setb -- sets a breakpoint") + print("delb -- removes a breakpoint") + print("delallb -- removes all breakpoints") + print("setw -- adds a new watch expression") + print("delw -- removes the watch expression at index") + print("delallw -- removes all watch expressions") + print("run -- runs until next breakpoint") + print("step -- runs until next line, stepping into function calls") + print("over -- runs until next line, stepping over function calls") + print("out -- runs until line after returning from current function") + print("listb -- lists breakpoints") + print("listw -- lists watch expressions") + print("eval -- evaluates expression on the current context and returns its value") + print("exec -- executes statement on the current context") + print("load -- loads a local file for debugging") + print("reload -- restarts the current debugging session") + print("stack -- reports stack trace") + print("output stdout -- capture and redirect io stream (default|copy|redirect)") + print("basedir [] -- sets the base path of the remote application, or shows the current one") + print("exit -- exits debugger") + else + local _, _, spaces = string.find(params, "^(%s*)$") + if not spaces then + print("Invalid command") + return nil, nil, "Invalid command" + end + end + return file, line +end + +-- Starts debugging server +local function listen(host, port) + host = host or "*" + port = port or mobdebug.port + + local socket = require "socket" + + print("Lua Remote Debugger") + print("Run the program you wish to debug") + + local server = socket.bind(host, port) + local client = server:accept() + + client:send("STEP\n") + client:receive() + + local breakpoint = client:receive() + local _, _, file, line = string.find(breakpoint, "^202 Paused%s+(.-)%s+(%d+)%s*$") + if file and line then + print("Paused at file " .. file ) + print("Type 'help' for commands") + else + local _, _, size = string.find(breakpoint, "^401 Error in Execution (%d+)%s*$") + if size then + print("Error in remote application: ") + print(client:receive(size)) + end + end + + while true do + io.write("> ") + local line = io.read("*line") + handle(line, client) + end +end + +local cocreate +local function coro() + if cocreate then return end -- only set once + cocreate = cocreate or coroutine.create + coroutine.create = function(f, ...) + return cocreate(function(...) + require("mobdebug").on() + return f(...) + end, ...) + end +end + +local moconew +local function moai() + if moconew then return end -- only set once + moconew = moconew or (MOAICoroutine and MOAICoroutine.new) + if not moconew then return end + MOAICoroutine.new = function(...) + local thread = moconew(...) + -- need to support both thread.run and getmetatable(thread).run, which + -- was used in earlier MOAI versions + local mt = thread.run and thread or getmetatable(thread) + local patched = mt.run + mt.run = function(self, f, ...) + return patched(self, function(...) + require("mobdebug").on() + return f(...) + end, ...) + end + return thread + end +end + +-- this is a function that removes all hooks and closes the socket to +-- report back to the controller that the debugging is done. +-- the script that called `done` can still continue. +local function done() + if not (isrunning() and server) then return end + + if not jit then + for co, debugged in pairs(coroutines) do + if debugged then debug.sethook(co) end + end + end + + debug.sethook() + server:close() + + coro_debugger = nil -- to make sure isrunning() returns `false` + seen_hook = nil -- to make sure that the next start() call works + abort = nil -- to make sure that callback calls use proper "abort" value +end + +-- make public functions available +mobdebug.listen = listen +mobdebug.loop = loop +mobdebug.scratchpad = scratchpad +mobdebug.handle = handle +mobdebug.connect = connect +mobdebug.start = start +mobdebug.on = on +mobdebug.off = off +mobdebug.moai = moai +mobdebug.coro = coro +mobdebug.done = done +mobdebug.line = serpent.line +mobdebug.dump = serpent.dump +mobdebug.yield = nil -- callback + +-- this is needed to make "require 'modebug'" to work when mobdebug +-- module is loaded manually +package.loaded.mobdebug = mobdebug + +return mobdebug diff --git a/samples/Lua/HelloLua/proj.android/AndroidManifest.xml b/samples/Lua/HelloLua/proj.android/AndroidManifest.xml index a79a2e0111..0703d5285d 100644 --- a/samples/Lua/HelloLua/proj.android/AndroidManifest.xml +++ b/samples/Lua/HelloLua/proj.android/AndroidManifest.xml @@ -31,4 +31,5 @@ android:normalScreens="true" android:largeScreens="true" android:xlargeScreens="true"/> + From 99345698ea35afb65ab13e30aae1db5e0188887f Mon Sep 17 00:00:00 2001 From: lihex Date: Fri, 24 Jan 2014 17:28:56 +0800 Subject: [PATCH 44/51] reset to default texture format after running test case --- .../Resources/luaScript/PerformanceTest/PerformanceTest.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua b/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua index 070d78b44d..9e2ef7adc9 100644 --- a/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua +++ b/samples/Lua/TestLua/Resources/luaScript/PerformanceTest/PerformanceTest.lua @@ -1353,6 +1353,9 @@ local function runTextureTest() local time local pTexture = nil local pCache = cc.Director:getInstance():getTextureCache() + + local pDefaultFormat = cc.Texture2D:getDefaultAlphaPixelFormat(); + print("RGBA 8888") cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888) pTexture = pCache:addImage(strFileName) @@ -1397,6 +1400,8 @@ local function runTextureTest() print(" ERROR") end pCache:removeTexture(pTexture) + + cc.Texture2D:setDefaultAlphaPixelFormat(pDefaultFormat) end local function PerformTests() print("--------") From b127c7954e01d4c5e11274d05500ae34aff3b44b Mon Sep 17 00:00:00 2001 From: samuele3hu Date: Fri, 24 Jan 2014 17:44:05 +0800 Subject: [PATCH 45/51] issue #3837:Add LuaSocket license file --- licenses/LICENSE_LuaSocket.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 licenses/LICENSE_LuaSocket.txt diff --git a/licenses/LICENSE_LuaSocket.txt b/licenses/LICENSE_LuaSocket.txt new file mode 100644 index 0000000000..b0b5367393 --- /dev/null +++ b/licenses/LICENSE_LuaSocket.txt @@ -0,0 +1,20 @@ +LuaSocket 2.0.2 license +Copyright © 2004-2007 Diego Nehab + +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. From 8c3af04b72d9e4eb4a6d69606e17cb256cee167d Mon Sep 17 00:00:00 2001 From: CocosRobot Date: Fri, 24 Jan 2014 09:48:11 +0000 Subject: [PATCH 46/51] [AUTO] : updating submodule reference to latest autogenerated bindings --- cocos/scripting/auto-generated | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos/scripting/auto-generated b/cocos/scripting/auto-generated index c8375f61cc..e8828b9aa8 160000 --- a/cocos/scripting/auto-generated +++ b/cocos/scripting/auto-generated @@ -1 +1 @@ -Subproject commit c8375f61ccc86b108dc3e57f2a593e30296daf7a +Subproject commit e8828b9aa8b1bfdf08bc3c077ec2cc1ebd9b9c82 From 6e704b6843c5c57d175f1809437da9ca82b6d860 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 17:51:36 +0800 Subject: [PATCH 47/51] issue #3713: Adds AutoreleasePool::isClearing() for easily debugging memory issues. It only valid in DEBUG mode. --- cocos/base/CCAutoreleasePool.cpp | 23 ++++++++++++++++------- cocos/base/CCAutoreleasePool.h | 14 +++++++++++--- cocos/base/CCObject.cpp | 3 ++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/cocos/base/CCAutoreleasePool.cpp b/cocos/base/CCAutoreleasePool.cpp index 77cf41f0fe..9df01c2269 100644 --- a/cocos/base/CCAutoreleasePool.cpp +++ b/cocos/base/CCAutoreleasePool.cpp @@ -29,7 +29,9 @@ NS_CC_BEGIN AutoreleasePool::AutoreleasePool() : _name("") -, _isInClear(false) +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) +, _isClearing(false) +#endif { _managedObjectArray.reserve(150); PoolManager::getInstance()->push(this); @@ -37,7 +39,9 @@ AutoreleasePool::AutoreleasePool() AutoreleasePool::AutoreleasePool(const std::string &name) : _name(name) -, _isInClear(false) +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) +, _isClearing(false) +#endif { _managedObjectArray.reserve(150); PoolManager::getInstance()->push(this); @@ -58,20 +62,23 @@ void AutoreleasePool::addObject(Object* object) void AutoreleasePool::clear() { - _isInClear = true; +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) + _isClearing = true; +#endif for (const auto &obj : _managedObjectArray) { obj->release(); } _managedObjectArray.clear(); - _isInClear = false; +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) + _isClearing = false; +#endif } +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) + bool AutoreleasePool::contains(Object* object) const { - if (_isInClear) - return false; - for (const auto& obj : _managedObjectArray) { if (obj == object) @@ -80,6 +87,8 @@ bool AutoreleasePool::contains(Object* object) const return false; } +#endif + void AutoreleasePool::dump() { CCLOG("autorelease pool: %s, number of managed object %d\n", _name.c_str(), static_cast(_managedObjectArray.size())); diff --git a/cocos/base/CCAutoreleasePool.h b/cocos/base/CCAutoreleasePool.h index 0146cbd962..8dd449fa72 100644 --- a/cocos/base/CCAutoreleasePool.h +++ b/cocos/base/CCAutoreleasePool.h @@ -81,11 +81,17 @@ public: */ void clear(); +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) + /** + * Whether the pool is doing `clear` operation. + */ + bool isClearing() const { return _isClearing; }; + /** * Checks whether the pool contains the specified object. */ bool contains(Object* object) const; - +#endif /** * Dump the objects that are put into autorelease pool. It is used for debugging. * @@ -108,10 +114,12 @@ private: std::vector _managedObjectArray; std::string _name; +#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) /** - * The flag for checking whether Object::release() is invoked in AutoreleasePool::clear(). + * The flag for checking whether the pool is doing `clear` operation. */ - bool _isInClear; + bool _isClearing; +#endif }; class CC_DLL PoolManager diff --git a/cocos/base/CCObject.cpp b/cocos/base/CCObject.cpp index 9e582d95bf..97b0ce540b 100644 --- a/cocos/base/CCObject.cpp +++ b/cocos/base/CCObject.cpp @@ -72,7 +72,8 @@ void Object::release() if (_referenceCount == 0) { - if (PoolManager::getInstance()->isObjectInPools(this)) + auto poolManager = PoolManager::getInstance(); + if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this)) { // Trigger an assert if the reference count is 0 but the object is still in autorelease pool. // This happens when 'autorelease/release' were not used in pairs with 'new/retain'. From b6932d580d6eb5dc5d8408f2348a7e03de7e6a1a Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 17:57:36 +0800 Subject: [PATCH 48/51] issue #3713: Modifies the scope of DEBUG macro in CCAutoreleasePool.h , contains(Object* obj) should be valid in RELEASE version too. --- cocos/base/CCAutoreleasePool.cpp | 4 ---- cocos/base/CCAutoreleasePool.h | 4 +++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cocos/base/CCAutoreleasePool.cpp b/cocos/base/CCAutoreleasePool.cpp index 9df01c2269..3ce5ea4d65 100644 --- a/cocos/base/CCAutoreleasePool.cpp +++ b/cocos/base/CCAutoreleasePool.cpp @@ -75,8 +75,6 @@ void AutoreleasePool::clear() #endif } -#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0) - bool AutoreleasePool::contains(Object* object) const { for (const auto& obj : _managedObjectArray) @@ -87,8 +85,6 @@ bool AutoreleasePool::contains(Object* object) const return false; } -#endif - void AutoreleasePool::dump() { CCLOG("autorelease pool: %s, number of managed object %d\n", _name.c_str(), static_cast(_managedObjectArray.size())); diff --git a/cocos/base/CCAutoreleasePool.h b/cocos/base/CCAutoreleasePool.h index 8dd449fa72..63461f6262 100644 --- a/cocos/base/CCAutoreleasePool.h +++ b/cocos/base/CCAutoreleasePool.h @@ -86,12 +86,13 @@ public: * Whether the pool is doing `clear` operation. */ bool isClearing() const { return _isClearing; }; +#endif /** * Checks whether the pool contains the specified object. */ bool contains(Object* object) const; -#endif + /** * Dump the objects that are put into autorelease pool. It is used for debugging. * @@ -146,6 +147,7 @@ public: AutoreleasePool *getCurrentPool() const; bool isObjectInPools(Object* obj) const; + /** * @js NA * @lua NA From 52ca254ecf52237739b8f072962ef291a67e2347 Mon Sep 17 00:00:00 2001 From: "Huabing.Xu" Date: Fri, 24 Jan 2014 18:39:26 +0800 Subject: [PATCH 49/51] 3.0 Beta2 HotFix: fix shader PositionTextureColorAlphaTest --- cocos/2d/CCShaderCache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos/2d/CCShaderCache.cpp b/cocos/2d/CCShaderCache.cpp index fc06d2d985..aeca686f3a 100644 --- a/cocos/2d/CCShaderCache.cpp +++ b/cocos/2d/CCShaderCache.cpp @@ -290,7 +290,7 @@ void ShaderCache::loadDefaultShader(GLProgram *p, int type) break; case kShaderType_PositionTextureColorAlphaTest: - p->initWithVertexShaderByteArray(ccPositionTextureColor_noMVP_vert, ccPositionTextureColorAlphaTest_frag); + p->initWithVertexShaderByteArray(ccPositionTextureColor_vert, ccPositionTextureColorAlphaTest_frag); p->addAttribute(GLProgram::ATTRIBUTE_NAME_POSITION, GLProgram::VERTEX_ATTRIB_POSITION); p->addAttribute(GLProgram::ATTRIBUTE_NAME_COLOR, GLProgram::VERTEX_ATTRIB_COLOR); From 04d91f7e1d4a643be08f5d11c32639ec4ac635e7 Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 22:33:43 +0800 Subject: [PATCH 50/51] Fix a mistake in Color4B(const Color3B& color). --- cocos/2d/ccTypes.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cocos/2d/ccTypes.cpp b/cocos/2d/ccTypes.cpp index b0bfefc710..11b995efd5 100644 --- a/cocos/2d/ccTypes.cpp +++ b/cocos/2d/ccTypes.cpp @@ -107,9 +107,9 @@ Color4B::Color4B(GLubyte _r, GLubyte _g, GLubyte _b, GLubyte _a) {} Color4B::Color4B(const Color3B& color) -: r(color.r * 255) -, g(color.g * 255) -, b(color.b * 255) +: r(color.r) +, g(color.g) +, b(color.b) , a(255) {} From 8efa186649115eb5668ff6157a581e77e00ad24b Mon Sep 17 00:00:00 2001 From: James Chen Date: Fri, 24 Jan 2014 22:34:14 +0800 Subject: [PATCH 51/51] Fixes a comment typo in CCObject.h. --- cocos/base/CCObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cocos/base/CCObject.cpp b/cocos/base/CCObject.cpp index 97b0ce540b..717e81b9a7 100644 --- a/cocos/base/CCObject.cpp +++ b/cocos/base/CCObject.cpp @@ -97,7 +97,7 @@ void Object::release() // obj->retain(); // obj->autorelease(); // This `autorelease` is the pair of `retain` of previous line. // - // Corrent usage (2): + // Correct usage (2): // // auto obj = Node::create(); // obj->retain();