diff --git a/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java b/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java index 83347c3..cf96aa9 100644 --- a/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java +++ b/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxGLSurfaceView.java @@ -472,4 +472,24 @@ public class Cocos2dxGLSurfaceView extends GLSurfaceView { sb.append("]"); Log.d(Cocos2dxGLSurfaceView.TAG, sb.toString()); } + + /** + * android 7 和 7.1上main线程初始化GL线程的时候会等待初始化完毕,cocos启动和加载时间,和启动第一个页面时间很容易造成anr + * + * @param holder + */ + @Override + public void surfaceRedrawNeeded(SurfaceHolder holder) { + // 特殊处理android 7 和 7.1 初始化时间过长时不产生ANR + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N || Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) { + try { + this.requestRender(); + } catch (Exception e) { + // 如果出错, 就什么都不干了 + } catch (Error e) { + } + } else { + super.surfaceRedrawNeeded(holder); + } + } } diff --git a/templates/frameworks/runtime-src/Classes/AppDelegate.cpp b/templates/frameworks/runtime-src/Classes/AppDelegate.cpp index fade8c8..e5403f8 100644 --- a/templates/frameworks/runtime-src/Classes/AppDelegate.cpp +++ b/templates/frameworks/runtime-src/Classes/AppDelegate.cpp @@ -96,14 +96,13 @@ bool AppDelegate::applicationDidFinishLaunching() auto director = Director::getInstance(); auto glview = director->getOpenGLView(); if (!glview) { - string title = "__PROJECT_COCOS_NAME__"; - glview = cocos2d::GLViewImpl::create(title.c_str()); + glview = cocos2d::GLViewImpl::create("__PROJECT_COCOS_NAME__"); director->setOpenGLView(glview); director->startAnimation(); } // set default FPS - Director::getInstance()->setAnimationInterval(1.0 / 60.0f); + director->setAnimationInterval(1.0 / 60.0f); // register lua module auto engine = LuaEngine::getInstance(); diff --git a/tests/res/audio/bgm.ogg b/tests/res/audio/bgm.ogg new file mode 100755 index 0000000..cb2fd5f Binary files /dev/null and b/tests/res/audio/bgm.ogg differ diff --git a/tests/res/audio/effect.ogg b/tests/res/audio/effect.ogg new file mode 100755 index 0000000..ae55eac Binary files /dev/null and b/tests/res/audio/effect.ogg differ diff --git a/tests/res/button.png b/tests/res/button.png new file mode 100644 index 0000000..9208c25 Binary files /dev/null and b/tests/res/button.png differ diff --git a/tests/res/css/NodeCell.csb b/tests/res/css/NodeCell.csb new file mode 100644 index 0000000..3c77e4b Binary files /dev/null and b/tests/res/css/NodeCell.csb differ diff --git a/tests/res/css/NodeFullScreen.csb b/tests/res/css/NodeFullScreen.csb new file mode 100644 index 0000000..72e182d Binary files /dev/null and b/tests/res/css/NodeFullScreen.csb differ diff --git a/tests/res/css/images/BS08.png b/tests/res/css/images/BS08.png new file mode 100644 index 0000000..0211fa3 Binary files /dev/null and b/tests/res/css/images/BS08.png differ diff --git a/tests/src/app/MyApp.lua b/tests/src/app/MyApp.lua new file mode 100755 index 0000000..5fb845c --- /dev/null +++ b/tests/src/app/MyApp.lua @@ -0,0 +1,18 @@ + +require("config") +require("cocos.init") +require("framework.init") + +local AppBase = require("framework.AppBase") +local MyApp = class("MyApp", AppBase) + +function MyApp:ctor() + MyApp.super.ctor(self) +end + +function MyApp:run() + cc.FileUtils:getInstance():addSearchPath("res/") + self:enterScene("MainScene") +end + +return MyApp diff --git a/tests/src/app/scenes/BaseLayer.lua b/tests/src/app/scenes/BaseLayer.lua new file mode 100755 index 0000000..175786a --- /dev/null +++ b/tests/src/app/scenes/BaseLayer.lua @@ -0,0 +1,26 @@ +local BaseLayer = class("BaseLayer", function() + return ccui.Layout:create() +end) + +function BaseLayer:ctor() + self:setContentSize(cc.size(display.width, display.height)) + self:setTouchEnabled(false) + self:setBackGroundColor(cc.c3b(0x3c, 0x3c, 0x3c)) + self:setBackGroundColorType(1) + + -- back button + local btn = ccui.Button:create() + btn:pos(display.width - 100, 40) + btn:addTo(self) + btn:setTitleText("Back") + btn:setTitleFontSize(26) + btn:addTouchEventListener(function(sender, eventType) + if 2 == eventType then + self:getParent():openScrollView() + self:removeSelf() + audio.stopAll() + end + end) +end + +return BaseLayer diff --git a/tests/src/app/scenes/MainScene.lua b/tests/src/app/scenes/MainScene.lua new file mode 100755 index 0000000..286db57 --- /dev/null +++ b/tests/src/app/scenes/MainScene.lua @@ -0,0 +1,64 @@ +local MainScene = class("MainScene", function() + return display.newScene("MainScene") +end) + +function MainScene:ctor() + local tests = { + "Test_NodeFrameEvent", + "Test_NodeEvent", + "Test_KeypadEvent", + "Test_NodeTouchEvent", + "Test_AccelerometerEvent", + "Test_CocosStudio", + "Test_Audio", + } + + local scrollView = ccui.ScrollView:create() + scrollView:addTo(self) + scrollView:align(display.TOP_CENTER, display.cx, display.top) + self.scrollView = scrollView + + local total = 0 + local btnSize = nil + for i = #tests, 1, -1 do + local btn = ccui.Button:create() + btn:setTitleText(tests[i]) + btn:setTitleFontSize(24) + btn:addTouchEventListener(function(sender, eventType) + if 2 == eventType then + scrollView:setVisible(false) + app:createView(tests[i]):addTo(self) + end + end) + if not btnSize then + btnSize = btn:getContentSize() + end + btn:pos((display.width - btnSize.width) / 2 + btnSize.width / 2, + btnSize.height * total + btnSize.height / 2) + total = total + 1 + + scrollView:addChild(btn) + end + + local totalHeight = btnSize.height * total + scrollView:setInnerContainerSize(cc.size(display.width, totalHeight)) + local scrollHeight = display.height + if totalHeight < scrollHeight then + scrollHeight = totalHeight + end + scrollView:setContentSize(cc.size(display.width, scrollHeight)) +end + +function MainScene:openScrollView() + self.scrollView:setVisible(true) +end + +function MainScene:onEnter() + print("MainScene onEnter") +end + +function MainScene:onExit() + print("MainScene onExit") +end + +return MainScene diff --git a/tests/src/app/views/Test_AccelerometerEvent.lua b/tests/src/app/views/Test_AccelerometerEvent.lua new file mode 100755 index 0000000..44df849 --- /dev/null +++ b/tests/src/app/views/Test_AccelerometerEvent.lua @@ -0,0 +1,36 @@ +local BaseLayer = require("app.scenes.BaseLayer") + +local TestCase = class("Test_AccelerometerEvent", BaseLayer) + +function TestCase:ctor() + self.super.ctor(self) + + -- tips + local label = display.newTTFLabel({ + text = "Test Accelerometer On iOS or Android", + size = 25, + color = cc.c3b(0, 0, 0), + }) + label:align(display.CENTER, display.cx, display.cy + 200) + self:addChild(label) + + -- show + local result = display.newTTFLabel({ + text = "0, 0, 0", + size = 25, + color = cc.c3b(255, 0, 0), + }) + result:center() + self:addChild(result) + + self:addNodeEventListener(cc.ACCELEROMETER_EVENT, function(event) + result:setString("x=" .. event.x) + print("x", event.x) + print("y", event.y) + print("z", event.z) + print("time", event.timestamp) + end) + self:setAccelerometerEnabled(true) +end + +return TestCase diff --git a/tests/src/app/views/Test_Audio.lua b/tests/src/app/views/Test_Audio.lua new file mode 100755 index 0000000..9622eaf --- /dev/null +++ b/tests/src/app/views/Test_Audio.lua @@ -0,0 +1,132 @@ +local BaseLayer = require("app.scenes.BaseLayer") + +local TestCase = class("Test_Audio", BaseLayer) + +function TestCase:ctor() + self.super.ctor(self) + + -- tips + local label = display.newTTFLabel({ + text = "New Audio engine test case", + size = 25, + color = cc.c3b(0, 0, 0), + }) + label:align(display.CENTER, display.cx, display.top - 40) + self:addChild(label) + + local channelCount = 0 + local loadedCB = function(fn, success) + if not success then + print("Fail to load audio:" .. fn) + return + end + + channelCount = channelCount + 1 + local playWay = audio.playBGM + local text = "Play BGM:" + if channelCount > 1 then + playWay = audio.playEffect + text = "Play Effect:" + end + + local btn = ccui.Button:create() + :pos(display.cx, display.height - 50 * channelCount - 100) + :addTo(self) + + btn:setTitleText(text .. fn) + btn:setTitleFontSize(30) + btn:setTitleColor(cc.c3b(255, 255, 0)) + btn:addTouchEventListener(function(sender, eventType) + if 2 == eventType then + playWay(fn) + end + end) + + if channelCount == 2 then + self:loadBtns() + end + end + + -- load audio sync + local btn = ccui.Button:create() + :pos(display.cx, display.height - 100) + :addTo(self) + + btn:setTitleText("Preload oggs") + btn:setTitleFontSize(30) + btn:setTitleColor(cc.c3b(255, 255, 0)) + btn:addTouchEventListener(function(sender, eventType) + if 2 == eventType then + audio.loadFile("audio/bgm.ogg", loadedCB) + audio.loadFile("audio/effect.ogg", loadedCB) + btn:setVisible(false) + end + end) +end + +function TestCase:loadBtns() + local btns = { + {"Down_BGMVolume", function() + audio.setBGMVolume(0.3) + end}, + {"Up_BGMVolume", function() + audio.setBGMVolume(1) + end}, + {"Down_EffectVolume", function() + audio.setEffectVolume(0.3) + end}, + {"Up_EffectVolume", function() + audio.setEffectVolume(1) + end}, + {"PauseAll", function() + audio.pauseAll() + end}, + {"SingleEffect_vol0.5", function() + if not self._effect then + self._effect = audio.playEffect("audio/effect.ogg", true) + if self._effect then + self._effect:setVolume(0.5) -- change volume just for this effect + self:performWithDelay(function() + self._effect:stop() -- stop looped effect + self._effect = nil + end, 3) + end + end + end}, + {"ResumeAll", function() + audio.resumeAll() + end}, + {"StopAll", function() + audio.stopAll() + end}, + {"unloadFile", function() + audio.unloadFile("audio/effect.ogg") + end}, + {"unloadAllFile", function() + audio.unloadAllFile() + end}, + } + + for index, info in ipairs(btns) do + local isOdd = index % 2 == 1 + local posX = display.cx + 150 + if isOdd then + posX = display.cx - 150 + end + local posY = math.floor((index - 1) / 2) * 50 + 50 + local btn = ccui.Button:create() + :pos(posX, posY) + :addTo(self) + + btn:setTitleText(info[1]) + btn:setTitleFontSize(30) + btn:setTitleColor(cc.c3b(255, 255, 0)) + btn:addTouchEventListener(function(sender, eventType) + if 2 == eventType then + info[2]() + end + end) + end +end + +return TestCase diff --git a/tests/src/app/views/Test_CocosStudio.lua b/tests/src/app/views/Test_CocosStudio.lua new file mode 100755 index 0000000..1e514e8 --- /dev/null +++ b/tests/src/app/views/Test_CocosStudio.lua @@ -0,0 +1,40 @@ +local BaseLayer = require("app.scenes.BaseLayer") + +local TestCase = class("Test_CocosStudio", BaseLayer) + +function TestCase:ctor() + self.super.ctor(self) + + local node = cc.CSLoader:getInstance():createNodeWithFlatBuffersFile("css/NodeFullScreen.csb") + node:addTo(self) + :center() + -- Multi-resolution adaptation + ccui.Helper:seekWidgetByName(node, "Panel_top"):setPositionY(display.cy) + ccui.Helper:seekWidgetByName(node, "Panel_bottom"):setPositionY(-display.cy) + + local list = ccui.Helper:seekWidgetByName(node, "ListView") + for i = 1, 5 do + local btn = cc.CSLoader:getInstance():createNodeWithFlatBuffersFile("css/NodeCell.csb") + :getChildren()[1] + btn:removeSelf() + + btn:setTitleText("Name" .. i) + btn:setTitleFontSize(30) + btn:addTouchEventListener(function(sender, eventType) + if 2 == eventType then + print("clicked " .. i) + end + end) + list:pushBackCustomItem(btn) + end + + ccui.Helper:seekWidgetByName(node, "Button_bottom") + :addTouchEventListener(function(sender, eventType) + if 2 == eventType then + self:getParent():openScrollView() + self:removeSelf() + end + end) +end + +return TestCase diff --git a/tests/src/app/views/Test_KeypadEvent.lua b/tests/src/app/views/Test_KeypadEvent.lua new file mode 100755 index 0000000..0debda9 --- /dev/null +++ b/tests/src/app/views/Test_KeypadEvent.lua @@ -0,0 +1,28 @@ +local BaseLayer = require("app.scenes.BaseLayer") + +local TestCase = class("Test_KeypadEvent", BaseLayer) + +function TestCase:ctor() + self.super.ctor(self) + + -- tips + local label = display.newTTFLabel({ + text = "Check result in console log", + size = 25, + color = cc.c3b(0, 0, 0), + }) + label:align(display.CENTER, display.cx, display.cy) + self:addChild(label) + + -- real test + self:addNodeEventListener(cc.KEYPAD_EVENT, function(event) + -- event.code is number + -- event.key is string + print(event.code, event.key, event.type) + end) + self:setKeypadEnabled(true) + + print("==is keypad enable:", self:isKeypadEnabled()) +end + +return TestCase diff --git a/tests/src/app/views/Test_NodeEvent.lua b/tests/src/app/views/Test_NodeEvent.lua new file mode 100755 index 0000000..f5f859c --- /dev/null +++ b/tests/src/app/views/Test_NodeEvent.lua @@ -0,0 +1,51 @@ +local BaseLayer = require("app.scenes.BaseLayer") + +local TestCase = class("Test_NodeEvent", BaseLayer) + +function TestCase:ctor() + self.super.ctor(self) + + -- tips + local label = display.newTTFLabel({ + text = "Check result in console log", + size = 25, + color = cc.c3b(0, 0, 0), + }) + label:align(display.CENTER, display.cx, display.cy) + self:addChild(label) + + -- real test + -- case 1, default handler + self:setNodeEventEnabled(true) + + -- case 2, customer handler + self:performWithDelay(function() + local node = display.newNode() + node:addNodeEventListener(cc.NODE_EVENT, function(event) + print("** node event:", event.name) + end) + node:addTo(self) + end, 1) +end + +function TestCase:onEnter() + print("==onEnter") +end + +function TestCase:onExit() + print("==onExit") +end + +function TestCase:onEnterTransitionFinish() + print("==onEnterTransitionFinish") +end + +function TestCase:onExitTransitionStart() + print("==onExitTransitionStart") +end + +function TestCase:onCleanup() + print("==onCleanup") +end + +return TestCase diff --git a/tests/src/app/views/Test_NodeFrameEvent.lua b/tests/src/app/views/Test_NodeFrameEvent.lua new file mode 100755 index 0000000..bb4c157 --- /dev/null +++ b/tests/src/app/views/Test_NodeFrameEvent.lua @@ -0,0 +1,29 @@ +local BaseLayer = require("app.scenes.BaseLayer") + +local TestCase = class("Test_NodeFrameEvent", BaseLayer) + +function TestCase:ctor() + self.super.ctor(self) + + -- tips + local label = display.newTTFLabel({ + text = "Check result in console log", + size = 25, + color = cc.c3b(0, 0, 0), + }) + label:align(display.CENTER, display.cx, display.cy) + self:addChild(label) + + -- real test + self:addNodeEventListener(cc.NODE_ENTER_FRAME_EVENT, function(dt) + print(dt) + end) + self:scheduleUpdate() + + self:performWithDelay(function() + self:unscheduleUpdate() + print("==unscheduleUpdate") + end, 2) +end + +return TestCase diff --git a/tests/src/app/views/Test_NodeTouchEvent.lua b/tests/src/app/views/Test_NodeTouchEvent.lua new file mode 100755 index 0000000..371a6ce --- /dev/null +++ b/tests/src/app/views/Test_NodeTouchEvent.lua @@ -0,0 +1,48 @@ +local BaseLayer = require("app.scenes.BaseLayer") + +local TestCase = class("Test_NodeTouchEvent", BaseLayer) + +function TestCase:ctor() + self.super.ctor(self) + + -- tips + local label = display.newTTFLabel({ + text = "Left is single touch, right is mulit touchs", + size = 25, + color = cc.c3b(0, 0, 0), + }) + label:align(display.CENTER, display.cx, display.cy + 200) + self:addChild(label) + + -- real test case 1 : single touch + local sp = display.newSprite("button.png") + sp:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event) + dump(event) + if event.name == "began" then + return true + end + end) + sp:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE) -- default mode + sp:setTouchEnabled(true) + sp:pos(150, display.cy):addTo(self) + sp:setScale(0.5) + sp:setRotation(45) + + -- real test case 2 : mulit touch + --[[ + mulit touch always after single touch, so can NOT get touch here, + because BaseLayer get full screen touch. + And mulit touch's began has no "return true" way + ]]-- + local multi = display.newSprite("button.png") + multi:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event) + dump(event) + end) + multi:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE) + multi:setTouchEnabled(true) + multi:pos(display.width - 150, display.cy):addTo(self) + multi:setScale(0.5) + multi:setRotation(45) +end + +return TestCase diff --git a/tests/src/config.lua b/tests/src/config.lua new file mode 100755 index 0000000..283b4e5 --- /dev/null +++ b/tests/src/config.lua @@ -0,0 +1,15 @@ + +-- 0 - disable debug info, 1 - less debug info, 2 - verbose debug info +DEBUG = 1 + +-- display FPS stats on screen +DEBUG_FPS = true + +-- dump memory info every 10 seconds +DEBUG_MEM = false + +-- design resolution +CONFIG_SCREEN_WIDTH = 960 +CONFIG_SCREEN_HEIGHT = 640 + +CONFIG_SCREEN_AUTOSCALE = "FIXED_WIDTH" diff --git a/tests/src/main.lua b/tests/src/main.lua new file mode 100644 index 0000000..2a596ea --- /dev/null +++ b/tests/src/main.lua @@ -0,0 +1,10 @@ + +function __G__TRACKBACK__(errorMessage) + print("----------------------------------------") + print("LUA ERROR: " .. tostring(errorMessage) .. "\n") + print(debug.traceback("", 2)) + print("----------------------------------------") +end + +package.path = package.path .. ";src/?.lua;src/framework/protobuf/?.lua" +require("app.MyApp").new():run() diff --git a/tools/runner/CMakeLists.txt b/tools/runner/CMakeLists.txt new file mode 100644 index 0000000..cbcfdcd --- /dev/null +++ b/tools/runner/CMakeLists.txt @@ -0,0 +1,77 @@ +# Lua Game Runner, a desktop app to debug Lua. + +cmake_minimum_required(VERSION 3.16) + +set(APP_NAME LuaGameRunner) + +project(${APP_NAME}) + +set(COCOS2DX_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../) +set(CMAKE_MODULE_PATH ${COCOS2DX_ROOT_PATH}/cmake/Modules/) + +include(CocosBuildSet) +set(BUILD_LUA_LIBS ON) +add_subdirectory(${COCOS2DX_ROOT_PATH}/cocos ${ENGINE_BINARY_PATH}/cocos/core) + +# record sources, headers +set(GAME_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/Classes/AppDelegate.h + ${CMAKE_CURRENT_SOURCE_DIR}/Classes/setup.h + ) +set(GAME_SOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/Classes/AppDelegate.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Classes/setup.cpp + ) +# sources need to compile info, include dirs and source files + +if(LINUX) + # list(APPEND GAME_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/proj.linux/main.cpp) +elseif(WINDOWS) + list(APPEND GAME_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/proj.win32/getopt.h + ${CMAKE_CURRENT_SOURCE_DIR}/proj.win32/main.h + ${CMAKE_CURRENT_SOURCE_DIR}/proj.win32/resource.h + ) + list(APPEND GAME_SOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/proj.win32/getopt.c + ${CMAKE_CURRENT_SOURCE_DIR}/proj.win32/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/proj.win32/game.rc + ) +elseif(MACOSX) + list(APPEND GAME_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/ConsoleWindowController.h + ) + set(APP_UI_RES + ${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/Icon.icns + ${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/Info.plist + ${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/ConsoleWindow.xib + ) + list(APPEND GAME_SOURCE + ${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/main.mm + ${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/Prefix.pch + ${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/ConsoleWindowController.m + ${APP_UI_RES} + ) +endif() + +set(APP_SRC ${GAME_HEADER} ${GAME_SOURCE}) + +# mark app complie info and libs info +add_executable(${APP_NAME} ${APP_SRC}) +target_link_libraries(${APP_NAME} luacocos2d) +target_include_directories(${APP_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Classes) + +# mark app resources, resource will be copy auto after mark +setup_cocos_app_config(${APP_NAME}) +if(MACOSX) + set_target_properties(${APP_NAME} PROPERTIES RESOURCE "${APP_UI_RES}") + set_target_properties(${APP_NAME} PROPERTIES + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/proj.mac/Info.plist" + ) + set_target_properties(${APP_NAME} PROPERTIES + LINK_FLAGS "-pagezero_size 10000 -image_base 100000000" + ) +elseif(WINDOWS) + cocos_copy_target_dll(${APP_NAME}) +endif() + diff --git a/tools/runner/Classes/AppDelegate.cpp b/tools/runner/Classes/AppDelegate.cpp new file mode 100644 index 0000000..2a88f81 --- /dev/null +++ b/tools/runner/Classes/AppDelegate.cpp @@ -0,0 +1,89 @@ +/**************************************************************************** + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + + 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 "AppDelegate.h" +#include "scripting/lua-bindings/manual/CCLuaEngine.h" +#include "cocos2d.h" +#include "scripting/lua-bindings/manual/lua_module_register.h" +#include "external/xxtea/xxtea.h" + +USING_NS_CC; +using namespace std; + +AppDelegate::AppDelegate() +{ +} + +AppDelegate::~AppDelegate() +{ +} + +// if you want a different context, modify the value of glContextAttrs +// it will affect all platforms +void AppDelegate::initGLContextAttrs() +{ + // set OpenGL context attributes: red,green,blue,alpha,depth,stencil,multisamplesCount + GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8, 0 }; + + GLView::setGLContextAttrs(glContextAttrs); +} + +int register_custom_module(lua_State* L) +{ + // Register your custom module add in Classes here. + return 1; +} + +bool AppDelegate::applicationDidFinishLaunching() +{ + // set default FPS + Director::getInstance()->setAnimationInterval(1.0 / 60.0f); + + // register lua module + auto engine = LuaEngine::getInstance(); + ScriptEngineManager::getInstance()->setScriptEngine(engine); + LuaStack *stack = engine->getLuaStack(); + lua_State *L = stack->getLuaState(); + lua_module_register(L); + //register custom function + register_custom_module(L); + + engine->executeScriptFile("src/main.lua"); + + return true; +} + +// This function will be called when the app is inactive. Note, when receiving a phone call it is invoked. +void AppDelegate::applicationDidEnterBackground() +{ + Director::getInstance()->stopAnimation(); + Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("APP_ENTER_BACKGROUND_EVENT"); +} + +// this function will be called when the app is active again +void AppDelegate::applicationWillEnterForeground() +{ + Director::getInstance()->startAnimation(); + Director::getInstance()->getEventDispatcher()->dispatchCustomEvent("APP_ENTER_FOREGROUND_EVENT"); +} diff --git a/tools/runner/Classes/AppDelegate.h b/tools/runner/Classes/AppDelegate.h new file mode 100644 index 0000000..57c03f0 --- /dev/null +++ b/tools/runner/Classes/AppDelegate.h @@ -0,0 +1,60 @@ +/**************************************************************************** + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + + 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. + ****************************************************************************/ + +#pragma once + +#include "cocos2d.h" + +/** +@brief The cocos2d Application. + +Private inheritance here hides part of interface from Director. +*/ +class AppDelegate : private cocos2d::Application +{ +public: + AppDelegate(); + virtual ~AppDelegate(); + + virtual void initGLContextAttrs(); + + /** + @brief Implement Director and Scene init code here. + @return true Initialize success, app continue. + @return false Initialize failed, app terminate. + */ + virtual bool applicationDidFinishLaunching(); + + /** + @brief Called when the application moves to the background + @param the pointer of the application + */ + virtual void applicationDidEnterBackground(); + + /** + @brief Called when the application reenters the foreground + @param the pointer of the application + */ + virtual void applicationWillEnterForeground(); +}; \ No newline at end of file diff --git a/tools/runner/Classes/setup.cpp b/tools/runner/Classes/setup.cpp new file mode 100644 index 0000000..a0db7b4 --- /dev/null +++ b/tools/runner/Classes/setup.cpp @@ -0,0 +1,177 @@ +#ifdef _WINDOWS +#undef _UNICODE +#include "../proj.win32/getopt.h" +#else +#include +#endif + +#include "setup.h" +#include "cocos2d.h" + +USING_NS_CC; +using namespace std; + +// singleton +static CommandSetup *s_instance = nullptr; + +CommandSetup::CommandSetup() +: _logToFile(false) +, _scale(100) +, _width(960) +, _height(640) +, _relauncher(nullptr) +{ +} + +CommandSetup::~CommandSetup() +{ +} + +CommandSetup* CommandSetup::getInstance() +{ + if (!s_instance) { + s_instance = new (std::nothrow) CommandSetup(); + s_instance->init(); + } + return s_instance; +} + +void CommandSetup::init(void) +{ + // setup hotkeys + auto keyEvent = cocos2d::EventListenerKeyboard::create(); + keyEvent->onKeyReleased = [&](EventKeyboard::KeyCode key, Event*) { + if (key == EventKeyboard::KeyCode::KEY_F5) { + std::string cmdLine = makeCommand(); + _relauncher(cmdLine); + } + }; + Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(keyEvent, 1); +} + +void CommandSetup::setRelauncher(RELAUNCHER cb) +{ + _relauncher = cb; +} + +void CommandSetup::setEngineRootPath(std::string root) +{ + _engineRootPath = root; +} + +// example short: +// -w 1136 -h 640 -s 75 -l -g /newprj -r /newprj/output +// example long: +// --width 1136 --height 640 --scale 75 --log --gamedir /newprj --writedir /newprj/output +void CommandSetup::parseCommand(int argc, char *argv[]) +{ + // parse opts + int ch; + int optIndex = 0; + struct option long_options[] = { + {"width" , required_argument, NULL, 'w'}, + {"height" , required_argument, NULL, 'h'}, + {"scale" , required_argument, NULL, 's'}, + {"log" , no_argument , NULL, 'l'}, + {"gamedir" , required_argument, NULL, 'g'}, + {"writedir", required_argument, NULL, 'r'}, + }; + while((ch = getopt_long(argc, (char * const *)argv, "w:h:s:lg:r:", long_options, &optIndex)) != -1) { + switch(ch) { + case 'l': // -l + _logToFile = true; + break; + case 'w': // -w 1136 + _width = atoi(optarg); + break; + case 'h': // -h 640 + _height = atoi(optarg); + break; + case 's': // -s 75 + _scale = atoi(optarg); + break; + case 'g': // -g "/gamedir" + _gameRootPath = optarg; + break; + case 'r': // -r "/writedir" + _writePath = optarg; + break; + default: + printf("unknow option :%c\n", ch); + } + } + + // parse args, not in use yet + while (optind < argc) { + printf("arg:%s\n", argv[optind]); + optind++; + } +} + +std::string CommandSetup::makeCommand(void) +{ + stringstream stream; + + stream << "-w "; + stream << _width; + + stream << " -h "; + stream << _height; + + stream << " -s "; + stream << _scale; + + stream << " -g "; + stream << _gameRootPath; + + stream << " -r "; + stream << _writePath; + + if (_logToFile) { + stream << " -l"; + } + + return stream.str(); +} + +void CommandSetup::setupEngine(void) +{ + // set default writePath + if (_writePath.size() == 0) { + _writePath = _gameRootPath; + } + + printf("=== begin setup configs ===\n"); + printf("logToFile:%s\n", _logToFile ? "true" : "false"); + printf("scale:%f\n", _scale / 100.0); + printf("size:%dx%d\n", _width, _height); + printf("writePath:%s\n", _writePath.c_str()); + printf("gameRootPath:%s\n", _gameRootPath.c_str()); + printf("engineRootPath:%s\n", _engineRootPath.c_str()); + printf("=== end setup configs ===\n"); + + if (_gameRootPath.size() > 0) { + // load game + std::vector paths; + paths.push_back(_gameRootPath); + FileUtils::getInstance()->setDefaultResourceRootPath(_gameRootPath); + FileUtils::getInstance()->setSearchPaths(paths); + } else { + // load engine default test cases. + std::vector paths; + paths.push_back(_engineRootPath + "tests"); + paths.push_back(_engineRootPath + "templates"); + FileUtils::getInstance()->setDefaultResourceRootPath(paths[0]); + FileUtils::getInstance()->setSearchPaths(paths); + } + + FileUtils::getInstance()->setWritablePath(_writePath); + // initialize director + auto director = Director::getInstance(); + auto glview = director->getOpenGLView(); + if (!glview) { + glview = cocos2d::GLViewImpl::createWithRect("LuaGameRunner", Rect(0, 0, _width, _height), _scale / 100.0f); + director->setOpenGLView(glview); + director->startAnimation(); + } +} diff --git a/tools/runner/Classes/setup.h b/tools/runner/Classes/setup.h new file mode 100644 index 0000000..4c5d71b --- /dev/null +++ b/tools/runner/Classes/setup.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +typedef void (*RELAUNCHER)(std::string& cmdLine); + +class CommandSetup +{ +public: + CommandSetup(); + virtual ~CommandSetup(); + + static CommandSetup* getInstance(); + + void setRelauncher(RELAUNCHER cb); + void setEngineRootPath(std::string root); + void parseCommand(int argc, char *argv[]); + std::string makeCommand(void); + void setupEngine(void); + +private: + void init(void); + + bool _logToFile; + int _scale; + int _width; + int _height; + std::string _writePath; + std::string _gameRootPath; + std::string _engineRootPath; + RELAUNCHER _relauncher; +}; diff --git a/tools/runner/proj.mac/ConsoleWindow.xib b/tools/runner/proj.mac/ConsoleWindow.xib new file mode 100644 index 0000000..4692f09 --- /dev/null +++ b/tools/runner/proj.mac/ConsoleWindow.xib @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/runner/proj.mac/ConsoleWindowController.h b/tools/runner/proj.mac/ConsoleWindowController.h new file mode 100644 index 0000000..698e932 --- /dev/null +++ b/tools/runner/proj.mac/ConsoleWindowController.h @@ -0,0 +1,24 @@ + +#import + +@interface ConsoleWindowController : NSWindowController +{ + NSTextView *textView; + IBOutlet NSButton *checkScroll; + IBOutlet NSButton *topCheckBox; + NSMutableArray *linesCount; + + NSFileHandle *readHandle; +} + +@property (assign) IBOutlet NSTextView *textView; + +- (void) trace:(NSString*)msg; +- (IBAction)onClear:(id)sender; +- (IBAction)onScrollChange:(id)sender; +- (IBAction)onTopChange:(id)sender; + +@end + + + diff --git a/tools/runner/proj.mac/ConsoleWindowController.m b/tools/runner/proj.mac/ConsoleWindowController.m new file mode 100644 index 0000000..59600e5 --- /dev/null +++ b/tools/runner/proj.mac/ConsoleWindowController.m @@ -0,0 +1,119 @@ + +#import "ConsoleWindowController.h" + +@interface ConsoleWindowController () + +@end + +#define MAX_LINES_COUNT 200 + +@implementation ConsoleWindowController +@synthesize textView; + +- (id)initWithWindow:(NSWindow *)window +{ + self = [super initWithWindow:window]; + if (self) + { + // Initialization code here. + linesCount = [[NSMutableArray arrayWithCapacity:MAX_LINES_COUNT + 1] retain]; + // init pipe + NSPipe *pipe = [NSPipe pipe]; + readHandle = [pipe fileHandleForReading]; + int outfd = [[pipe fileHandleForWriting] fileDescriptor]; + if (dup2(outfd, fileno(stderr)) != fileno(stderr) || dup2(outfd, fileno(stdout)) != fileno(stdout)) { + perror("Unable to redirect output"); + } else { + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector(handleNotification:) + name: NSFileHandleReadCompletionNotification + object: readHandle]; + [readHandle readInBackgroundAndNotify]; + } + } + + return self; +} + +- (void)dealloc +{ + [linesCount release]; + [super dealloc]; +} + +- (void)windowDidLoad +{ + [super windowDidLoad]; + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. +} + +- (void)handleNotification:(NSNotification *)note +{ + [readHandle readInBackgroundAndNotify]; + NSData *data = [[note userInfo] objectForKey:NSFileHandleNotificationDataItem]; + NSString *str = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + if (str) { + [self trace:str]; + } else { + NSLog(@"Received non utf8 data, can't print"); + } +} + +- (void) trace:(NSString*)msg +{ + NSFont *font = [NSFont fontWithName:@"Monaco" size:12.0]; + NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName]; + NSAttributedString *string = [[[NSAttributedString alloc] initWithString:msg attributes:attrsDictionary] autorelease]; + NSNumber *len = [NSNumber numberWithUnsignedInteger:[string length]]; + [linesCount addObject:len]; + + NSTextStorage *storage = [textView textStorage]; + [storage beginEditing]; + [storage appendAttributedString:string]; + + if ([linesCount count] >= MAX_LINES_COUNT) + { + len = [linesCount objectAtIndex:0]; + [storage deleteCharactersInRange:NSMakeRange(0, [len unsignedIntegerValue])]; + [linesCount removeObjectAtIndex:0]; + } + + [storage endEditing]; + [textView setTextColor:[NSColor systemBlueColor]];// log text color + [self changeScroll]; +} + +- (void) changeScroll +{ + BOOL scroll = [checkScroll state] == NSControlStateValueOn; + if(scroll) + { + [self.textView scrollRangeToVisible: NSMakeRange(self.textView.string.length, 0)]; + } +} + +- (IBAction)onClear:(id)sender +{ + NSTextStorage *storage = [textView textStorage]; + [storage setAttributedString:[[[NSAttributedString alloc] initWithString:@""] autorelease]]; +} + +- (IBAction)onScrollChange:(id)sender +{ + [self changeScroll]; +} + +- (IBAction)onTopChange:(id)sender +{ + BOOL isTop = [topCheckBox state] == NSControlStateValueOn; + if(isTop) + { + [self.window setLevel:NSFloatingWindowLevel]; + } + else + { + [self.window setLevel:NSNormalWindowLevel]; + } +} + +@end diff --git a/tools/runner/proj.mac/Icon.icns b/tools/runner/proj.mac/Icon.icns new file mode 100644 index 0000000..5a6cd36 Binary files /dev/null and b/tools/runner/proj.mac/Icon.icns differ diff --git a/tools/runner/proj.mac/Info.plist b/tools/runner/proj.mac/Info.plist new file mode 100644 index 0000000..58a9567 --- /dev/null +++ b/tools/runner/proj.mac/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + Icon + CFBundleIdentifier + org.cocos2d-lua.${PRODUCT_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSApplicationCategoryType + public.app-category.games + NSHumanReadableCopyright + Copyright © 2019. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/tools/runner/proj.mac/Prefix.pch b/tools/runner/proj.mac/Prefix.pch new file mode 100644 index 0000000..dde8bdc --- /dev/null +++ b/tools/runner/proj.mac/Prefix.pch @@ -0,0 +1,11 @@ +// +// Prefix header for all source files of the 'Paralaxer' target in the 'Paralaxer' project +// + +#ifdef __OBJC__ + #import +#endif + +#ifdef __cplusplus + #include "cocos2d.h" +#endif diff --git a/tools/runner/proj.mac/main.mm b/tools/runner/proj.mac/main.mm new file mode 100644 index 0000000..3509fbd --- /dev/null +++ b/tools/runner/proj.mac/main.mm @@ -0,0 +1,62 @@ +#include +#include + +#import "ConsoleWindowController.h" +#include "AppDelegate.h" +#include "setup.h" + +USING_NS_CC; + +// uncomment below line, open debug console. +#define USE_CONSOLE_WINDOW + +static std::string getEngineRoot(void) +{ + // get exe path size + uint32_t size = 0; + int res = _NSGetExecutablePath(NULL, &size); + // get exe path, tools/runner/xxx.app/Contents/MacOS/xxx + char *path = (char *)malloc(size + 1); + path[size] = 0; + res = _NSGetExecutablePath(path, &size); + // find engine root + char *p = strstr(path, "tools/runner"); + *p = 0; // cut str + std::string pathTemp(path); + free(path); // free memory + return pathTemp; +} + +static void relaunchSelf(std::string &cmdLine) +{ + NSString *nscmdLine = [NSString stringWithCString:cmdLine.c_str() + encoding:NSUTF8StringEncoding]; + NSArray *args = [nscmdLine componentsSeparatedByString:@" "]; + + NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; + NSMutableDictionary *cfg = [NSMutableDictionary dictionaryWithObject:args + forKey:NSWorkspaceLaunchConfigurationArguments]; + NSError *error = nil; + [[NSWorkspace sharedWorkspace] launchApplicationAtURL:url + options:NSWorkspaceLaunchNewInstance + configuration:cfg error:&error]; + exit(0); +} + +int main(int argc, char *argv[]) +{ + AppDelegate app; + +#ifdef USE_CONSOLE_WINDOW + ConsoleWindowController *consoleController = [[ConsoleWindowController alloc] initWithWindowNibName:@"ConsoleWindow"]; + [consoleController.window orderFrontRegardless]; +#endif + + CommandSetup *cmd = CommandSetup::getInstance(); + cmd->setRelauncher(relaunchSelf); + cmd->setEngineRootPath(getEngineRoot()); + cmd->parseCommand(argc, argv); + cmd->setupEngine(); + + return Application::getInstance()->run(); +} diff --git a/tools/runner/proj.win32/game.ico b/tools/runner/proj.win32/game.ico new file mode 100644 index 0000000..9000415 Binary files /dev/null and b/tools/runner/proj.win32/game.ico differ diff --git a/tools/runner/proj.win32/game.rc b/tools/runner/proj.win32/game.rc new file mode 100644 index 0000000..812f9e6 --- /dev/null +++ b/tools/runner/proj.win32/game.rc @@ -0,0 +1,204 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +/* IDC_STATIC is documented in winuser.h, but not defined. */ +#ifndef IDC_STATIC +#define IDC_STATIC (-1) +#endif + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Chinese (Simplified, PRC) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) +LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED +#pragma code_page(936) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU_COCOS MENU +BEGIN + POPUP "Help(&H)" + BEGIN + MENUITEM "About(&A)", ID_HELP_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG_ABOUT DIALOGEX 0, 0, 243, 94 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About LuaGameRunner" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,173,69,63,18 + CTEXT "LuaGameRunner",IDC_STATIC,28,23,173,17 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_DIALOG_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 236 + TOPMARGIN, 7 + BOTTOMMARGIN, 87 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Chinese (Simplified, PRC) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL +#pragma code_page(1252) + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU_COCOS MENU +BEGIN + POPUP "&Help" + BEGIN + MENUITEM "&About ...", ID_HELP_ABOUT + END +END + +#endif // English resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +GLFW_ICON ICON "game.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "FileDescription", "game Module" + VALUE "FileVersion", "1, 0, 0, 1" + VALUE "InternalName", "LuaGameRunner" + VALUE "LegalCopyright", "Copyright " + VALUE "OriginalFilename", "LuaGameRunner.exe" + VALUE "ProductName", "game Module" + VALUE "ProductVersion", "1, 0, 0, 1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/runner/proj.win32/getopt.c b/tools/runner/proj.win32/getopt.c new file mode 100644 index 0000000..65cfccf --- /dev/null +++ b/tools/runner/proj.win32/getopt.c @@ -0,0 +1,973 @@ +/* Getopt for Microsoft C +This code is a modification of the Free Software Foundation, Inc. +Getopt library for parsing command line argument the purpose was +to provide a Microsoft Visual C friendly derivative. This code +provides functionality for both Unicode and Multibyte builds. + +Date: 02/03/2011 - Ludvik Jerabek - Initial Release +Version: 1.0 +Comment: Supports getopt, getopt_long, and getopt_long_only +and POSIXLY_CORRECT environment flag +License: LGPL + +Revisions: + +02/03/2011 - Ludvik Jerabek - Initial Release +02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 +07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs +08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception +08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB +02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file +08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi +10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features +06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable + +**DISCLAIMER** +THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT +APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY +DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY +USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST +PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON +YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE +EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +*/ +#define _CRT_SECURE_NO_WARNINGS +#include +#include +#include +#include "getopt.h" + +#ifdef __cplusplus + #define _GETOPT_THROW throw() +#else + #define _GETOPT_THROW +#endif + +int optind = 1; +int opterr = 1; +int optopt = '?'; +enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER }; + +// +// +// Ansi structures and functions follow +// +// + +static struct _getopt_data_a +{ + int optind; + int opterr; + int optopt; + char *optarg; + int __initialized; + char *__nextchar; + enum ENUM_ORDERING __ordering; + int __posixly_correct; + int __first_nonopt; + int __last_nonopt; +} getopt_data_a; +char *optarg_a; + +static void exchange_a(char **argv, struct _getopt_data_a *d) +{ + int bottom = d->__first_nonopt; + int middle = d->__last_nonopt; + int top = d->optind; + char *tem; + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + int len = middle - bottom; + register int i; + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + top -= len; + } + else + { + int len = top - middle; + register int i; + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + bottom += len; + } + } + d->__first_nonopt += (d->optind - d->__last_nonopt); + d->__last_nonopt = d->optind; +} +static const char *_getopt_initialize_a (const char *optstring, struct _getopt_data_a *d, int posixly_correct) +{ + d->__first_nonopt = d->__last_nonopt = d->optind; + d->__nextchar = NULL; + d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT"); + if (optstring[0] == '-') + { + d->__ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + d->__ordering = REQUIRE_ORDER; + ++optstring; + } + else if (d->__posixly_correct) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + return optstring; +} +int _getopt_internal_r_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct) +{ + int print_errors = d->opterr; + if (argc < 1) + return -1; + d->optarg = NULL; + if (d->optind == 0 || !d->__initialized) + { + if (d->optind == 0) + d->optind = 1; + optstring = _getopt_initialize_a (optstring, d, posixly_correct); + d->__initialized = 1; + } + else if (optstring[0] == '-' || optstring[0] == '+') + optstring++; + if (optstring[0] == ':') + print_errors = 0; + if (d->__nextchar == NULL || *d->__nextchar == '\0') + { + if (d->__last_nonopt > d->optind) + d->__last_nonopt = d->optind; + if (d->__first_nonopt > d->optind) + d->__first_nonopt = d->optind; + if (d->__ordering == PERMUTE) + { + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_a ((char **) argv, d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; + while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) + d->optind++; + d->__last_nonopt = d->optind; + } + if (d->optind != argc && !strcmp(argv[d->optind], "--")) + { + d->optind++; + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_a((char **) argv, d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; + d->optind = argc; + } + if (d->optind == argc) + { + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } + if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0')) + { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } + d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-')); + } + if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1]))))) + { + char *nameend; + unsigned int namelen; + const struct option_a *p; + const struct option_a *pfound = NULL; + struct option_list + { + const struct option_a *p; + struct option_list *next; + } *ambig_list = NULL; + int exact = 0; + int indfound = -1; + int option_index; + for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++); + namelen = (unsigned int)(nameend - d->__nextchar); + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, d->__nextchar, namelen)) + { + if (namelen == (unsigned int)strlen(p->name)) + { + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + pfound = p; + indfound = option_index; + } + else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) + { + struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); + newp->p = p; + newp->next = ambig_list; + ambig_list = newp; + } + } + if (ambig_list != NULL && !exact) + { + if (print_errors) + { + struct option_list first; + first.p = pfound; + first.next = ambig_list; + ambig_list = &first; + fprintf (stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); + do + { + fprintf (stderr, " '--%s'", ambig_list->p->name); + ambig_list = ambig_list->next; + } + while (ambig_list != NULL); + fputc ('\n', stderr); + } + d->__nextchar += strlen(d->__nextchar); + d->optind++; + d->optopt = 0; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + d->optind++; + if (*nameend) + { + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { + if (argv[d->optind - 1][1] == '-') + { + fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name); + } + else + { + fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name); + } + } + d->__nextchar += strlen(d->__nextchar); + d->optopt = pfound->val; + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { + fprintf(stderr,"%s: option '--%s' requires an argument\n",argv[0], pfound->name); + } + d->__nextchar += strlen(d->__nextchar); + d->optopt = pfound->val; + return optstring[0] == ':' ? ':' : '?'; + } + } + d->__nextchar += strlen(d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL) + { + if (print_errors) + { + if (argv[d->optind][1] == '-') + { + fprintf(stderr, "%s: unrecognized option '--%s'\n",argv[0], d->__nextchar); + } + else + { + fprintf(stderr, "%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar); + } + } + d->__nextchar = (char *)""; + d->optind++; + d->optopt = 0; + return '?'; + } + } + { + char c = *d->__nextchar++; + char *temp = (char*)strchr(optstring, c); + if (*d->__nextchar == '\0') + ++d->optind; + if (temp == NULL || c == ':' || c == ';') + { + if (print_errors) + { + fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c); + } + d->optopt = c; + return '?'; + } + if (temp[0] == 'W' && temp[1] == ';') + { + char *nameend; + const struct option_a *p; + const struct option_a *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + if (longopts == NULL) + goto no_longs; + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c); + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + return c; + } + else + d->optarg = argv[d->optind++]; + for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++); + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) == strlen(p->name)) + { + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + pfound = p; + indfound = option_index; + } + else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { + fprintf(stderr, "%s: option '-W %s' is ambiguous\n",argv[0], d->optarg); + } + d->__nextchar += strlen(d->__nextchar); + d->optind++; + return '?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { + fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name); + } + d->__nextchar += strlen(d->__nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { + fprintf(stderr, "%s: option '-W %s' requires an argument\n",argv[0], pfound->name); + } + d->__nextchar += strlen(d->__nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + else + d->optarg = NULL; + d->__nextchar += strlen(d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } +no_longs: + d->__nextchar = NULL; + return 'W'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else + { + if (*d->__nextchar != '\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + fprintf(stderr,"%s: option requires an argument -- '%c'\n",argv[0], c); + } + d->optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } + } + return c; + } +} +int _getopt_internal_a (int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct) +{ + int result; + getopt_data_a.optind = optind; + getopt_data_a.opterr = opterr; + result = _getopt_internal_r_a (argc, argv, optstring, longopts,longind, long_only, &getopt_data_a,posixly_correct); + optind = getopt_data_a.optind; + optarg_a = getopt_data_a.optarg; + optopt = getopt_data_a.optopt; + return result; +} +int getopt_a (int argc, char *const *argv, const char *optstring) _GETOPT_THROW +{ + return _getopt_internal_a (argc, argv, optstring, (const struct option_a *) 0, (int *) 0, 0, 0); +} +int getopt_long_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW +{ + return _getopt_internal_a (argc, argv, options, long_options, opt_index, 0, 0); +} +int getopt_long_only_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW +{ + return _getopt_internal_a (argc, argv, options, long_options, opt_index, 1, 0); +} +int _getopt_long_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) +{ + return _getopt_internal_r_a (argc, argv, options, long_options, opt_index,0, d, 0); +} +int _getopt_long_only_r_a (int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d) +{ + return _getopt_internal_r_a (argc, argv, options, long_options, opt_index, 1, d, 0); +} + +// +// +// Unicode Structures and Functions +// +// + +static struct _getopt_data_w +{ + int optind; + int opterr; + int optopt; + wchar_t *optarg; + int __initialized; + wchar_t *__nextchar; + enum ENUM_ORDERING __ordering; + int __posixly_correct; + int __first_nonopt; + int __last_nonopt; +} getopt_data_w; +wchar_t *optarg_w; + +static void exchange_w(wchar_t **argv, struct _getopt_data_w *d) +{ + int bottom = d->__first_nonopt; + int middle = d->__last_nonopt; + int top = d->optind; + wchar_t *tem; + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + int len = middle - bottom; + register int i; + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + top -= len; + } + else + { + int len = top - middle; + register int i; + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + bottom += len; + } + } + d->__first_nonopt += (d->optind - d->__last_nonopt); + d->__last_nonopt = d->optind; +} +static const wchar_t *_getopt_initialize_w (const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct) +{ + d->__first_nonopt = d->__last_nonopt = d->optind; + d->__nextchar = NULL; + d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT"); + if (optstring[0] == L'-') + { + d->__ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == L'+') + { + d->__ordering = REQUIRE_ORDER; + ++optstring; + } + else if (d->__posixly_correct) + d->__ordering = REQUIRE_ORDER; + else + d->__ordering = PERMUTE; + return optstring; +} +int _getopt_internal_r_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct) +{ + int print_errors = d->opterr; + if (argc < 1) + return -1; + d->optarg = NULL; + if (d->optind == 0 || !d->__initialized) + { + if (d->optind == 0) + d->optind = 1; + optstring = _getopt_initialize_w (optstring, d, posixly_correct); + d->__initialized = 1; + } + else if (optstring[0] == L'-' || optstring[0] == L'+') + optstring++; + if (optstring[0] == L':') + print_errors = 0; + if (d->__nextchar == NULL || *d->__nextchar == L'\0') + { + if (d->__last_nonopt > d->optind) + d->__last_nonopt = d->optind; + if (d->__first_nonopt > d->optind) + d->__first_nonopt = d->optind; + if (d->__ordering == PERMUTE) + { + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_w((wchar_t **) argv, d); + else if (d->__last_nonopt != d->optind) + d->__first_nonopt = d->optind; + while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) + d->optind++; + d->__last_nonopt = d->optind; + } + if (d->optind != argc && !wcscmp(argv[d->optind], L"--")) + { + d->optind++; + if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind) + exchange_w((wchar_t **) argv, d); + else if (d->__first_nonopt == d->__last_nonopt) + d->__first_nonopt = d->optind; + d->__last_nonopt = argc; + d->optind = argc; + } + if (d->optind == argc) + { + if (d->__first_nonopt != d->__last_nonopt) + d->optind = d->__first_nonopt; + return -1; + } + if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0')) + { + if (d->__ordering == REQUIRE_ORDER) + return -1; + d->optarg = argv[d->optind++]; + return 1; + } + d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-')); + } + if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1]))))) + { + wchar_t *nameend; + unsigned int namelen; + const struct option_w *p; + const struct option_w *pfound = NULL; + struct option_list + { + const struct option_w *p; + struct option_list *next; + } *ambig_list = NULL; + int exact = 0; + int indfound = -1; + int option_index; + for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++); + namelen = (unsigned int)(nameend - d->__nextchar); + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!wcsncmp(p->name, d->__nextchar, namelen)) + { + if (namelen == (unsigned int)wcslen(p->name)) + { + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + pfound = p; + indfound = option_index; + } + else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) + { + struct option_list *newp = (struct option_list*)alloca(sizeof(*newp)); + newp->p = p; + newp->next = ambig_list; + ambig_list = newp; + } + } + if (ambig_list != NULL && !exact) + { + if (print_errors) + { + struct option_list first; + first.p = pfound; + first.next = ambig_list; + ambig_list = &first; + fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]); + do + { + fwprintf (stderr, L" '--%s'", ambig_list->p->name); + ambig_list = ambig_list->next; + } + while (ambig_list != NULL); + fputwc (L'\n', stderr); + } + d->__nextchar += wcslen(d->__nextchar); + d->optind++; + d->optopt = 0; + return L'?'; + } + if (pfound != NULL) + { + option_index = indfound; + d->optind++; + if (*nameend) + { + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { + if (argv[d->optind - 1][1] == L'-') + { + fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n",argv[0], pfound->name); + } + else + { + fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n",argv[0], argv[d->optind - 1][0],pfound->name); + } + } + d->__nextchar += wcslen(d->__nextchar); + d->optopt = pfound->val; + return L'?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { + fwprintf(stderr,L"%s: option '--%s' requires an argument\n",argv[0], pfound->name); + } + d->__nextchar += wcslen(d->__nextchar); + d->optopt = pfound->val; + return optstring[0] == L':' ? L':' : L'?'; + } + } + d->__nextchar += wcslen(d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL) + { + if (print_errors) + { + if (argv[d->optind][1] == L'-') + { + fwprintf(stderr, L"%s: unrecognized option '--%s'\n",argv[0], d->__nextchar); + } + else + { + fwprintf(stderr, L"%s: unrecognized option '%c%s'\n",argv[0], argv[d->optind][0], d->__nextchar); + } + } + d->__nextchar = (wchar_t *)L""; + d->optind++; + d->optopt = 0; + return L'?'; + } + } + { + wchar_t c = *d->__nextchar++; + wchar_t *temp = (wchar_t*)wcschr(optstring, c); + if (*d->__nextchar == L'\0') + ++d->optind; + if (temp == NULL || c == L':' || c == L';') + { + if (print_errors) + { + fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c); + } + d->optopt = c; + return L'?'; + } + if (temp[0] == L'W' && temp[1] == L';') + { + wchar_t *nameend; + const struct option_w *p; + const struct option_w *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound = 0; + int option_index; + if (longopts == NULL) + goto no_longs; + if (*d->__nextchar != L'\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c); + } + d->optopt = c; + if (optstring[0] == L':') + c = L':'; + else + c = L'?'; + return c; + } + else + d->optarg = argv[d->optind++]; + for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++); + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar)) + { + if ((unsigned int) (nameend - d->__nextchar) == wcslen(p->name)) + { + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + pfound = p; + indfound = option_index; + } + else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val) + ambig = 1; + } + if (ambig && !exact) + { + if (print_errors) + { + fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n",argv[0], d->optarg); + } + d->__nextchar += wcslen(d->__nextchar); + d->optind++; + return L'?'; + } + if (pfound != NULL) + { + option_index = indfound; + if (*nameend) + { + if (pfound->has_arg) + d->optarg = nameend + 1; + else + { + if (print_errors) + { + fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n",argv[0], pfound->name); + } + d->__nextchar += wcslen(d->__nextchar); + return L'?'; + } + } + else if (pfound->has_arg == 1) + { + if (d->optind < argc) + d->optarg = argv[d->optind++]; + else + { + if (print_errors) + { + fwprintf(stderr, L"%s: option '-W %s' requires an argument\n",argv[0], pfound->name); + } + d->__nextchar += wcslen(d->__nextchar); + return optstring[0] == L':' ? L':' : L'?'; + } + } + else + d->optarg = NULL; + d->__nextchar += wcslen(d->__nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } +no_longs: + d->__nextchar = NULL; + return L'W'; + } + if (temp[1] == L':') + { + if (temp[2] == L':') + { + if (*d->__nextchar != L'\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else + d->optarg = NULL; + d->__nextchar = NULL; + } + else + { + if (*d->__nextchar != L'\0') + { + d->optarg = d->__nextchar; + d->optind++; + } + else if (d->optind == argc) + { + if (print_errors) + { + fwprintf(stderr,L"%s: option requires an argument -- '%c'\n",argv[0], c); + } + d->optopt = c; + if (optstring[0] == L':') + c = L':'; + else + c = L'?'; + } + else + d->optarg = argv[d->optind++]; + d->__nextchar = NULL; + } + } + return c; + } +} +int _getopt_internal_w (int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct) +{ + int result; + getopt_data_w.optind = optind; + getopt_data_w.opterr = opterr; + result = _getopt_internal_r_w (argc, argv, optstring, longopts,longind, long_only, &getopt_data_w,posixly_correct); + optind = getopt_data_w.optind; + optarg_w = getopt_data_w.optarg; + optopt = getopt_data_w.optopt; + return result; +} +int getopt_w (int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW +{ + return _getopt_internal_w (argc, argv, optstring, (const struct option_w *) 0, (int *) 0, 0, 0); +} +int getopt_long_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW +{ + return _getopt_internal_w (argc, argv, options, long_options, opt_index, 0, 0); +} +int getopt_long_only_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW +{ + return _getopt_internal_w (argc, argv, options, long_options, opt_index, 1, 0); +} +int _getopt_long_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) +{ + return _getopt_internal_r_w (argc, argv, options, long_options, opt_index,0, d, 0); +} +int _getopt_long_only_r_w (int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d) +{ + return _getopt_internal_r_w (argc, argv, options, long_options, opt_index, 1, d, 0); +} \ No newline at end of file diff --git a/tools/runner/proj.win32/getopt.h b/tools/runner/proj.win32/getopt.h new file mode 100644 index 0000000..3360934 --- /dev/null +++ b/tools/runner/proj.win32/getopt.h @@ -0,0 +1,136 @@ +/* Getopt for Microsoft C +This code is a modification of the Free Software Foundation, Inc. +Getopt library for parsing command line argument the purpose was +to provide a Microsoft Visual C friendly derivative. This code +provides functionality for both Unicode and Multibyte builds. + +Date: 02/03/2011 - Ludvik Jerabek - Initial Release +Version: 1.0 +Comment: Supports getopt, getopt_long, and getopt_long_only +and POSIXLY_CORRECT environment flag +License: LGPL + +Revisions: + +02/03/2011 - Ludvik Jerabek - Initial Release +02/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4 +07/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs +08/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception +08/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB +02/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file +08/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi +10/15/2012 - Ludvik Jerabek - Modified to match latest GNU features +06/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable + +**DISCLAIMER** +THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE +EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT +APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY +DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY +USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST +PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON +YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE +EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +*/ +#ifndef __GETOPT_H_ + #define __GETOPT_H_ + + #ifdef _GETOPT_API + #undef _GETOPT_API + #endif + + #if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT) + #error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually" + #elif defined(STATIC_GETOPT) + #pragma message("Warning static builds of getopt violate the Lesser GNU Public License") + #define _GETOPT_API + #elif defined(EXPORTS_GETOPT) + #pragma message("Exporting getopt library") + #define _GETOPT_API __declspec(dllexport) + #else + #pragma message("Importing getopt library") + #define _GETOPT_API __declspec(dllimport) + #endif + + // Change behavior for C\C++ + #ifdef __cplusplus + #define _BEGIN_EXTERN_C extern "C" { + #define _END_EXTERN_C } + #define _GETOPT_THROW throw() + #else + #define _BEGIN_EXTERN_C + #define _END_EXTERN_C + #define _GETOPT_THROW + #endif + + // Standard GNU options + #define null_argument 0 /*Argument Null*/ + #define no_argument 0 /*Argument Switch Only*/ + #define required_argument 1 /*Argument Required*/ + #define optional_argument 2 /*Argument Optional*/ + + // Shorter Options + #define ARG_NULL 0 /*Argument Null*/ + #define ARG_NONE 0 /*Argument Switch Only*/ + #define ARG_REQ 1 /*Argument Required*/ + #define ARG_OPT 2 /*Argument Optional*/ + + #include + #include + +_BEGIN_EXTERN_C + + extern _GETOPT_API int optind; + extern _GETOPT_API int opterr; + extern _GETOPT_API int optopt; + + // Ansi + struct option_a + { + const char* name; + int has_arg; + int *flag; + int val; + }; + extern _GETOPT_API char *optarg_a; + extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW; + extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; + extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW; + + // Unicode + struct option_w + { + const wchar_t* name; + int has_arg; + int *flag; + int val; + }; + extern _GETOPT_API wchar_t *optarg_w; + extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW; + extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; + extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW; + +_END_EXTERN_C + + #undef _BEGIN_EXTERN_C + #undef _END_EXTERN_C + #undef _GETOPT_THROW + #undef _GETOPT_API + + #ifdef _UNICODE + #define getopt getopt_w + #define getopt_long getopt_long_w + #define getopt_long_only getopt_long_only_w + #define option option_w + #define optarg optarg_w + #else + #define getopt getopt_a + #define getopt_long getopt_long_a + #define getopt_long_only getopt_long_only_a + #define option option_a + #define optarg optarg_a + #endif +#endif // __GETOPT_H_ diff --git a/tools/runner/proj.win32/main.cpp b/tools/runner/proj.win32/main.cpp new file mode 100644 index 0000000..aa2f72d --- /dev/null +++ b/tools/runner/proj.win32/main.cpp @@ -0,0 +1,124 @@ +#include "main.h" +#include "cocos2d.h" +#include "../Classes/AppDelegate.h" +#include "setup.h" + +USING_NS_CC; + +// uncomment below line, open debug console +#define USE_WIN32_CONSOLE + +static std::string getEngineRoot(void) +{ + TCHAR szAppDir[MAX_PATH] = { 0 }; + if (!GetModuleFileName(NULL, szAppDir, MAX_PATH)) + return ""; + + int len = wcslen(szAppDir) + 1; + char *chAppDir = (char *)malloc(len); + wcstombs(chAppDir, szAppDir, len); + chAppDir[len - 1] = '\0'; + + // find engine root + char *p = strstr(chAppDir, "tools\\runner"); + *p = 0; // cut str + std::string pathTemp(chAppDir); + free(chAppDir); // free memory + return pathTemp; +} + +static void relaunchSelf(std::string& cmdLine) +{ + // get exe path + TCHAR szAppDir[MAX_PATH] = { 0 }; + if (!GetModuleFileName(NULL, szAppDir, MAX_PATH)) + return; + + int len = wcslen(szAppDir) + 1; + char* chAppDir = (char*)malloc(len); + wcstombs(chAppDir, szAppDir, len); + chAppDir[len - 1] = '\0'; + + std::string exePath(chAppDir); + free(chAppDir); // free memory + + std::string winCmd = exePath + " " + cmdLine; + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx + SECURITY_ATTRIBUTES sa = { 0 }; + sa.nLength = sizeof(sa); + + PROCESS_INFORMATION pi = { 0 }; + STARTUPINFO si = { 0 }; + si.cb = sizeof(STARTUPINFO); + +#define MAX_COMMAND 1024 // lenth of commandLine is always beyond MAX_PATH + + WCHAR command[MAX_COMMAND]; + memset(command, 0, sizeof(command)); + MultiByteToWideChar(CP_ACP, 0, winCmd.c_str(), -1, command, MAX_COMMAND); + + BOOL success = CreateProcess(NULL, + command, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + FALSE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &si, // STARTUPINFO pointer + &pi); // receives PROCESS_INFORMATION + if (!success) { + printf("relaunchSelf fail: %s", winCmd.c_str()); + } + exit(0); +} + +int WINAPI _tWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + +#ifdef USE_WIN32_CONSOLE + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); +#endif + + // create the application instance + AppDelegate app; + + // convert __wargv to argv + char **argv = (char **)malloc(__argc * sizeof(char *)); + for (int i = 0; i < __argc; ++i) { + int len = wcslen(__wargv[i]) + 1; + char *buf = (char *)malloc(len); + wcstombs(buf, __wargv[i], len); + buf[len - 1] = '\0'; + argv[i] = buf; + } + + CommandSetup* cmd = CommandSetup::getInstance(); + cmd->setRelauncher(relaunchSelf); + cmd->setEngineRootPath(getEngineRoot()); + cmd->parseCommand(__argc, argv); + cmd->setupEngine(); + + // free __wargv + for (int i = 0; i < __argc; ++i) { + free(argv[i]); + } + free(argv); + + int ret = Application::getInstance()->run(); + +#ifdef USE_WIN32_CONSOLE + FreeConsole(); +#endif + + return ret; +} diff --git a/tools/runner/proj.win32/main.h b/tools/runner/proj.win32/main.h new file mode 100644 index 0000000..7943814 --- /dev/null +++ b/tools/runner/proj.win32/main.h @@ -0,0 +1,35 @@ +/**************************************************************************** + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + + 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. + ****************************************************************************/ + +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +// Windows Header Files: +#include +#include + +// C RunTime Header Files +#include "platform/CCStdC.h" + diff --git a/tools/runner/proj.win32/resource.h b/tools/runner/proj.win32/resource.h new file mode 100644 index 0000000..aa09388 --- /dev/null +++ b/tools/runner/proj.win32/resource.h @@ -0,0 +1,45 @@ +/**************************************************************************** + Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd. + + 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. + ****************************************************************************/ + +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by game.RC +// + +#define IDS_PROJNAME 100 +#define IDR_TESTJS 100 + +#define ID_FILE_NEW_WINDOW 32771 +#define ID_HELP_ABOUT 32772 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 32775 +#endif +#endif