cocos_js/cocos/scripting/js-bindings/manual/jsb_cocos2dx_manual.cpp
2022-06-30 13:08:54 +08:00

414 lines
12 KiB
C++

/****************************************************************************
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
http://www.cocos.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated engine source code (the "Software"), a limited,
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
to use Cocos Creator solely to develop games on your target platforms. You shall
not use Cocos Creator software for developing other software or tools that's
used for developing games. You are not granted to publish, distribute,
sublicense, and/or sell copies of Cocos Creator.
The software or tools in this License Agreement are licensed, not sold.
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
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 "jsb_cocos2dx_manual.hpp"
#include "cocos/scripting/js-bindings/jswrapper/SeApi.h"
#include "cocos/scripting/js-bindings/manual/jsb_conversions.hpp"
//#include "cocos/scripting/js-bindings/manual/jsb_global.h"
#include "storage/local-storage/LocalStorage.h"
#include <sstream>
using namespace cocos2d;
extern se::Object* __jsb_cocos2d_FileUtils_proto;
static bool jsb_cocos2dx_empty_func(se::State& s)
{
return true;
}
SE_BIND_FUNC(jsb_cocos2dx_empty_func)
class __JSPlistDelegator: public cocos2d::SAXDelegator
{
public:
static __JSPlistDelegator* getInstance() {
static __JSPlistDelegator* pInstance = NULL;
if (pInstance == NULL) {
pInstance = new (std::nothrow) __JSPlistDelegator();
}
return pInstance;
};
virtual ~__JSPlistDelegator();
cocos2d::SAXParser* getParser();
std::string parse(const std::string& path);
std::string parseText(const std::string& text);
// implement pure virtual methods of SAXDelegator
void startElement(void *ctx, const char *name, const char **atts) override;
void endElement(void *ctx, const char *name) override;
void textHandler(void *ctx, const char *ch, int len) override;
private:
cocos2d::SAXParser _parser;
std::string _result;
bool _isStoringCharacters;
std::string _currentValue;
};
cocos2d::SAXParser* __JSPlistDelegator::getParser() {
return &_parser;
}
std::string __JSPlistDelegator::parse(const std::string& path) {
_result.clear();
SAXParser parser;
if (false != parser.init("UTF-8") )
{
parser.setDelegator(this);
parser.parse(FileUtils::getInstance()->fullPathForFilename(path));
}
return _result;
}
__JSPlistDelegator::~__JSPlistDelegator(){
CCLOGINFO("deallocing __JSSAXDelegator: %p", this);
}
std::string __JSPlistDelegator::parseText(const std::string& text){
_result.clear();
SAXParser parser;
if (false != parser.init("UTF-8") )
{
parser.setDelegator(this);
parser.parse(text.c_str(), text.size());
}
return _result;
}
void __JSPlistDelegator::startElement(void *ctx, const char *name, const char **atts) {
_isStoringCharacters = true;
_currentValue.clear();
std::string elementName = (char*)name;
int end = (int)_result.size() - 1;
if(end >= 0 && _result[end] != '{' && _result[end] != '[' && _result[end] != ':') {
_result += ",";
}
if (elementName == "dict") {
_result += "{";
}
else if (elementName == "array") {
_result += "[";
}
}
void __JSPlistDelegator::endElement(void *ctx, const char *name) {
_isStoringCharacters = false;
std::string elementName = (char*)name;
if (elementName == "dict") {
_result += "}";
}
else if (elementName == "array") {
_result += "]";
}
else if (elementName == "key") {
_result += "\"" + _currentValue + "\":";
}
else if (elementName == "string") {
_result += "\"" + _currentValue + "\"";
}
else if (elementName == "false" || elementName == "true") {
_result += elementName;
}
else if (elementName == "real" || elementName == "integer") {
_result += _currentValue;
}
}
void __JSPlistDelegator::textHandler(void*, const char *ch, int len) {
std::string text((char*)ch, 0, len);
if (_isStoringCharacters)
{
_currentValue += text;
}
}
// cc.sys.localStorage
static bool JSB_localStorageGetItem(se::State& s)
{
const auto& args = s.args();
size_t argc = args.size();
if (argc == 1)
{
std::string ret_val;
bool ok = true;
std::string key;
ok = seval_to_std_string(args[0], &key);
SE_PRECONDITION2(ok, false, "Error processing arguments");
std::string value;
ok = localStorageGetItem(key, &value);
if (ok)
s.rval().setString(value);
else
s.rval().setNull(); // Should return null to make JSB behavior same as Browser since returning undefined will make JSON.parse(undefined) trigger exception.
return true;
}
SE_REPORT_ERROR("Invalid number of arguments");
return false;
}
SE_BIND_FUNC(JSB_localStorageGetItem)
static bool JSB_localStorageRemoveItem(se::State& s)
{
const auto& args = s.args();
size_t argc = args.size();
if (argc == 1)
{
bool ok = true;
std::string key;
ok = seval_to_std_string(args[0], &key);
SE_PRECONDITION2(ok, false, "Error processing arguments");
localStorageRemoveItem(key);
return true;
}
SE_REPORT_ERROR("Invalid number of arguments");
return false;
}
SE_BIND_FUNC(JSB_localStorageRemoveItem)
static bool JSB_localStorageSetItem(se::State& s)
{
const auto& args = s.args();
size_t argc = args.size();
if (argc == 2)
{
bool ok = true;
std::string key;
ok = seval_to_std_string(args[0], &key);
SE_PRECONDITION2(ok, false, "Error processing arguments");
std::string value;
ok = seval_to_std_string(args[1], &value);
SE_PRECONDITION2(ok, false, "Error processing arguments");
localStorageSetItem(key, value);
return true;
}
SE_REPORT_ERROR("Invalid number of arguments");
return false;
}
SE_BIND_FUNC(JSB_localStorageSetItem)
static bool JSB_localStorageClear(se::State& s)
{
const auto& args = s.args();
size_t argc = args.size();
if (argc == 0)
{
localStorageClear();
return true;
}
SE_REPORT_ERROR("Invalid number of arguments");
return false;
}
SE_BIND_FUNC(JSB_localStorageClear)
static bool JSB_localStorageKey(se::State& s) {
const auto &args = s.args();
size_t argc = args.size();
if (argc == 1) {
bool ok = true;
int nIndex = 0;
ok = seval_to_int32(args[0], &nIndex);
SE_PRECONDITION2(ok, false, "Error processing arguments");
std::string value;
localStorageGetKey(nIndex, &value);
s.rval().setString(value);
return true;
}
SE_REPORT_ERROR("Invalid number of arguments");
return false;
}
SE_BIND_FUNC(JSB_localStorageKey)
static bool JSB_localStorage_getLength(se::State& s)
{
const auto& args = s.args();
size_t argc = args.size();
if (argc == 0) {
int nLength = 0;
localStorageGetLength(nLength);
s.rval().setInt32(nLength);
return true;
}
SE_REPORT_ERROR("Invalid number of arguments");
return false;
}
SE_BIND_PROP_GET(JSB_localStorage_getLength);
static bool register_sys_localStorage(se::Object* obj)
{
se::Value sys;
if (!obj->getProperty("sys", &sys))
{
se::HandleObject sysObj(se::Object::createPlainObject());
obj->setProperty("sys", se::Value(sysObj));
sys.setObject(sysObj);
}
se::HandleObject localStorageObj(se::Object::createPlainObject());
sys.toObject()->setProperty("localStorage", se::Value(localStorageObj));
localStorageObj->defineFunction("getItem", _SE(JSB_localStorageGetItem));
localStorageObj->defineFunction("removeItem", _SE(JSB_localStorageRemoveItem));
localStorageObj->defineFunction("setItem", _SE(JSB_localStorageSetItem));
localStorageObj->defineFunction("clear", _SE(JSB_localStorageClear));
localStorageObj->defineFunction("key", _SE(JSB_localStorageKey));
localStorageObj->defineProperty("length", _SE(JSB_localStorage_getLength), nullptr);
std::string strFilePath = cocos2d::FileUtils::getInstance()->getWritablePath();
strFilePath += "/jsb.sqlite";
localStorageInit(strFilePath);
se::ScriptEngine::getInstance()->addBeforeCleanupHook([](){
localStorageFree();
});
se::ScriptEngine::getInstance()->clearException();
return true;
}
#define BIND_PROP_WITH_TYPE__CONV_FUNC__RETURN(cls, property, type, convertFunc, returnFunc) \
static bool js_##cls_set_##property(se::State& s) \
{ \
cocos2d::cls* cobj = (cocos2d::cls*)s.nativeThisObject(); \
SE_PRECONDITION2(cobj, false, "js_#cls_set_#property : Invalid Native Object"); \
const auto& args = s.args(); \
size_t argc = args.size(); \
bool ok = true; \
if (argc == 1) { \
type arg0; \
ok &= convertFunc(args[0], &arg0); \
SE_PRECONDITION2(ok, false, "js_#cls_set_#property : Error processing arguments"); \
cobj->set_##property(arg0); \
return true; \
} \
SE_REPORT_ERROR("wrong number of arguments: %d, was expecting %d", (int)argc, 1); \
return false; \
} \
SE_BIND_PROP_SET(js_##cls_set_##property) \
\
static bool js_##cls_get_##property(se::State& s) \
{ \
cocos2d::cls* cobj = (cocos2d::cls*)s.nativeThisObject(); \
SE_PRECONDITION2(cobj, false, "js_#cls_get_#property : Invalid Native Object"); \
s.rval().returnFunc(cobj->_##property); \
return true; \
} \
SE_BIND_PROP_GET(js_##cls_get_##property)
#define _SE_DEFINE_PROP(cls, property) \
__jsb_cocos2d_##cls##_proto->defineProperty(#property, _SE(js_##cls_get_##property), _SE(js_##cls_set_##property));
//IDEA: move to auto bindings.
static bool js_se_setExceptionCallback(se::State &s) {
auto &args = s.args();
if (args.size() != 1 || !args[0].isObject() || !args[0].toObject()->isFunction()) {
SE_REPORT_ERROR("expect 1 arguments of Function type, %d provided", (int)args.size());
return false;
}
se::Object *objFunc = args[0].toObject();
// se::Value::reset will invoke decRef() while destroying s.args()
// increase ref here
objFunc->incRef();
if (s.thisObject()) {
s.thisObject()->attachObject(objFunc); // prevent GC
} else {
//prevent GC in C++ & JS
objFunc->root();
}
se::ScriptEngine::getInstance()->setJSExceptionCallback([objFunc](const char *location, const char *message, const char *stack) {
se::ValueArray jsArgs;
jsArgs.resize(3);
jsArgs[0] = se::Value(location);
jsArgs[1] = se::Value(message);
jsArgs[2] = se::Value(stack);
objFunc->call(jsArgs, nullptr);
});
return true;
}
SE_BIND_FUNC(js_se_setExceptionCallback)
#define DESCRIPT_FIELD(kls, field, field_type) do {\
ss << "\"" << #field << "\": " << "{" ; \
ss << "\"type\": \"" << field_type << "\"," ; \
ss << "\"offset\": " << offsetof(kls, field) << ","; \
ss << "\"size\": " << sizeof(((kls*)nullptr)->field); \
ss << "}";} while(false)
static bool register_se_setExceptionCallback(se::Object *obj)
{
se::Value jsb;
if (!obj->getProperty("jsb", &jsb)) {
jsb.setObject(se::Object::createPlainObject());
obj->setProperty("jsb", jsb);
}
auto *jsbObj = jsb.toObject();
jsbObj->defineFunction("onError", _SE(js_se_setExceptionCallback));
return true;
}
bool register_all_cocos2dx_manual(se::Object* obj)
{
register_sys_localStorage(obj);
register_se_setExceptionCallback(obj);
return true;
}