require("luaScript.Tools.EvalServerScript");
require("luaScript.Tools.List")
require("luaScript.Tools.ConfigConverter");
bit32 = bit32 or require("bit")
-- 异或
function getNumXor(num1, num2)
local ret=bit32.bxor(num1,num2);
return ret;
end
--或
function getNumOr(num1,num2)
local ret=bit32.bor(num1,num2);
return ret;
end
--与
function getNumBand(num1,num2)
local ret=bit32.band(num1,num2);
return ret;
end
--取反
function getNumNot(num1,num2)
local ret=bit32.bnot(num1,num2);
return ret;
end
-- 格式化时间函数, 把以秒为单位的数字转换成
-- {day = num, hours = num, min = num, second = num的形式}
function formatTime(second)
if second < 0 then
return { day = 0; hours = 0; min = 0; second = 0;};
end;
local t = {};
t.day = math.floor(second / 86400);
second = second % 86400;
t.hours = math.floor(second / 3600);
second = second % 3600;
t.min = math.floor(second / 60);
t.second = second % 60;
return t;
end
--返回的时间表格式化一下
function formatTime2(second)
local t = formatTime(second);
t.hours = string.format("%02d",t.hours);
t.min = string.format("%02d",t.min);
t.second = string.format("%02d",t.second);
return t;
end
-- 格式化时间成字符串
-- 如果是1秒则返回是01
-- 返回的是xx:xx:xx:xx:xx
function formatTimeToStr(second)
local data = formatTime(second)
if data.day > 0 then
return string.format("%.2d天%.2d:%.2d:%.2d", data.day, data.hours, data.min, data.second)
elseif data.hours > 0 then
return string.format("%.2d:%.2d:%.2d", data.hours, data.min, data.second)
else
return string.format("%.2d:%.2d", data.min, data.second)
end
end
-- 格式化时间成字符串,排行榜格式
function formatTimeToRankStr(second)
local data = formatTime(second)
if data.day > 0 then
return string.format(LN.SEASON_TIME_DAY_HOUR, data.day, data.hours)
elseif data.hours > 0 then
return string.format(LN.SEASON_TIME_HOUR, data.hours)
elseif data.min > 0 then
return string.format(LN.SEASON_TIME_MINUTE, data.min)
else
return string.format(LN.SEASON_TIME_SECOND, data.second)
end
end
-- 获取今天的日期,返回的结果格式是"2017-12-23"
function getTodayString()
local t = os.time()
local d = os.date('*t', t)
local str = string.format("%04d-%02d-%02d", d.year, d.month, d.day);
return str;
end
-- AES 128/ECB/PKCS5Padding加密
function AES_encode(postData, aesKey)
if postData == nil or aesKey == nil then
return ""
end
local jsonData = json.encode(postData);
--print("加密前的数据", table.tostring(jsonData))
-- 使用aes加密
local aesData = aes.encode(aesKey, jsonData)
local base64Data = base64.encode(aesData)
--print("加密后的数据", base64Data)
return base64Data
end
-- AES 128/ECB/PKCS5Padding解密
function AES_decode(data, aesKey)
if data == nil or aesKey == nil then
return ""
end
--print("解密前的原始数据", data)
local jsonData = json.decode(aes.decode(aesKey, base64.decode(data)));
--print("解密后的jsonData", table.tostring(jsonData))
return jsonData
end
-- 把123#123格式转换成ccp(123,123)
function toPosition(str)
local numberArray = toNumberArray("#")(str)
if #numberArray ~= 2 then
return cc.p(0,0)
else
return cc.p(numberArray[1] , numberArray[2]);
end
end
-- 传入一个相机和屏幕的像素位置,获取xz平面的一个世界位置
function convertScreenToWorldPos(Camera, ScreenX, ScreenY)
local floorPlane = cc.Plane:new(cc.vec3(0,1,0) , 0);
-- 计算出mainlayer的世界位置
local screenSize = cc.Director:getInstance():getWinSizeInPixels();
local ray = Camera:pickRay(ScreenX / screenSize.width , ScreenY / screenSize.height);
local distance = ray:intersectsPlane(floorPlane);
if distance >= 0 then
return ray:getPoint(distance);
end
return ray:getPoint(0);
end
-- 根据一个世界位置和一个相机计算投影后的位置
function projectPosByWorldPos(camera, worldPos)
local screenSize = cc.Director:getInstance():getWinSizeInPixels()
-- 获取对应的屏幕位置
local clientPos = camera:project(cc.Rectangle:new(screenSize.width, screenSize.height), worldPos);
return cc.p(clientPos.x, screenSize.height - clientPos.y);
end
-- 创建顺序播放的动画序列
function createActionArray(...)
local arg = {...}
if #arg == 1 then
local v = arg[1];
if type(v) == "function" then
return cc.CallFunc:create(v);
else
return v;
end
else
local action = nil;
local actionArray = {};
for i,v in ipairs(arg) do
if type(v) == "function" then
table.insert(actionArray , cc.CallFunc:create(v));
else
table.insert(actionArray , v);
end
end
local action = cc.Sequence:create(actionArray);
return action;
end
end
-- 创建同时播放的动画序列
function createSpawnActions(...)
local arg = {...}
if #arg == 1 then
local v = arg[1];
if type(v) == "function" then
return cc.CallFunc:create(v);
else
return v;
end
else
local action = nil;
local actionArray = {};
for i,v in ipairs(arg) do
if type(v) == "function" then
table.insert(actionArray , cc.CallFunc:create(v));
else
table.insert(actionArray , v);
end
end
local action = cc.Spawn:create(actionArray);
return action;
end
end
-- 创建动态时间动画序列
function createDynamicTimeActionArray(...)
local arg = {...}
if #arg == 1 then
local v = arg[1];
if type(v) == "function" then
return cc.CallFunc:create(v);
else
return v;
end
else
local action = nil;
local actionArray = {};
for i,v in ipairs(arg) do
if type(v) == "function" then
table.insert(actionArray , cc.CallFunc:create(v));
else
table.insert(actionArray , v);
end
end
local action = cc.DynamicTimeSequence:create(actionArray);
return action;
end
end
-- 尚未实现的弹出提示
function onImplementClick()
showTooltip(RT("not implement"));
end
EaseType =
{
[1] = function(action , param)return action end,
[2] = function(action , param)return cc.EaseRateAction:create(action , param) end,
[3] = function(action , param)return cc.EaseIn:create(action , param) end,
[4] = function(action , param)return cc.EaseOut:create(action , param) end,
[5] = function(action , param)return cc.EaseInOut:create(action , param) end,
[6] = function(action , param)return cc.EaseExponentialIn:create(action) end,
[7] = function(action , param)return cc.EaseExponentialOut:create(action) end,
[8] = function(action , param)return cc.EaseExponentialInOut:create(action) end,
[9] = function(action , param)return cc.EaseSineIn:create(action) end,
[10] = function(action , param)return cc.EaseSineOut:create(action) end,
[11] = function(action , param)return cc.EaseSineInOut:create(action) end,
[12] = function(action , param)return cc.EaseElastic:create(action , param) end,
[13] = function(action , param)return cc.EaseElasticIn:create(action , param) end,
[14] = function(action , param)return cc.EaseElasticOut:create(action , param) end,
[15] = function(action , param)return cc.EaseElasticInOut:create(action , param) end,
[16] = function(action , param)return cc.EaseBounce:create(action) end,
[17] = function(action , param)return cc.EaseBounceIn:create(action) end,
[18] = function(action , param)return cc.EaseBounceOut:create(action) end,
[19] = function(action , param)return cc.EaseBounceInOut:create(action) end,
[20] = function(action , param)return cc.EaseBackIn:create(action) end,
[21] = function(action , param)return cc.EaseBackOut:create(action) end,
[22] = function(action , param)return cc.EaseBackInOut:create(action) end,
}
--[[
创建节点的淡入淡出效果
--]]
function createEaseAction(easeType , param , action)
local easeFunction = EaseType[easeType];
if easeFunction then
return easeFunction(action , param);
else
return action;
end
end
-- 创建震动Action
-- @rate 频率 每秒多少次
-- @range 振动幅度 {x=10, y=0} 左右振动10像素,上下振动0像素
-- @times 播放次数,-1表示无限
function createShakeAction(rate , range , times)
-- 每次所需时间
local oneSeconds = 1 / rate / 4;
local oneShakeAction = createActionArray(cc.EaseSineOut:create(cc.MoveBy:create(oneSeconds , cc.p(-range.width / 2 , -range.height / 2)))
, cc.EaseSineInOut:create(cc.MoveBy:create(oneSeconds * 2 , cc.p(range.width , range.height)))
, cc.EaseSineIn:create(cc.MoveBy:create(oneSeconds , cc.p(-range.width / 2 , -range.height / 2)))
)
if times == -1 then
return cc.RepeatForever:create(oneShakeAction);
else
return cc.Repeat:create(oneShakeAction , times);
end
end
-- 创建旋转Action
-- @roundPerSecond 每秒转动多少圈
-- @rounds 需要旋转多少圈,-1则无限
-- @reverse 是否反方向旋转
function createRotationAction(roundPerSecond , rounds , reverse)
local angle;
if reverse then
angle = -360;
else
angle = 360;
end
local action = cc.RotateBy:create(1 / roundPerSecond , angle);
if rounds == -1 then
return cc.RepeatForever:create(action);
else
return cc.Repeat:create(action , rounds);
end
end
-- 创建旋转Action
-- @angle 旋转多少度
-- @speed 每秒转动多少度
function createRotationReverseAction(angle , speed , easeType , easeParam)
local oneRoundTime = math.abs(angle) / speed;
return createEaseAction(easeType , easeParam , createActionArray(cc.RotateBy:create(oneRoundTime , angle) , cc.RotateBy:create(oneRoundTime , -angle)));
end
-- 创建缩放Action
-- @scale 放大到多少
-- @seconds 动画时长
function createScaleReverseAction(scale , seconds , easeType , easeParam)
return createEaseAction(easeType , easeParam , createActionArray(cc.ScaleTo:create(seconds / 2 , scale) , cc.ScaleTo:create(seconds / 2 , 1)));
end
-- 在下一帧执行一次函数func
function runInNextFrame(func , ...)
local arg = {...}
local function exec()
func(unpack(arg));
end
cc.Director:getInstance():getScheduler():performFunctionInCocosThread(exec)
end
-- 延迟delaySeconds这么多秒后执行
function runDelay(delaySeconds, func , ...)
local id
local arg = {...}
local function unschedule()
if id then
cc.Director:getInstance():getScheduler():unscheduleScriptEntry(id);
id = nil;
end
end
local function exec()
if id then
cc.Director:getInstance():getScheduler():unscheduleScriptEntry(id);
id = nil;
end
func(unpack(arg));
end
id = cc.Director:getInstance():getScheduler():scheduleScriptFunc(exec, delaySeconds, false)
return unschedule;
end
-- 在下一帧延迟多少秒后执行
function runDelayInNextFrame(delaySeconds, func)
local function nextFrameFunc()
runDelay(delaySeconds, func)
end
runInNextFrame(nextFrameFunc)
end
-- 使当前页面在屏幕居中
function centerWindow(ui)
local size = ui:getContentSize();
local sizeScreen = cc.Director:getInstance():getWinSize();
ui:setPosition(ui.Parent:convertToNodeSpace(ccp((sizeScreen.width - size.width) / 2 , (sizeScreen.height - size.height) / 2)));
end
-- 把字符串替换成replaceTable中的词义
function replaceStringByTable(str , replaceTable)
local newString = str;
for i , v in pairs(replaceTable) do
if type(v) == "string" or type(v) == "number" then
local newV = string.gsub(v , "%%" , "%%%%");
newString = string.gsub(newString , "%[" .. i .. "%]" , newV);
end
end
return newString;
end
-- 创建一个下划线按钮
-- @title 名字
-- @fontSize 字体大小
-- @color 字体颜色
-- @onClick 点击回调的函数
function createLabelButtonHtmlText(title, fontSize, color, onClick)
if not title then
return "";
end
local function createLuaControl()
local label = cc.Label:createWithTTF(title, "res/default/msyh.ttc" , fontSize);
local size = label:getContentSize();
local layer = cc.Layer:create();
layer:setContentSize(label:getContentSize());
local ui = loadUI("res/ui/ui_tongyong/tongyong_xiahuaxian.ui")
ui.Items.HtmlCtrl_wenzi:setText(title);
ui.Items.HtmlCtrl_wenzi:setColor(color);
ui.Items.Layout_1:setTouchEnabled(true);
ui.Items.Layout_1:registerClick(onClick);
local lineSize = ui.Items.Layout_xian:getSize()
ui.Items.Layout_xian:setSize(cc.size(size.width, lineSize.height))
ui.Items.Layout_xian:setBackGroundColor(color)
layer:addChild(ui)
return layer
end
return "";
end
-- str 格式这样 r_g_b_a 255_232_139_255
function stringToColorWithSeparate(str)
local colorStr = string.split(str, "_");
if(#colorStr==3)then
local color = cc.c3b(tonumber(colorStr[1]),tonumber(colorStr[2]),tonumber(colorStr[3]));
return color;
elseif(#colorStr==4)then
local color = cc.c4b(tonumber(colorStr[1]),tonumber(colorStr[2]),tonumber(colorStr[3]),tonumber(colorStr[3]));
return color;
end
end
function createLabelButtonHtmlText2(title, color, onClick)
if not title then
return "";
end
local function createLuaControl()
local label = cc.HtmlCtrl:create()
label:setAutoSize(true);
label:setText(title);
local size = label:getContentSize();
local layer = cc.Layer:create();
layer:setContentSize(label:getContentSize());
local ui = loadUI("res/ui/ui_tongyong/tongyong_xiahuaxian.ui")
ui.Items.HtmlCtrl_wenzi:setText(title);
ui.Items.Layout_1:setTouchEnabled(true);
ui.Items.Layout_1:registerClick(onClick);
local lineSize = ui.Items.Layout_xian:getSize()
ui.Items.Layout_xian:setSize(cc.size(size.width, lineSize.height))
ui.Items.Layout_xian:setBackGroundColor(color)
layer:addChild(ui)
return layer
end
return "";
end
-- 显示退出确认对话框
function showExitDialog(text)
local function onOk(id)
cc.Director:getInstance():endToLua();
end
local function onCancel()
end
showConfirmDialog(text, onOk, onCancel)
end
-- 重启游戏
function restartGame()
cc.Application:getInstance():restart();
end
-- 显示重启确认对话框
function showRestartDialog(text)
local function onOk()
restartGame();
end
local function onCancel()
end
showConfirmDialog(text, onOk, onCancel)
end
local XmlFilter =
{
["<"] = "<";
[">"] = ">";
["&"] = "&";
["'"] = "'";
["\""] = """;
}
local function replaceIt(c)
return XmlFilter[c] or c;
end
-- 把XML转义符全部替换
function replaceXmlByFilter(str)
return string.gsub(str , "[%&%>%<%'%\"]" , replaceIt);
end
--[[
-- 获取首个屏蔽字出现的位置和结束位置
-- 没有屏蔽字出现则返回nil, nil;
function findMaskWord(str)
local wordList = Config.MaskWord;
local startPos;
local endPos;
for k, v in pairs(wordList) do
startPos, endPos = string.find(str, v.maskWord);
if startPos or endPos then
print(v.maskWord);
return startPos, endPos;
end
end
return nil, nil;
end
]]
-- 把一个utf8的字符串转换成utf32的table数组
function Utf8To32(utf8str)
assert(type(utf8str) == "string")
local res, seq, val = {}, 0, nil
for i = 1, #utf8str do
local c = string.byte(utf8str, i)
if seq == 0 then
table.insert(res, val)
seq = c < 0x80 and 1 or c < 0xE0 and 2 or c < 0xF0 and 3 or
c < 0xF8 and 4 or --c < 0xFC and 5 or c < 0xFE and 6 or
error("invalid UTF-8 character sequence")
val = bit32.band(c, 2^(8-seq) - 1)
else
val = bit32.bor(bit32.lshift(val, 6), bit32.band(c, 0x3F))
end
seq = seq - 1
end
table.insert(res, val)
return res
end
function Utf8Table(utf8str)
assert(type(utf8str) == "string")
local res = {}
for i = 1, #utf8str do
local c = string.byte(utf8str, i)
table.insert(res, c)
end
table.insert(res, val)
return res
end
local char = string.char
local function tail(n, k)
local u, r=''
for i=1,k do
n,r = math.floor(n/0x40), n%0x40
u = char(r+0x80) .. u
end
return u, n
end
-- 把一个utf32字符数字,转换成utf8字符串
function Utf32To8(a)
local n = a;
local r;
local u;
if n<0x80 then -- 1 byte
return char(n)
elseif n<0x800 then -- 2 byte
u, n = tail(n, 1)
return char(n+0xc0) .. u
elseif n<0x10000 then -- 3 byte
u, n = tail(n, 2)
return char(n+0xe0) .. u
elseif n<0x200000 then -- 4 byte
u, n = tail(n, 3)
return char(n+0xf0) .. u
elseif n<0x4000000 then -- 5 byte
u, n = tail(n, 4)
return char(n+0xf8) .. u
else -- 6 byte
u, n = tail(n, 5)
return char(n+0xfc) .. u
end
end
MaskCodeType =
{
NAME = 1;
CHAT = 2;
}
local emojiTable = require("luaScript.Tools.Emoji");
-- 保存所有正则表达式
local g_batchRegex = {};
-- 动态构造正则表达式批量处理
-- maskCode 屏蔽范围:1表示命名2表示聊天3表示聊天和命名
function getBatchRegex(maskCode)
maskCode = maskCode or 0xffffffff;
-- 构造正则表达式批量处理
local batchRegex = g_batchRegex[maskCode];
if batchRegex == nil then
batchRegex = cc.BatchRegex:new();
g_batchRegex[maskCode] = batchRegex;
if maskCode == 3 or maskCode == 2 then
for i , v in ipairs(string.split(LN.MASK_PATTERNS , "\n")) do
if v ~= "" then
batchRegex:add(v);
end
end
end
-- 名字
if maskCode == 3 or maskCode == 1 then
for i , v in ipairs(string.split(LN.MASK_PATTERNS_NAME , "\n")) do
if v ~= "" then
batchRegex:add(v);
end
end
end
end
return batchRegex;
end
-- 检测字符串里是否有屏蔽字
-- 有屏蔽字返回false, 没有返回true
function checkMaskWord(str, maskCode)
local regex = getBatchRegex(maskCode);
local result = regex:search(str);
if #result > 0 then
print('在字符串 "' .. str .. '" 发现屏蔽字 ' .. result[1]);
return false , result[1];
end
-- 表情也屏蔽
local names32 = Utf8To32(str);
local namesRet = "";
for i , v in ipairs(names32) do
local emoji = emojiTable[v];
if emoji then
if type(emoji) == "table" then
local val = names32[i + 1];
if val then
if emoji[val] then
return false , "表情";
end
end
else
return false , "表情";
end
end
end
return true;
end
-- 替换字符串里可能有的屏蔽字, 效率低下, 求改成c++版本
-- @replaceChar 屏蔽字替换成的字符, 默认为"*";
function replaceMaskWord(str, replaceChar, maskCode)
require("luaScript.Tools.Utf16");
replaceChar = replaceChar or "*";
print("replaceChar" , replaceChar);
local regex = getBatchRegex(maskCode);
print("regex" , regex);
return regex:replace(str , replaceChar);
end
local XmlFilter =
{
[60] = "<";
[62] = ">";
[38] = "&";
[39] = "'";
[34] = """;
}
-- 表情库
function createEmojiHtml(emojiValue , value2)
local emoji = emojiTable[emojiValue];
if emoji then
if type(emoji) == "table" then
if value2 then
local emoji = emoji[value2];
if emoji then
return "
";
end
end
else
return "
";
end
end
return XmlFilter[emojiValue] or Utf32To8(emojiValue);
end
-- 把聊天中的表情文字替换掉
function replaceChatEmoji(str)
local utf32 = Utf8To32(str);
local text = "";
for i , v in ipairs(utf32) do
text = text .. createEmojiHtml(v , utf32[i + 1]);
end
return text;
end
-- 在waitView关闭后执行
function runInWaitViewEnd(func , ...)
if g_WaitViewInstance then
local arg = {...};
local function onCloseWaitView()
game:unregEvent("onCloseWaitView");
func(unpack(arg));
end
game:regEvent("onCloseWaitView" , onCloseWaitView);
else
func(...);
end
end
-- 显示平台相关的等待窗口
function showPlatformWaitView()
local platformPlugin = PluginManager:getInstance():loadPlugin("AnalyticsPlatform");
if platformPlugin then
platformPlugin:call("showWaitView");
end
end
-- 关闭平台相关的等待窗口
function closePlatformWaitView()
local platformPlugin = PluginManager:getInstance():loadPlugin("AnalyticsPlatform");
if platformPlugin then
platformPlugin:call("closeWaitView");
end
end
-- 显示滚动公告
function showFloatTooltip(msg)
local homeView = cc.Director:getInstance():getRunningScene();
local html = cc.HtmlCtrl:create('' .. replaceXmlByFilter(msg) .. '');
if homeView.mFloatBar == nil then
homeView.mFloatBar = cc.LayerColor:create(cc.c4b(0,0,0,76));
homeView:addChild(homeView.mFloatBar);
end
local winSize = cc.Director:getInstance():getWinSize();
homeView.mFloatBar:removeAllChildren();
homeView.mFloatBar:addChild(html);
homeView.mFloatBar:setContentSize(cc.size(winSize.width , html:getHeight()));
homeView.mFloatBar:setPosition(cc.p(0 , winSize.height - html:getContentSize().height));
html:setAnchorPoint(cc.p(0,0));
html:setPosition(cc.p(1280 , (homeView.mFloatBar:getContentSize().height - html:getContentSize().height) / 2));
local function onEnd()
homeView.mFloatBar:removeFromParent();
homeView.mFloatBar = nil;
end
print("width " , html:getContentSize().width , html:getContentSize().height , winSize.width , html:getWidth() , html:getHeight());
-- 多少像素每秒
local speed = 30;
html:runActions(cc.MoveTo:create(html:getContentSize().width / speed , cc.p( - html:getContentSize().width , 0)) , onEnd);
end
local function sortFunc(a,b)
local numA = tonumber(a)
local numB = tonumber(b)
if numA ~= nil and numB ~= nil then
return numA < numB
else
return a < b
end
end
-- 根据Key排序 :从小到大
function pairsByKeys (t)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, sortFunc)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
local function sortFuncEx(a,b)
local numA = tonumber(a)
local numB = tonumber(b)
if numA ~= nil and numB ~= nil then
return numA > numB
else
return a > b
end
end
-- 根据Key排序(从大到小)
function pairsByKeysEx (t)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a, sortFuncEx)
local i = 0 -- iterator variable
local iter = function () -- iterator function
i = i + 1
if a[i] == nil then
return nil
else
return a[i], t[a[i]]
end
end
return iter
end
function getNetTimeOutNum()
if g_netTimeOut then
return g_netTimeOut
else
return 10;
end
end
function sortListByFunc(list, sortFunc)
local a = {}
for _, v in pairs(list) do table.insert(a, v) end
if not sortFunc then return; end
table.sort(a, sortFunc)
return a;
end
local stQuery =
{
"1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"
, "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O"
, "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", [0] = "0"
};
-- 10进制转62进制, 注意数值太大会导致溢出
function dec2ST(decNum)
local ret = "";
local num = 0;
if type(decNum) == "string" then
num = tonumber(decNum);
elseif type(decNum) == "number" then
num = decNum;
else
return ret;
end;
local h;
repeat
h = math.floor(num / 62);
local m = num % 62;
ret = ret .. stQuery[m];
num = h;
until h <= 0;
return string.reverse(ret);
end;
-- 16进制转62进制, 注意数值太大会导致溢出
function hex2ST(str)
local ret = "";
local num = 0;
if type(str) == "string" then
local len = string.len(str);
for i = 1, len do
local c = string.sub(str, i, i);
local ascii = string.byte(c);
if ascii >= 48 and ascii <= 57 then
num = num * 16 + ascii - 48;
elseif ascii >= 65 and ascii <= 70 then
num = num * 16 + ascii - 65 + 10;
elseif ascii >= 97 and ascii <= 102 then
num = num * 16 + ascii - 97 + 10;
end
end
else
return ret;
end;
local h;
repeat
h = math.floor(num / 62);
local m = num % 62;
ret = ret .. stQuery[m];
num = h;
until h <= 0;
return string.reverse(ret);
end;
function alignString(str, alignSize, maxSize)
local len = string.len(str);
local alignStr = str;
if maxSize then
if len < maxSize then
for i = 1, maxSize - len do
alignStr = "0" .. alignStr;
end
end;
else
local m = len % alignSize;
if m > 0 then
for i = 1, (alignSize - m) do
alignStr = "0" .. alignStr;
end
end;
end
return alignStr;
end;
-- 16进制转62进制 支持大数, 但只有压缩效果(4位16进制用3位62进制表示), 数值不相等
function hex2STEx(str)
local ret ="";
local len = string.len(str);
local alignStr = str;
local alignSize = 4;
-- 对齐字符串
local m = len % alignSize;
if m > 0 then
for i = 1, (alignSize - m) do
alignStr = "0" .. alignStr;
end
len = len + alignSize - m;
end;
local i = 1;
while i < len do
local s = string.sub(alignStr, i, i + alignSize - 1);
ret = ret .. hex2ST(s);
i = i + alignSize;
end;
return ret;
end
-- 播放UI的从上往下掉落的动画
function fallDownUI(ui)
if not isUIAniEnabled() then
return;
end
local oldPosY = ui:getPositionY();
ui:setPositionY( cc.Director:getInstance():getVisibleSize().height);
ui:runActions(cc.EaseSineInOut:create(cc.MoveTo:create(0.3 , cc.p(ui:getPositionX() , oldPosY - 15)))
, cc.EaseSineInOut:create(cc.MoveBy:create(0.2 , cc.p(0 , 45)))
, cc.EaseSineIn:create(cc.MoveBy:create(0.2 , cc.p(0 , -30)))
);
end
-- 播放UI放大动画
function scaleUI(ui)
if not isUIAniEnabled() then
return;
end
local oldScaleX = ui:getScaleX();
local oldScaleY = ui:getScaleY();
ui:setScaleX(0);
ui:setScaleY(0);
ui:runActions(cc.EaseSineInOut:create(cc.ScaleTo:create(0.2 , oldScaleX + 0.05 , oldScaleY + 0.05))
, cc.EaseSineInOut:create(cc.ScaleTo:create(0.1 , oldScaleX - 0.05 , oldScaleY - 0.05))
, cc.EaseSineIn:create(cc.ScaleTo:create(0.1 , oldScaleX , oldScaleY))
);
end
-- 播放UI的从上往下掉落的动画
function moveDownUI(ui)
if not isUIAniEnabled() then
return;
end
local oldPosY = ui:getPositionY();
ui:setPositionY( cc.Director:getInstance():getVisibleSize().height);
ui:runActions(cc.EaseExponentialOut:create(cc.MoveTo:create(0.5 , cc.p(ui:getPositionX() , oldPosY)))
);
end
-- 播放UI的从下往上掉落的动画
function moveUpUI(ui)
if not isUIAniEnabled() then
return;
end
local oldPosY = ui:getPositionY();
ui:setPositionY(-ui.ContentSize.height);
ui:runActions(cc.EaseExponentialOut:create(cc.MoveTo:create(0.5 , cc.p(ui:getPositionX() , oldPosY)))
);
end
-- 播放UI的从右往左掉落的动画
function moveLeftUI(ui)
if not isUIAniEnabled() then
return;
end
local oldPosX = ui:getPositionX();
ui:setPositionX(cc.Director:getInstance():getVisibleSize().width);
ui:runActions(cc.EaseExponentialOut:create(cc.MoveTo:create(0.5 , cc.p(oldPosX , ui:getPositionY())))
);
end
-- 播放UI的从左往右掉落的动画
function moveRightUI(ui)
if not isUIAniEnabled() then
return;
end
local oldPosX = ui:getPositionX();
ui:setPositionX(- cc.Director:getInstance():getVisibleSize().width);
ui:runActions(cc.EaseExponentialOut:create(cc.MoveTo:create(0.5 , cc.p(oldPosX , ui:getPositionY())))
);
end
-- 播放UI放大动画
function scaleAndMoveUI(ui , sourcePos)
if not isUIAniEnabled() then
return;
end
local oldScaleX = ui:getScaleX();
local oldScaleY = ui:getScaleY();
ui:setScaleX(0);
ui:setScaleY(0);
ui:runActions(cc.EaseExponentialOut:create(cc.ScaleTo:create(0.5 , oldScaleX , oldScaleY))
);
local oldX = ui:getPositionX();
local oldY = ui:getPositionY();
ui:setPosition(sourcePos);
ui:runAction(cc.EaseExponentialOut:create(cc.MoveTo:create(0.5 , cc.p(oldX , oldY))));
end
function beijingDate(formatStr, time)
assert(formatStr and type(formatStr) == "string", "formatStr必须是字符串类型");
time = time or os.time();
local convert2Zone = 8;
local timeZone = tonumber(os.date("%H", 0));
local d = tonumber(os.date("%d", 0));
if d ~= 1 then timeZone = timeZone - 24; end;
if timeZone ~= convert2Zone then
time = time - (timeZone - convert2Zone) * 3600;
end
return os.date(formatStr, time);
end
AutoCallback =
{
cbList = {};
id = nil;
lastIndex = 1;
};
-- 指定每天的某一时刻之前x秒运行一次回调
-- @func 回调函数
-- @hour 小时, 默认0点
-- @min 分, 默认0分
-- @sec 秒, 默认0秒
-- @beforeSec 提前秒数, 可为负数, 达到之后多少秒执行的效果, 默认0秒
-- @thresholdValue 误差阀值, 0为过期不候, 默认为0
-- @return 此回调的句柄, 用于反注册
function AutoCallback:runBeforeTime(func, hour, min, sec, beforeSec, thresholdValue)
assert(func, "回调函数不能为空");
hour = hour or 0;
min = min or 0;
sec = sec or 0;
beforeSec = beforeSec or 0;
thresholdValue = thresholdValue or 0;
local param =
{
func = func;
hour = hour;
min = min;
sec = sec;
thresholdValue = thresholdValue;
beforeSec = beforeSec;
bHasRun = false;
}
local handler = self.lastIndex;
self.cbList[handler] = param;
self.lastIndex = handler + 1;
if not self.id then
self.id = cc.Director:getInstance():getScheduler():scheduleScriptFunc(function() self:update();end
, 1
, false);
end
return handler;
end;
-- 指定每天的某一时刻运行一次回调
-- @func 回调函数
-- @hour 小时, 默认0点
-- @min 分, 默认0分
-- @sec 秒, 默认0秒
-- @thresholdValue 误差阀值, 0为过期不候, 默认为0
-- @return 此回调的句柄, 用于反注册
function AutoCallback:runAtTime(func, hour, min, sec, thresholdValue)
return self:runBeforeTime(func, hour, min, sec, 0, thresholdValue);
end;
function AutoCallback:update()
local bHave = next(self.cbList);
if not bHave then
cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.id);
self.id = nil;
return;
end
local curServerTime = getCurServerTime();
--[[
local year = tonumber(os.date("%Y", curServerTime));
local month = tonumber(os.date("%m", curServerTime));
local day = tonumber(os.date("%d", curServerTime));
]]
local curServerTimeTable = BeijingTime.dateFunc(curServerTime);
local year = curServerTimeTable.year;
local month = curServerTimeTable.month;
local day = curServerTimeTable.day;
for k, v in pairs(self.cbList) do
--local cbTime = os.time({year = year, month = month, day = day, hour = v.hour, min = v.min, sec = v.sec});
local cbTime = BeijingTime.timeFunc({year = year, month = month, day = day, hour = v.hour, min = v.min, sec = v.sec});
cbTime = cbTime - v.beforeSec;
local interval = curServerTime - cbTime;
if v.bHasRun then
if interval < 0 or interval > v.thresholdValue then
v.bHasRun = false;
end
else
if interval >= 0 and interval <= v.thresholdValue then
v.func();
v.bHasRun = true;
end
end;
end
end;
function AutoCallback:removeCB(handler)
assert(handler, "句柄不能为空");
self.cbList[handler] = nil;
end;
function logAppEvent(event)
if plugins.analytics then
plugins.analytics:logEvent(event , {});
end
end
-- 显示内嵌网页
function showWebView(url , width , height , posX , posY)
print("showWebView" ,url , width , height , posX , posY);
local platformPlugin = PluginManager:getInstance():loadPlugin("AnalyticsPlatform");
if platformPlugin then
local visibleSize = cc.Director:getInstance():getVisibleSize();
local frameSize = cc.Director:getInstance():getOpenGLView():getFrameSize();
platformPlugin:call("openWebView" , url , width / visibleSize.width * frameSize.width , height / visibleSize.height * frameSize.height
, posX / visibleSize.width * frameSize.width , posY / visibleSize.height * frameSize.height);
end
end
-- 关闭内嵌网页
function closeWebView()
local platformPlugin = PluginManager:getInstance():loadPlugin("AnalyticsPlatform");
if platformPlugin then
platformPlugin:call("closeWebView");
end
end
-- 在目标窗口的旁边创建一个Tooltip,并返回创建好的tooltip节点
-- targetContainer 目标参考容器节点
-- targetNode 目标参考点的节点
-- tipsText tooltip的文本内容
-- tipsWidth 文本宽度,可选值
function createTooltip(targetContainer , targetNode , tipsText , tipsWidth, dir)
local tips = loadUI("res/ui/ui_tongyong/tips.ui");
-- 定义一个函数给外部用
function tips:setText(text)
tips.Items.HtmlCtrl_1:setText(text);
end
--tips.Items.HtmlCtrl_1:setTextAreaSize(cc.size(tipsWidth or 0 , 0));
tips:setText(tipsText);
-- 强制计算一遍布局,以便让screenLayoutNode里的getContentSize能取到准确的位置
tips:requestDoLayout();
tips:doLayout();
-- targetContainer:addChild(tips)
app.mainScene.showDialogNode:addChild(tips);
-- 关注targetContainer退出的消息(兼容以前的版本)
local function onNodeEvent(node , eventType)
if eventType == cc.NodeEvent.OnExit then
-- 移除悬浮框
if not tolua.isnull(tips) then
tips:removeFromParent()
end
end
end
targetContainer:addNodeEventListener(onNodeEvent)
-- 让他每帧执行布局计算
autoScreenLayoutNode(targetContainer , targetNode , tips, nil, dir);
return tips;
end
-- 在目标窗口的旁边创建一个Tooltip,并返回创建好的tooltip节点
-- targetContainer 目标参考容器节点
-- targetNode 目标参考点的节点
-- tipsText tooltip的文本内容
-- tipsWidth 文本宽度,可选值
function createTooltip2(targetContainer , targetNode , tipsText , tipsWidth)
local tips = loadUI("res/ui/ui_maoxian/mx_guanka_xinxi_texin_tips.ui");
-- 定义一个函数给外部用
function tips:setText(text)
tips.Items.HtmlCtrl_3:setText(text);
end
--tips.Items.HtmlCtrl_1:setTextAreaSize(cc.size(tipsWidth or 0 , 0));
tips:setText(tipsText);
-- 强制计算一遍布局,以便让screenLayoutNode里的getContentSize能取到准确的位置
tips:requestDoLayout();
tips:doLayout();
targetContainer:addChild(tips);
-- 让他每帧执行布局计算
autoScreenLayoutNode(targetContainer , targetNode , tips);
--[[
tips:playClip("fadeIn" ,
function()
tips.FadeInEnd = true;
if tips.DestroyRequest then
tips:playClip("fadeOut"
, function()
tips:removeFromParent();
end
);
end
end
)
local remove = tips.removeFromParent;
function tips:removeFromParent()
if self.FadeInEnd then
self:playClip("fadeOut"
, function()remove(tip);end
);
else
self.DestroyRequest = true;
end
end
--]]
return tips;
end
---- 显示一个特别Tooltip,并自动销毁
function showDiffTooltip(tipsText,autoRemove)
local tips = loadUI("res/ui/ui_tongyong/t_buzu_tishi.ui");
tips.Items.HtmlCtr_miaoshu:setText(tipsText);
if(autoRemove)then
local winSize = cc.Director:getInstance():getWinSize();
tips:setTranslation(winSize.width / 2 , winSize.height /3* 2 , 0);
app.mainScene:addChild(tips , UIZOrder.TipsOrder);
local t = app.config.GlobalClient.TASK_TOOL_TIPS_TIME.number/1000;
local delayRemove = function()
tips:runActions(cc.DelayTime:create(t) , function()
tips:playClip("danchu",function()
tips:removeFromParent();
end)
end);
end
tips:playClip("danru",delayRemove);
else
app:showUI(tips,transparency or 204);
tips:playClip("danru");
end
return tips;
end
function showTooltipWithHtmlText(htmlText)
local tips = loadUI("res/ui/ui_tongyong/texttips.ui");
tips.Items.Text:setText(htmlText);
local director = cc.Director:getInstance();
app.mainScene:addChild(tips , UIZOrder.TipsOrder);
local winSize = director:getWinSize();
tips:requestDoLayout();
tips:doLayout();
tips.Items.Layout_1:setAutoSize(false);
tips.Items.Layout_1:setUpdateBackgroundWithChildren(false);
local t = 1
local delayRemove = function()
tips.Items.Layout_3:runActions(cc.DelayTime:create(t) , function()
tips.Items.Layout_3:playClip("danchu",function()
tips:removeFromParent();
end)
end);
end
tips.Items.Layout_3:playClip("danru",delayRemove);
return tips;
end
-- 显示一个Tooltip,并自动销毁
function showTooltip(tipsText)
if (not tipsText) or tipsText == "" then
return
end
if app.club_php.clubID and app.club_php.clubID ~= 0 then
if app.club_php:getCestIsOpen(app.club_php.clubID) then
tipsText = string.gsub(tipsText, "玩家", "选手")
tipsText = string.gsub(tipsText, "成员", "选手")
tipsText = string.gsub(tipsText, "亲友圈", "赛事")
tipsText = string.gsub(tipsText, "茶馆", "赛事")
end
end
logD("showTooltip() : " .. tipsText)
--local model = '%s'
local strTips = string.format("%s", tipsText)
showTooltipWithHtmlText(strTips)
end
function showDropTip(tipsText)
app:dropNotice(tipsText)
end
-- 显示对话框
-- btnCallbackOk : 点击确定时的回调
-- btnCallbackCancel : 点击取消时的回调,如果为空,则不显示取消按钮
-- fontSize : 显示内容字体大小
-- imgpath : 替换确定按钮图片路径
-- notice:备注
-- bShowKeFu: 显示联系客服的按钮
function showConfirmDialog(textContent, btnCallbackOk, btnCallbackCancel, fontSize, imgpath, notice, bShowKeFu)
local view;
local ui = loadUI("res/ui/ui_tongyong/ui_querenjiemian.ui");
ui:setAnchorPoint(cc.p(0.5, 0.5));
logD(textContent)
-- 内容
ui.Items.Text_Content:setText(textContent or "");
if fontSize then
ui.Items.Text_Content:setFontSize(fontSize)
end
-- 确认按钮
local function onButtonClickOk()
playBtnEffect()
if btnCallbackOk then
btnCallbackOk();
end
view:removeFromParent();
end
ui.Items.Button_OK:registerClick(onButtonClickOk);
if imgpath then
ui.Items.Button_OK:loadTextureNormal(imgpath)
end
-- 取消按钮
local function onButtonClickCancel()
playBtnEffect()
if btnCallbackCancel then
btnCallbackCancel();
end
view:removeFromParent();
end
if btnCallbackCancel then
ui.Items.Button_Cancel:registerClick(onButtonClickCancel);
else
ui.Items.Button_Cancel:removeFromParent();
end
if notice then
ui.Items.Text_notice:setText(tostring(notice))
else
ui.Items.Text_notice:setVisible(false)
end
if bShowKeFu then
local function onButtonClickKeFu()
playBtnEffect()
local tt =
{
action = "collecturl.getDataByUid";
app_id = getAppId(); --应用id
};
local phpUrl = getGlobalPhpUrl()
httpPost(phpUrl, tt, function(status, response)
if status == "successed" then
local data = json.decode(response)
if data.code == 200 and data.result ~= null then
app.plugin:callUrl(data.result.kefuurl)
end
else
local url = "http://cs.zxtycest.com/addons/kefu?gameid=47"
app.plugin:callUrl(url)
end
end)
end
ui.Items.Button_KeFu:registerClick(onButtonClickKeFu);
else
ui.Items.Button_KeFu:setVisible(false)
end
view = app:showWaitUI(ui, nil, nil, 9999);
return view;
end
-- 显示一个不可关闭的对话框
-- btnCallbackOk : 点击确定时的回调
-- btnCallbackCancel : 点击取消时的回调,如果为空,则不显示取消按钮
-- fontSize : 显示内容字体大小
-- imgpath : 替换确定按钮图片路径
-- notice:备注
-- bShowKeFu: 显示联系客服的按钮
function showConfirmDialogNotClose(textContent, btnCallbackOk, btnCallbackCancel, fontSize, imgpath, notice, bShowKeFu)
local view;
local ui = loadUI("res/ui/ui_tongyong/ui_querenjiemian.ui");
ui:setAnchorPoint(cc.p(0.5, 0.5));
logD(textContent)
-- 内容
ui.Items.Text_Content:setText(textContent or "");
if fontSize then
ui.Items.Text_Content:setFontSize(fontSize)
end
-- 确认按钮
local function onButtonClickOk()
playBtnEffect()
if btnCallbackOk then
btnCallbackOk();
end
end
ui.Items.Button_OK:registerClick(onButtonClickOk);
if imgpath then
ui.Items.Button_OK:loadTextureNormal(imgpath)
end
ui.Items.Button_Cancel:removeFromParent();
if notice then
ui.Items.Text_notice:setText(tostring(notice))
else
ui.Items.Text_notice:setVisible(false)
end
if bShowKeFu then
local function onButtonClickKeFu()
playBtnEffect()
local tt =
{
action = "collecturl.getDataByUid";
app_id = getAppId(); --应用id
};
local phpUrl = getGlobalPhpUrl()
httpPost(phpUrl, tt, function(status, response)
if status == "successed" then
local data = json.decode(response)
if data.code == 200 and data.result ~= null then
app.plugin:callUrl(data.result.kefuurl)
end
else
local url = "http://cs.zxtycest.com/addons/kefu?gameid=47"
app.plugin:callUrl(url)
end
end)
end
ui.Items.Button_KeFu:registerClick(onButtonClickKeFu);
else
ui.Items.Button_KeFu:setVisible(false)
end
view = app:showWaitUI(ui, nil, nil, 9999);
ui:bindEvent(app, "showConfirmDialogNotClose",function ()
view:removeFromParent()
end)
return view;
end
-- 播放UI声音文件
-- soundFile 声音文件名
function playUISound(filePath , streamBuffer)
if app.systemSetting.info.sound then
--print("播放UI声音" , filePath , debug.traceback());
return cc.AudioController:getInstance():playSound(filePath , streamBuffer or false);
end
end
-- 播放一个飞行ce
-- @ceFile 技能文件
-- @targetPoints 飞行技能的源坐标点
-- @effectPoints 飞行技能的目标坐标点
-- @onHit 被击触发函数,默认可以不设置
function playFlyEffect(ceFile, parentNode, targetPoints, effectPoints, onHit, onEndFunc)
--print("播放的技能资源名称:" .. ceFile)
-- 载入技能
local ce = createCombineEffect(ceFile);
if ce then
--创建一个源模型、源点、目标模型、目标点
local params = createDefaultCombineEffectParams();
params.ParentNode = parentNode;
params.CameraNode = app:getMainCameraNode();
params.SourcePos = effectPoints
params.TargetPos = targetPoints
local onStartEventFunc = nil
if onHit then
local hasOnHitEvent = false;
for i , v in pairs(ce:getChildren()) do
if v:getStartEventName() == "OnHit" then
hasOnHitEvent = true;
break;
end
end
if not hasOnHitEvent then
error("技能文件没配置OnHit事件:" , ceFile);
end
-- 绑定技能事件
local function onStartEvent(eventName , params)
-- 播放被击效果
if eventName == "OnHit" then
-- 只触发一次
if onHit then
onHit();
end
end
end
onStartEventFunc = onStartEvent;
end
-- 播放技能
local ceAction = cc.CombineEffectAction:createWithInstance(ce, params, onStartEventFunc, onEndFunc)
parentNode:runAction(ceAction)
return ceAction;
-- 如果没配技能,则直接触发被击
else
if onHit then
onHit();
end
end
end
function playModeCeEffect(ceFile, parentNode, sourceNode, targetPoints, effectPoints, onHit, onEndFunc)
--print("播放的技能资源名称:" .. ceFile)
-- 载入技能
local ce = createCombineEffect(ceFile);
if ce then
--创建一个源模型、源点、目标模型、目标点
local params = createDefaultCombineEffectParams();
params.ParentNode = parentNode;
params.CameraNode = app:getMainCameraNode();
params.SourcePos = effectPoints
params.TargetPos = targetPoints
params.SourceNode = sourceNode;
local onStartEventFunc = nil
if onHit then
local hasOnHitEvent = false;
for i , v in pairs(ce:getChildren()) do
if v:getStartEventName() == "OnHit" then
hasOnHitEvent = true;
break;
end
end
if not hasOnHitEvent then
error("技能文件没配置OnHit事件:" , ceFile);
end
-- 绑定技能事件
local function onStartEvent(eventName , params)
-- 播放被击效果
if eventName == "OnHit" then
-- 只触发一次
if onHit then
onHit();
end
end
end
onStartEventFunc = onStartEvent;
end
-- 播放技能
local ceAction = cc.CombineEffectAction:createWithInstance(ce, params, onStartEventFunc, onEndFunc)
parentNode:runAction(ceAction)
return ceAction;
-- 如果没配技能,则直接触发被击
else
if onHit then
onHit();
end
end
end
-- 回收所有资源
function collectMemory()
print("start collectMemory");
-- 卸载光效池
clearEffectCache();
-- 卸载没有使用的纹理
cc.BundleCache:getInstance():removeUnusedScenes();
cc.MaterialCache:getInstance():removeUnusedMaterials();
cc.AudioCache:getInstance():removeUnusedAudioBuffers();
cc.SpriteFrameCache:getInstance():unloadUnusedSpriteFrames(10);
cc.Director:getInstance():getTextureCache():removeUnusedTextures();
print("lua回收前的内存", collectgarbage("count"))
collectgarbage("collect")
print("lua回收后的内存", collectgarbage("count"))
print("finish collectMemory");
end
-- 是否安卓测试包
function isAndroidTestVersion()
return isAndroidPlatform() and app.config.Setting.LanguageType == 1;
end
-- 自动创建xml文件
function newLocalXmlFile(fileName)
local tempXmlPath = cc.FileUtils:getInstance():getWritablePath() .. fileName .. ".xml";
local file = io.open(tempXmlPath,"rb");
local tempXmlData;
if file then
local data = file:read("*a");
if data then
tempXmlData = xml.eval(data);
end
file:close();
end
if tempXmlData == nil then
tempXmlData = xml.new(fileName);
end
return tempXmlData, tempXmlPath;
end
-- 刪除XML文件
function deleteXmlFile(fileName)
local tempXmlPath = cc.FileUtils:getInstance():getWritablePath() .. fileName .. ".xml";
local removeOver = os.remove(tempXmlPath)
return removeOver
end
local UserConfigFileName = "UserConfig"
local xmlData, xmlPath = newLocalXmlFile(UserConfigFileName);
local XmlFileTable = {}
function initLocalXmlFile(fileName)
if not XmlFileTable[fileName] then
local xmlMsgData, xmlMsgPath = newLocalXmlFile(fileName);
XmlFileTable[fileName] = {};
XmlFileTable[fileName].data = xmlMsgData;
XmlFileTable[fileName].path = xmlMsgPath;
end
end
-- xml 以xml格式保存玩家数据
function saveUserXml(eName, eValue, fileName)
if not fileName then
fileName = UserConfigFileName;
end
if not XmlFileTable[fileName] then
initLocalXmlFile(fileName);
end
local fileData = XmlFileTable[fileName];
fileData.data[eName] = eValue;
xml.save(fileData.data , fileData.path);
end
-- xml 载入玩家xml数据
function loadUserXml(eName, fileName)
if not fileName then
fileName = UserConfigFileName;
end
if not XmlFileTable[fileName] then
initLocalXmlFile(fileName);
end
local fileData = XmlFileTable[fileName];
return fileData.data[eName] or "";
end
function escape(s)
return (string.gsub(s, "([^A-Za-z0-9_])", function(c)
return string.format("%%%02x", string.byte(c))
end))
end
function unescape(s)
return (string.gsub(s, "%%(%x%x)", function(hex)
return string.char(tonumber(hex, 16))
end))
end
local PasswordKey = "dfdsfsdf#*%&^*$^(*&@#^%*(&@#%^sdfdsfdsfwezhangsandfsdf";
function saveUserInfo(key,value)
saveUserXml(tostring(key) , escape(md5.crypt(tostring(value) , PasswordKey)));
end
function loadUserInfo(key)
local value = loadUserXml(tostring(key));
if value ~= "" then
return md5.decrypt(unescape(value) , PasswordKey);
else
return value;
end
end
local function checkUserConfig()
local key = "20190712"
local value = loadUserInfo(key)
if not value or value == "" then
XmlFileTable[UserConfigFileName] = nil
deleteXmlFile(UserConfigFileName)
initLocalXmlFile(UserConfigFileName);
saveUserInfo(key, 1);
end
end
if not EditorMode then
checkUserConfig();
end
-- 是否正在加载场景
LoadingScene = false;
-- 是否在解析xml过程中立即加载资源
function isImmediatelyLoad()
return EditorMode or LoadingScene;
end
function tableToPostUrl(tb)
local postUrl = "";
for k,v in pairs(tb) do
postUrl = postUrl.."&"..k.."="..v;
end
postUrl = string.sub(postUrl,2,-1);
print("post url is :",postUrl);
return postUrl;
end
-- 显示内嵌网页
function showWebView(url , width , height , posX , posY)
print("showWebView" ,url , width , height , posX , posY);
if PluginDevice then
local visibleSize = cc.Director:getInstance():getVisibleSize();
local frameSize = cc.Director:getInstance():getOpenGLView():getFrameSize();
PluginDevice:callVoid("openWebView" , url , width / visibleSize.width * frameSize.width , height / visibleSize.height * frameSize.height
, posX / visibleSize.width * frameSize.width , posY / visibleSize.height * frameSize.height);
end
end
-- 关闭内嵌网页
function closeWebView()
if PluginDevice then
PluginDevice:callVoid("closeWebView");
end
end
-- Node的每帧更新回调
-- stopCondition如果为值则代表最大时间,到达时间就取消定时器
-- stopCondition如果为函数则为停止定时器的回调函数
function scheduleUpdateScriptFunc(targetNode, stopCondition, callback)
if not targetNode then
return
end
local sum = 0
local function onFrameUpdate(t)
sum = sum + t
if type(stopCondition) == "function" then
local result = stopCondition()
if result then
-- 停止定时器
targetNode:unscheduleUpdate()
end
else
if sum >= stopCondition then
-- 停止定时器
targetNode:unscheduleUpdate()
end
end
callback(sum, t)
end
targetNode:scheduleUpdateWithPriorityLua(onFrameUpdate, 0)
end
-- 截取指定节点的字符串,中文算两个、英文算一个
function substr(str, endPos)
local pos = 0;
local size = #str;
local nextIndex = 1;
local len = 0;
for i = 1, size do
if i >= nextIndex then
local curByte = string.byte(str, i)
local byteCount = 1;
if curByte>0 and curByte<=127 then
byteCount = 1
elseif curByte>=192 and curByte<223 then
byteCount = 2
elseif curByte>=224 and curByte<239 then
byteCount = 3
elseif curByte>=240 and curByte<=247 then
byteCount = 4
end
nextIndex = i + byteCount;
if len >= endPos then
break;
end
if byteCount == 1 then
len = len + 1;
else
len = len + 2;
end
pos = pos + byteCount;
end
end
return string.sub(str, 1, pos);
end
-- 获取名字的长度,一个中文算2个长度单位,一个英文字符算一个长度单位
function getStringLen(str)
assert(type(str) == "string")
local len = 0;
local size = #str;
local nextIndex = 1;
for i = 1, size do
if i >= nextIndex then
local curByte = string.byte(str, i)
local byteCount = 1;
if curByte>0 and curByte<=127 then
byteCount = 1
elseif curByte>=192 and curByte<223 then
byteCount = 2
elseif curByte>=224 and curByte<239 then
byteCount = 3
elseif curByte>=240 and curByte<=247 then
byteCount = 4
end
nextIndex = i + byteCount;
if byteCount == 1 then
len = len + 1;
else
len = len + 2;
end
end
end
return len;
end
-- 系统自带的base64编码和解码好像有问题,在某些设备上可能出现缺少最后一个字符的情况
-- 所以自己写一个
function ToBase64(source_str)
local b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
local s64 = ''
local str = source_str
while #str > 0 do
local bytes_num = 0
local buf = 0
for byte_cnt=1,3 do
buf = (buf * 256)
if #str > 0 then
buf = buf + string.byte(str, 1, 1)
str = string.sub(str, 2)
bytes_num = bytes_num + 1
end
end
for group_cnt=1,(bytes_num+1) do
b64char = math.fmod(math.floor(buf/262144), 64) + 1
s64 = s64 .. string.sub(b64chars, b64char, b64char)
buf = buf * 64
end
for fill_cnt=1,(3-bytes_num) do
s64 = s64 .. '='
end
end
return s64
end
function FromBase64(str64)
local b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
local temp={}
for i=1,64 do
temp[string.sub(b64chars,i,i)] = i
end
temp['=']=0
local str=""
for i=1,#str64,4 do
if i>#str64 then
break
end
local data = 0
local str_count=0
for j=0,3 do
local str1=string.sub(str64,i+j,i+j)
if not temp[str1] then
return
end
if temp[str1] < 1 then
data = data * 64
else
data = data * 64 + temp[str1]-1
str_count = str_count + 1
end
end
for j=16,0,-8 do
if str_count > 0 then
str=str..string.char(math.floor(data/math.pow(2,j)))
data=math.mod(data,math.pow(2,j))
str_count = str_count - 1
end
end
end
return str
end
local clubXmlData, clubXmlPath = newLocalXmlFile("ClubConfig");
local XmlFileClubTable = {
["ClubConfig"] = { data = clubXmlData, path = clubXmlPath },
}
-- xml 以xml格式保存茶馆数据
function saveClubXml(eName, eValue, fileName)
if not fileName then
fileName = "ClubConfig";
else
initLocalXmlFile(fileName);
end
local fileData = XmlFileClubTable[fileName];
fileData.data[eName] = eValue;
xml.save(fileData.data , fileData.path);
end
-- xml 载入茶馆xml数据
function loadClubXml(eName, fileName)
if not fileName then
fileName = "ClubConfig";
else
initLocalXmlFile(fileName);
end
local fileData = XmlFileClubTable[fileName];
return fileData.data[eName] or "";
end
local clubPasswordKey = "dfdsfsdf#*%&^*$^(*&@#^%*(&@#%^sdfdsfdsfwefsdfsdf";
function saveClubInfo(key,value)
saveClubXml(tostring(key) , escape(md5.crypt(tostring(value) , clubPasswordKey)));
end
function loadClubInfo(key)
local value = loadClubXml(tostring(key));
if value ~= "" then
return md5.decrypt(unescape(value) , clubPasswordKey);
else
return value;
end
end