2025-05-24 14:29:14 +08:00
|
|
|
|
local breakSocketHandle, debugXpCall = require("LuaDebugjit")("localhost", 7003)
|
|
|
|
|
|
local timer = Timer.New(function()
|
|
|
|
|
|
breakSocketHandle()
|
|
|
|
|
|
end, 1, -1, false)
|
|
|
|
|
|
timer:Start();
|
|
|
|
|
|
|
|
|
|
|
|
require "Core.init"
|
|
|
|
|
|
json = require 'cjson'
|
|
|
|
|
|
require 'FairyGUI'
|
|
|
|
|
|
require 'Game.ControllerManager'
|
|
|
|
|
|
require 'Game.ViewManager'
|
|
|
|
|
|
require 'Game.DataManager'
|
|
|
|
|
|
require "Game.ExtendManager"
|
|
|
|
|
|
require "Game.ExtendHotupdate"
|
|
|
|
|
|
require "TableData"
|
|
|
|
|
|
|
|
|
|
|
|
MsgParser = require("MsgParser")
|
|
|
|
|
|
|
|
|
|
|
|
Utils = Game.Utils
|
|
|
|
|
|
PlayerPrefs = UnityEngine.PlayerPrefs
|
|
|
|
|
|
RuntimePlatform = UnityEngine.RuntimePlatform
|
|
|
|
|
|
Application = UnityEngine.Application
|
|
|
|
|
|
Screen = UnityEngine.Screen
|
|
|
|
|
|
ResourcesManager = taurus.unity.ResourcesManager
|
|
|
|
|
|
-- require 'tolua.reflection'
|
|
|
|
|
|
-- tolua.loadassembly('Assembly-CSharp')
|
|
|
|
|
|
-- local BindingFlags = require 'System.Reflection.BindingFlags'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local _game_info
|
|
|
|
|
|
local panel = nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
oldGameVersion = 2 --1 原始 2 老游戏新加功能
|
|
|
|
|
|
|
|
|
|
|
|
--主入口函数。从这里开始lua逻辑
|
|
|
|
|
|
function Main()
|
2025-11-15 00:29:21 +08:00
|
|
|
|
if true then
|
|
|
|
|
|
local suc = pcall(function()
|
|
|
|
|
|
local path = Application.streamingAssetsPath .. "/../../.."
|
|
|
|
|
|
package.cpath = package.cpath .. ";" .. path .. "/?.dll"
|
|
|
|
|
|
local dbg = require("emmy_core")
|
|
|
|
|
|
dbg.tcpConnect('localhost', 9966)
|
|
|
|
|
|
end)
|
|
|
|
|
|
if suc then
|
|
|
|
|
|
print("=============================调试连接成功!===========================")
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
2025-09-28 18:12:30 +08:00
|
|
|
|
|
2025-08-30 20:29:56 +08:00
|
|
|
|
-- PlayerPrefs.DeleteKey('session_id')
|
2025-05-24 14:29:14 +08:00
|
|
|
|
Application.targetFrameRate = 60
|
|
|
|
|
|
FairyGUI.UIConfig.buttonSound = FairyGUI.NAudioClip(ResourcesManager.LoadObject("base/common/sound/click.mp3",
|
|
|
|
|
|
typeof(UnityEngine.AudioClip)))
|
|
|
|
|
|
FairyGUI.UIConfig.defaultFont = "FZDaBiaoSong-B06S"
|
|
|
|
|
|
FairyGUI.FontManager.RegisterFont(FairyGUI.DynamicFont.New("SIYUAN", "base/static/fonts/SIYUAN.TTF"), null)
|
|
|
|
|
|
FairyGUI.FontManager.RegisterFont(
|
2025-08-30 20:29:56 +08:00
|
|
|
|
FairyGUI.DynamicFont.New("AlimamaFangYuanTiVF-Thin", "base/static/fonts/AlimamaFangYuanTiVF-Thin.ttf"), null)
|
2026-02-04 15:07:37 +08:00
|
|
|
|
FairyGUI.FontManager.RegisterFont(
|
|
|
|
|
|
FairyGUI.DynamicFont.New("AlimamaFangYuanTi-MediumRound", "base/static/fonts/AlimamaFangYuanTi-MediumRound.TTF"),
|
|
|
|
|
|
null)
|
|
|
|
|
|
FairyGUI.FontManager.RegisterFont(
|
|
|
|
|
|
FairyGUI.DynamicFont.New("AlimamaFangYuanTi-SemiBoldRound", "base/static/fonts/AlimamaFangYuanTi-SemiBoldRound.TTF"),
|
|
|
|
|
|
null)
|
|
|
|
|
|
|
|
|
|
|
|
FairyGUI.FontManager.RegisterFont(
|
|
|
|
|
|
FairyGUI.DynamicFont.New("AlimamaFangYuanTi-BoldRound-700", "base/static/fonts/AlimamaFangYuanTi-BoldRound-700.TTF"),
|
|
|
|
|
|
null)
|
2025-05-24 14:29:14 +08:00
|
|
|
|
_game_info = json.decode(GameApplication.Instance.GameInfo)
|
|
|
|
|
|
--_game_info["login_url"]="http://8.134.59.224:8101/"
|
|
|
|
|
|
--pt(_game_info)
|
|
|
|
|
|
debug_print = false --GetGameInfo("debug_print")
|
|
|
|
|
|
if Application.platform == RuntimePlatform.WindowsEditor then
|
|
|
|
|
|
debug_print = true
|
|
|
|
|
|
end
|
2026-01-27 17:50:25 +08:00
|
|
|
|
debug_print = true
|
2025-05-24 14:29:14 +08:00
|
|
|
|
local NetManager = taurus.client.NetManager
|
|
|
|
|
|
NetManager.debug_print = debug_print
|
|
|
|
|
|
-- 网络延时8秒
|
|
|
|
|
|
NetManager.TIMEOUT_TIME = 10
|
|
|
|
|
|
|
|
|
|
|
|
UIPackage.AddPackage("base/common/ui/Common")
|
|
|
|
|
|
panel = UIPackage.CreateObjectFromURL("ui://Common/UIPanel")
|
|
|
|
|
|
GRoot.inst:AddChildAt(panel, 0)
|
|
|
|
|
|
panel:MakeFullScreen()
|
|
|
|
|
|
panel:AddRelation(GRoot.inst, RelationType.Size)
|
|
|
|
|
|
--web网络API版本号
|
|
|
|
|
|
NetManager.VERSION = GetGameInfo("net_version")
|
|
|
|
|
|
|
|
|
|
|
|
TimerManager.New()
|
|
|
|
|
|
-- test:DynamicInvoke("222")
|
|
|
|
|
|
--ExtendManager.Init()
|
|
|
|
|
|
ControllerManager.Init()
|
|
|
|
|
|
ViewManager.Init()
|
|
|
|
|
|
|
|
|
|
|
|
ControllerManager.ChangeController(LoginController)
|
|
|
|
|
|
ViewManager.ChangeView(ViewManager.View_Login)
|
|
|
|
|
|
DataManager.AppVersion = GetGameInfo("app_version")
|
|
|
|
|
|
|
|
|
|
|
|
get_gps()
|
|
|
|
|
|
local timer = 0
|
|
|
|
|
|
local DSTweenManager = ds.tween.DSTweenManager
|
|
|
|
|
|
UpdateBeat:Add(function()
|
|
|
|
|
|
local deltaTime = Time.deltaTime
|
|
|
|
|
|
DSTweenManager.Update(deltaTime)
|
|
|
|
|
|
timer = timer + deltaTime
|
|
|
|
|
|
if timer >= 60 then
|
|
|
|
|
|
timer = 0
|
|
|
|
|
|
local ctr = ControllerManager.GetCurrenController()
|
|
|
|
|
|
if DataManager.CurrenRoom and ctr.baseType == GameController then
|
|
|
|
|
|
ctr:GetGPS()
|
|
|
|
|
|
else
|
|
|
|
|
|
get_gps()
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function GetGameInfo(key)
|
|
|
|
|
|
return _game_info[key]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function GetPlatform()
|
|
|
|
|
|
return ResourcesManager.OS_Dir
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function GetGameInfoPlatform(key)
|
|
|
|
|
|
local p_key = GetPlatform()
|
|
|
|
|
|
local _platfrom = _game_info[p_key]
|
|
|
|
|
|
return _platfrom[key]
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function BlurView(view, enabled)
|
|
|
|
|
|
if enabled then
|
|
|
|
|
|
local bf = FairyGUI.BlurFilter()
|
|
|
|
|
|
bf.blurSize = 0.05
|
|
|
|
|
|
view.filter = bf
|
|
|
|
|
|
else
|
|
|
|
|
|
view.filter = null
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function ShareScreenShotWithOption(callback, index)
|
|
|
|
|
|
--分享目标选择,包括分享截图到 微信/支付宝
|
|
|
|
|
|
local wx_win = BaseWindow.new("ui://Common/Win_WXShareWin", nil)
|
|
|
|
|
|
wx_win._close_destroy = true
|
|
|
|
|
|
wx_win._view:GetController("c1").selectedIndex = index or 3
|
|
|
|
|
|
local cb = function()
|
|
|
|
|
|
if callback then callback() end
|
|
|
|
|
|
end
|
|
|
|
|
|
wx_win._view:GetChild("btn_wx_session").onClick:Add(function()
|
|
|
|
|
|
wx_win:Destroy()
|
|
|
|
|
|
ShareScreenShot(1, callback)
|
|
|
|
|
|
end)
|
|
|
|
|
|
wx_win:Show()
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function ShareScreenShot(n, callback)
|
|
|
|
|
|
local json_data = {}
|
2025-05-27 02:03:04 +08:00
|
|
|
|
json_data["title"] = "游戏"
|
2025-05-24 14:29:14 +08:00
|
|
|
|
local mediaObject = {}
|
|
|
|
|
|
mediaObject["path"] = Application.persistentDataPath
|
|
|
|
|
|
mediaObject["filename"] = "screenshot"
|
|
|
|
|
|
mediaObject["type"] = 1
|
|
|
|
|
|
json_data["mediaObject"] = mediaObject
|
|
|
|
|
|
json_data["description"] = "一款现实中朋友约局休闲娱乐的场所!速度约朋友一起来玩吧!"
|
|
|
|
|
|
json_data["scene"] = 0
|
|
|
|
|
|
local json_str = json.encode(json_data)
|
|
|
|
|
|
TakeScreenShot.Take(function()
|
|
|
|
|
|
-- 1微信 2支付宝
|
|
|
|
|
|
GameApplication.Instance:ShareLink(n or 1, json_str, nil)
|
|
|
|
|
|
if callback then
|
|
|
|
|
|
callback()
|
|
|
|
|
|
end
|
|
|
|
|
|
end)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function shareQRCodePicture(url, secene)
|
|
|
|
|
|
--print(debug.traceback())
|
|
|
|
|
|
print(url)
|
|
|
|
|
|
print(secene)
|
|
|
|
|
|
local json_data = {}
|
2025-05-27 02:03:04 +08:00
|
|
|
|
json_data["title"] = "联赛"
|
2025-05-24 14:29:14 +08:00
|
|
|
|
local mediaObject = {}
|
|
|
|
|
|
local filename = "qrcode" .. DataManager.SelfUser.account_id
|
|
|
|
|
|
print(Application.persistentDataPath)
|
|
|
|
|
|
mediaObject["path"] = Application.persistentDataPath
|
|
|
|
|
|
mediaObject["filename"] = filename
|
|
|
|
|
|
mediaObject["type"] = 1
|
|
|
|
|
|
json_data["mediaObject"] = mediaObject
|
|
|
|
|
|
json_data["description"] = "一款现实中朋友约局休闲娱乐的场所!速度约朋友一起来玩吧!"
|
|
|
|
|
|
json_data["scene"] = secene
|
|
|
|
|
|
print("json_data==================")
|
|
|
|
|
|
local json_str = json.encode(json_data)
|
|
|
|
|
|
pt(json_str)
|
|
|
|
|
|
local tex2 = QRCodePicture.GenerateQRcode(url, 250, 250)
|
|
|
|
|
|
local tex1 = ResourcesManager.LoadObject("base/lobby/bg/bg.png", typeof(UnityEngine.Texture2D))
|
|
|
|
|
|
filename = filename .. ".jpg"
|
|
|
|
|
|
print("text2==========")
|
|
|
|
|
|
print(tex2)
|
|
|
|
|
|
print("text1==========")
|
|
|
|
|
|
print(tex1)
|
|
|
|
|
|
print("filename==========")
|
|
|
|
|
|
print(filename)
|
|
|
|
|
|
QRCodePicture.CombanitePicture(tex1, tex2, 393, 1334 - 802 - 250, filename)
|
|
|
|
|
|
|
|
|
|
|
|
GameApplication.Instance:ShareLink(1, json_str, nil)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function ShareChatRoom(room_id, share_time, round, game_name, group_id, player_list, _root_view, play_name)
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function UISetController(root, controller_name, gear_display, selectedIndex)
|
|
|
|
|
|
local ctr = root:GetController(controller_name)
|
|
|
|
|
|
local gear = gear_display:GetGear(0)
|
|
|
|
|
|
|
|
|
|
|
|
gear.controller = ctr
|
|
|
|
|
|
gear.pages = { ctr:GetPageId(selectedIndex) }
|
|
|
|
|
|
gear_display:HandleControllerChanged(ctr)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local bg_url = nil
|
|
|
|
|
|
function LoadGameBg(url, main_view)
|
|
|
|
|
|
local win_mode = main_view:GetChild("win_mode")
|
|
|
|
|
|
win_mode:RemoveChildren(0, -1, true)
|
|
|
|
|
|
local tex_bg = ResourcesManager.LoadObjectByGroup(url .. ".png", typeof(UnityEngine.Texture), url)
|
|
|
|
|
|
local bg = GImage()
|
|
|
|
|
|
bg.texture = FairyGUI.NTexture(tex_bg)
|
|
|
|
|
|
bg.width = win_mode.width
|
|
|
|
|
|
bg.height = win_mode.height
|
|
|
|
|
|
bg:AddRelation(win_mode, RelationType.Size)
|
|
|
|
|
|
win_mode:AddChild(bg)
|
|
|
|
|
|
|
|
|
|
|
|
-- 卸载资源
|
|
|
|
|
|
if url ~= bg_url and bg_url then
|
|
|
|
|
|
ResourcesManager.UnLoadGroup(bg_url)
|
|
|
|
|
|
end
|
|
|
|
|
|
bg_url = url
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function AddPanel(child)
|
|
|
|
|
|
child:MakeFullScreen()
|
|
|
|
|
|
child:AddRelation(GRoot.inst, RelationType.Size)
|
|
|
|
|
|
panel:AddChild(child)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function AddPanelAt(child, index)
|
|
|
|
|
|
child:MakeFullScreen()
|
|
|
|
|
|
child:AddRelation(GRoot.inst, RelationType.Size)
|
|
|
|
|
|
panel:AddChildAt(child, index)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function AddPanelCenter(child)
|
|
|
|
|
|
panel:AddChild(child)
|
|
|
|
|
|
child:Center(true)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--重启游戏
|
|
|
|
|
|
function RestartGame()
|
|
|
|
|
|
DSTweenManager.ClearTween()
|
|
|
|
|
|
panel:Dispose()
|
|
|
|
|
|
coroutine.stopAll()
|
|
|
|
|
|
BaseWindow.DestroyAll()
|
|
|
|
|
|
GameApplication.Instance:RestartGame()
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--场景切换通知
|
|
|
|
|
|
function OnLevelWasLoaded(level)
|
|
|
|
|
|
Time.timeSinceLevelLoad = 0
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--程序切到后台
|
|
|
|
|
|
function OnApplicationPause()
|
|
|
|
|
|
-- ViewUtil.CloseModalWait()
|
|
|
|
|
|
ViewManager.OnApplicationPause()
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
--程序从后台切回
|
|
|
|
|
|
function OnApplicationActive()
|
|
|
|
|
|
ViewManager.OnApplicationActive()
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function pt(...)
|
|
|
|
|
|
if debug_print then
|
|
|
|
|
|
local arg = { ... }
|
|
|
|
|
|
local has = false
|
|
|
|
|
|
for _, v in pairs(arg) do
|
|
|
|
|
|
if v and type(v) == "table" then
|
|
|
|
|
|
has = true
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
if not has then
|
|
|
|
|
|
print(...)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local content = ""
|
|
|
|
|
|
for _, v in pairs(arg) do
|
|
|
|
|
|
if v == "table" then
|
|
|
|
|
|
content = content .. tostring(v) .. "\n"
|
|
|
|
|
|
else
|
|
|
|
|
|
content = content .. "==>[T]:" .. LuaPrint(v, limit), debug.traceback() .. "\n"
|
|
|
|
|
|
end
|
|
|
|
|
|
print(content)
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function LuaPrint(lua_table, limit, indent, step)
|
|
|
|
|
|
step = step or 0
|
|
|
|
|
|
indent = indent or 0
|
|
|
|
|
|
local content = ""
|
|
|
|
|
|
if limit ~= nil then
|
|
|
|
|
|
if step > limit then
|
|
|
|
|
|
return "..."
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
if step > 10 then
|
|
|
|
|
|
return content .. "..."
|
|
|
|
|
|
end
|
|
|
|
|
|
if lua_table == nil then
|
|
|
|
|
|
return "nil"
|
|
|
|
|
|
end
|
|
|
|
|
|
if type(lua_table) == "userdata" or type(lua_table) == "lightuserdata" or type(lua_table) == "thread" then
|
|
|
|
|
|
return tostring(lua_table)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
if type(lua_table) == "string" or type(lua_table) == "number" then
|
|
|
|
|
|
return "[No-Table]:" .. lua_table
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
for k, v in pairs(lua_table) do
|
|
|
|
|
|
if k ~= "_class_type" then
|
|
|
|
|
|
local szBuffer = ""
|
|
|
|
|
|
Typev = type(v)
|
|
|
|
|
|
if Typev == "table" then
|
|
|
|
|
|
szBuffer = "{"
|
|
|
|
|
|
end
|
|
|
|
|
|
local szPrefix = string.rep(" ", indent)
|
|
|
|
|
|
if Typev == "table" and v._fields then
|
|
|
|
|
|
local kk, vv = next(v._fields)
|
|
|
|
|
|
if type(vv) == "table" then
|
|
|
|
|
|
content = content .. "\n\t" .. kk.name .. "={" .. LuaPrint(vv._fields, 5, indent + 1, step + 1) ..
|
2025-08-30 20:29:56 +08:00
|
|
|
|
"}"
|
2025-05-24 14:29:14 +08:00
|
|
|
|
else
|
|
|
|
|
|
content = content .. "\n\t" .. kk.name .. "=" .. vv
|
|
|
|
|
|
end
|
|
|
|
|
|
else
|
|
|
|
|
|
if type(k) == "table" then
|
|
|
|
|
|
if k.name then
|
|
|
|
|
|
if type(v) ~= "table" then
|
|
|
|
|
|
content = content .. "\n" .. k.name .. "=" .. v
|
|
|
|
|
|
else
|
|
|
|
|
|
content = content .. "\n" .. k.name .. " = list:"
|
|
|
|
|
|
local tmp = "\n"
|
|
|
|
|
|
for ka, va in ipairs(v) do
|
|
|
|
|
|
tmp = tmp .. "#" .. ka .. "_" .. tostring(va)
|
|
|
|
|
|
end
|
|
|
|
|
|
content = content .. tmp
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
elseif type(k) == "function" then
|
|
|
|
|
|
content = content .. "\n fun=function"
|
|
|
|
|
|
else
|
|
|
|
|
|
formatting = szPrefix .. tostring(k) .. " = " .. szBuffer
|
|
|
|
|
|
if Typev == "table" then
|
|
|
|
|
|
content = content .. "\n" .. formatting
|
|
|
|
|
|
content = content .. LuaPrint(v, limit, indent + 1, step + 1)
|
|
|
|
|
|
content = content .. "\n" .. szPrefix .. "},"
|
|
|
|
|
|
else
|
|
|
|
|
|
local szValue = ""
|
|
|
|
|
|
if Typev == "string" then
|
|
|
|
|
|
szValue = string.format("%q", v)
|
|
|
|
|
|
else
|
|
|
|
|
|
szValue = tostring(v)
|
|
|
|
|
|
end
|
|
|
|
|
|
content = content .. "\n" .. formatting .. (szValue or "nil") .. ","
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
return content
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function printlog(...)
|
|
|
|
|
|
if debug_print then
|
|
|
|
|
|
print(...)
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
2026-02-08 17:28:45 +08:00
|
|
|
|
|
|
|
|
|
|
function PrintStackTrace(ignoreCount, options)
|
|
|
|
|
|
-- 默认参数
|
|
|
|
|
|
ignoreCount = ignoreCount or 3
|
|
|
|
|
|
options = options or {}
|
|
|
|
|
|
|
|
|
|
|
|
-- 合并配置选项
|
|
|
|
|
|
local config = {
|
|
|
|
|
|
maxDepth = options.maxDepth or 20,
|
|
|
|
|
|
indentSize = options.indentSize or 2,
|
|
|
|
|
|
showVariables = options.showVariables ~= false, -- 默认true
|
|
|
|
|
|
maxVariableLength = options.maxVariableLength or 50,
|
|
|
|
|
|
showLineNumbers = options.showLineNumbers ~= false,
|
|
|
|
|
|
showFunctionType = options.showFunctionType ~= false,
|
|
|
|
|
|
showFullPath = options.showFullPath or false,
|
|
|
|
|
|
colorOutput = options.colorOutput or false,
|
|
|
|
|
|
skipDebuggerFrames = options.skipDebuggerFrames ~= false,
|
|
|
|
|
|
debuggerFiles = options.debuggerFiles or {
|
|
|
|
|
|
"debugger.lua",
|
|
|
|
|
|
"LuaDebugger.lua",
|
|
|
|
|
|
"=[C]"
|
|
|
|
|
|
},
|
|
|
|
|
|
includeTimestamp = options.includeTimestamp or false,
|
|
|
|
|
|
maxStackDepth = options.maxStackDepth or 100
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-- ANSI颜色代码(用于彩色输出)
|
|
|
|
|
|
local colors = {
|
|
|
|
|
|
reset = "\27[0m",
|
|
|
|
|
|
red = "\27[31m",
|
|
|
|
|
|
green = "\27[32m",
|
|
|
|
|
|
yellow = "\27[33m",
|
|
|
|
|
|
blue = "\27[34m",
|
|
|
|
|
|
magenta = "\27[35m",
|
|
|
|
|
|
cyan = "\27[36m",
|
|
|
|
|
|
white = "\27[37m",
|
|
|
|
|
|
gray = "\27[90m"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-- 如果不支持彩色输出,使用空字符串
|
|
|
|
|
|
if not config.colorOutput then
|
|
|
|
|
|
for k, _ in pairs(colors) do
|
|
|
|
|
|
colors[k] = ""
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 辅助函数:判断是否为调试器自身的帧
|
|
|
|
|
|
local function isDebuggerFrame(frameInfo)
|
|
|
|
|
|
if not config.skipDebuggerFrames then
|
|
|
|
|
|
return false
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
for _, pattern in ipairs(config.debuggerFiles) do
|
|
|
|
|
|
if frameInfo.src and frameInfo.src:find(pattern, 1, true) then
|
|
|
|
|
|
return true
|
|
|
|
|
|
end
|
|
|
|
|
|
if frameInfo.source and frameInfo.source:find(pattern, 1, true) then
|
|
|
|
|
|
return true
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
return false
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 辅助函数:格式化变量值(限制长度)
|
|
|
|
|
|
local function formatValue(value, maxLength)
|
|
|
|
|
|
if value == nil then
|
|
|
|
|
|
return colors.gray .. "nil" .. colors.reset
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local valueType = type(value)
|
|
|
|
|
|
local str
|
|
|
|
|
|
|
|
|
|
|
|
if valueType == "string" then
|
|
|
|
|
|
str = colors.green .. string.format("%q", value) .. colors.reset
|
|
|
|
|
|
elseif valueType == "number" then
|
|
|
|
|
|
str = colors.yellow .. tostring(value) .. colors.reset
|
|
|
|
|
|
elseif valueType == "boolean" then
|
|
|
|
|
|
str = colors.cyan .. tostring(value) .. colors.reset
|
|
|
|
|
|
elseif valueType == "table" then
|
|
|
|
|
|
local mt = getmetatable(value)
|
|
|
|
|
|
if mt and mt.__tostring then
|
|
|
|
|
|
str = tostring(value)
|
|
|
|
|
|
else
|
|
|
|
|
|
str = colors.magenta .. string.format("table: %p", value) .. colors.reset
|
|
|
|
|
|
end
|
|
|
|
|
|
elseif valueType == "function" then
|
|
|
|
|
|
str = colors.blue .. string.format("function: %p", value) .. colors.reset
|
|
|
|
|
|
elseif valueType == "userdata" or valueType == "thread" then
|
|
|
|
|
|
str = colors.white .. string.format("%s: %p", valueType, value) .. colors.reset
|
|
|
|
|
|
else
|
|
|
|
|
|
str = colors.gray .. tostring(value) .. colors.reset
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 限制长度
|
|
|
|
|
|
if #str > maxLength * 2 then -- 乘以2因为ANSI代码也占长度
|
|
|
|
|
|
str = str:sub(1, maxLength * 2) .. "..."
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
return str
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 辅助函数:格式化变量信息
|
|
|
|
|
|
local function formatVariables(vars, indent)
|
|
|
|
|
|
if not vars or not config.showVariables then
|
|
|
|
|
|
return ""
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
local lines = {}
|
|
|
|
|
|
local prefix = string.rep(" ", indent)
|
|
|
|
|
|
|
|
|
|
|
|
-- 处理局部变量
|
|
|
|
|
|
if vars.locals then
|
|
|
|
|
|
local hasLocals = false
|
|
|
|
|
|
local localNames = {}
|
|
|
|
|
|
for name, _ in pairs(vars.locals) do
|
|
|
|
|
|
table.insert(localNames, name)
|
|
|
|
|
|
end
|
|
|
|
|
|
table.sort(localNames) -- 按字母顺序排序
|
|
|
|
|
|
|
|
|
|
|
|
for _, name in ipairs(localNames) do
|
|
|
|
|
|
local info = vars.locals[name]
|
|
|
|
|
|
if not hasLocals then
|
|
|
|
|
|
table.insert(lines, prefix .. colors.cyan .. "Local Variables:" .. colors.reset)
|
|
|
|
|
|
hasLocals = true
|
|
|
|
|
|
end
|
|
|
|
|
|
local valueStr = formatValue(info.value, config.maxVariableLength)
|
|
|
|
|
|
table.insert(lines, string.format("%s %s%s%s = %s",
|
|
|
|
|
|
prefix, colors.yellow, name, colors.reset, valueStr))
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 处理上值(upvalues)
|
|
|
|
|
|
if vars.upvalues then
|
|
|
|
|
|
local hasUpvalues = false
|
|
|
|
|
|
local upvalueNames = {}
|
|
|
|
|
|
for name, _ in pairs(vars.upvalues) do
|
|
|
|
|
|
table.insert(upvalueNames, name)
|
|
|
|
|
|
end
|
|
|
|
|
|
table.sort(upvalueNames)
|
|
|
|
|
|
|
|
|
|
|
|
for _, name in ipairs(upvalueNames) do
|
|
|
|
|
|
local info = vars.upvalues[name]
|
|
|
|
|
|
if not hasUpvalues then
|
|
|
|
|
|
table.insert(lines, prefix .. colors.cyan .. "Upvalues:" .. colors.reset)
|
|
|
|
|
|
hasUpvalues = true
|
|
|
|
|
|
end
|
|
|
|
|
|
local valueStr = formatValue(info.value, config.maxVariableLength)
|
|
|
|
|
|
table.insert(lines, string.format("%s %s%s%s = %s",
|
|
|
|
|
|
prefix, colors.yellow, name, colors.reset, valueStr))
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
if #lines > 0 then
|
|
|
|
|
|
return table.concat(lines, "\n") .. "\n"
|
|
|
|
|
|
end
|
|
|
|
|
|
return ""
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 获取堆栈信息
|
|
|
|
|
|
local stackInfo = {}
|
|
|
|
|
|
local outputLines = {}
|
|
|
|
|
|
|
|
|
|
|
|
-- 添加标题
|
|
|
|
|
|
if config.includeTimestamp then
|
|
|
|
|
|
table.insert(outputLines, colors.white .. "=== Stack Trace @" .. os.date("%H:%M:%S") .. " ===" .. colors.reset)
|
|
|
|
|
|
else
|
|
|
|
|
|
table.insert(outputLines, colors.white .. "=== Stack Trace ===" .. colors.reset)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 收集堆栈信息
|
|
|
|
|
|
local frameCount = 0
|
|
|
|
|
|
local skippedDebuggerFrames = 0
|
|
|
|
|
|
|
|
|
|
|
|
for level = ignoreCount, config.maxStackDepth do
|
|
|
|
|
|
local source = debug.getinfo(level, "Snlf")
|
|
|
|
|
|
if not source then
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 构建栈帧信息
|
|
|
|
|
|
local frameInfo = {
|
|
|
|
|
|
level = level - ignoreCount + 1,
|
|
|
|
|
|
src = source.source,
|
|
|
|
|
|
funcName = source.name or "<anonymous>",
|
|
|
|
|
|
currentline = source.currentline,
|
|
|
|
|
|
linedefined = source.linedefined,
|
|
|
|
|
|
lastlinedefined = source.lastlinedefined,
|
|
|
|
|
|
what = source.what,
|
|
|
|
|
|
namewhat = source.namewhat or "",
|
|
|
|
|
|
source = source.source
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-- 跳过调试器自身的帧
|
|
|
|
|
|
if isDebuggerFrame(frameInfo) then
|
|
|
|
|
|
skippedDebuggerFrames = skippedDebuggerFrames + 1
|
|
|
|
|
|
goto continue
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 达到最大显示深度时停止
|
|
|
|
|
|
if frameCount >= config.maxDepth then
|
|
|
|
|
|
table.insert(outputLines, colors.gray .. string.format("... (%d more frames hidden)",
|
|
|
|
|
|
(config.maxStackDepth - level + 1)) .. colors.reset)
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 格式化文件路径
|
|
|
|
|
|
local filePath
|
|
|
|
|
|
if config.showFullPath then
|
|
|
|
|
|
filePath = source.source
|
|
|
|
|
|
else
|
|
|
|
|
|
-- 提取文件名
|
|
|
|
|
|
if source.source:sub(1, 1) == "@" then
|
|
|
|
|
|
local path = source.source:sub(2)
|
|
|
|
|
|
local _, filename = path:match("^.*[/\\](.+)$")
|
|
|
|
|
|
filePath = filename or path
|
|
|
|
|
|
elseif source.source:sub(1, 1) == "=" then
|
|
|
|
|
|
filePath = source.source:sub(2)
|
|
|
|
|
|
else
|
|
|
|
|
|
filePath = "[string]"
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 构建帧描述
|
|
|
|
|
|
local indent = string.rep(" ", config.indentSize)
|
|
|
|
|
|
local framePrefix = string.format("#%d ", frameCount + 1)
|
|
|
|
|
|
|
|
|
|
|
|
local frameLine
|
|
|
|
|
|
if config.showLineNumbers then
|
|
|
|
|
|
if source.currentline > 0 then
|
|
|
|
|
|
frameLine = string.format("%s%s in %s%s%s at %s%s%s:%s%d%s",
|
|
|
|
|
|
colors.white, framePrefix,
|
|
|
|
|
|
colors.yellow, frameInfo.funcName, colors.reset,
|
|
|
|
|
|
colors.blue, filePath, colors.reset,
|
|
|
|
|
|
colors.green, source.currentline, colors.reset)
|
|
|
|
|
|
else
|
|
|
|
|
|
frameLine = string.format("%s%s in %s%s%s at %s%s%s",
|
|
|
|
|
|
colors.white, framePrefix,
|
|
|
|
|
|
colors.yellow, frameInfo.funcName, colors.reset,
|
|
|
|
|
|
colors.blue, filePath, colors.reset)
|
|
|
|
|
|
end
|
|
|
|
|
|
else
|
|
|
|
|
|
frameLine = string.format("%s%s in %s%s%s",
|
|
|
|
|
|
colors.white, framePrefix,
|
|
|
|
|
|
colors.yellow, frameInfo.funcName, colors.reset)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 添加函数类型信息
|
|
|
|
|
|
if config.showFunctionType then
|
|
|
|
|
|
local typeColor = colors.gray
|
|
|
|
|
|
if source.what == "Lua" then
|
|
|
|
|
|
typeColor = colors.green
|
|
|
|
|
|
elseif source.what == "C" then
|
|
|
|
|
|
typeColor = colors.red
|
|
|
|
|
|
elseif source.what == "main" then
|
|
|
|
|
|
typeColor = colors.cyan
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
frameLine = frameLine .. string.format(" [%s%s%s]",
|
|
|
|
|
|
typeColor, source.what, colors.reset)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
table.insert(outputLines, frameLine)
|
|
|
|
|
|
|
|
|
|
|
|
-- 获取并格式化变量
|
|
|
|
|
|
if config.showVariables then
|
|
|
|
|
|
local success, vars = pcall(function()
|
|
|
|
|
|
local varInfo = {}
|
|
|
|
|
|
|
|
|
|
|
|
-- 获取局部变量
|
|
|
|
|
|
varInfo.locals = {}
|
|
|
|
|
|
local idx = 1
|
|
|
|
|
|
while true do
|
|
|
|
|
|
local name, value = debug.getlocal(level + 1, idx)
|
|
|
|
|
|
if not name then break end
|
|
|
|
|
|
|
|
|
|
|
|
-- 过滤掉调试器内部变量
|
|
|
|
|
|
if not name:find("^_debugger_") then
|
|
|
|
|
|
varInfo.locals[name] = {
|
|
|
|
|
|
value = value,
|
|
|
|
|
|
type = type(value)
|
|
|
|
|
|
}
|
|
|
|
|
|
end
|
|
|
|
|
|
idx = idx + 1
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 获取上值
|
|
|
|
|
|
varInfo.upvalues = {}
|
|
|
|
|
|
local func = debug.getinfo(level + 1, "f").func
|
|
|
|
|
|
if func then
|
|
|
|
|
|
idx = 1
|
|
|
|
|
|
while true do
|
|
|
|
|
|
local name, value = debug.getupvalue(func, idx)
|
|
|
|
|
|
if not name then break end
|
|
|
|
|
|
|
|
|
|
|
|
varInfo.upvalues[name] = {
|
|
|
|
|
|
value = value,
|
|
|
|
|
|
type = type(value)
|
|
|
|
|
|
}
|
|
|
|
|
|
idx = idx + 1
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
return varInfo
|
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
if success then
|
|
|
|
|
|
local varsStr = formatVariables(vars, config.indentSize * 2)
|
|
|
|
|
|
if varsStr ~= "" then
|
|
|
|
|
|
table.insert(outputLines, varsStr)
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
frameCount = frameCount + 1
|
|
|
|
|
|
|
|
|
|
|
|
-- 到达主程序层时停止
|
|
|
|
|
|
if source.what == "main" then
|
|
|
|
|
|
break
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
::continue::
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 添加统计信息
|
|
|
|
|
|
table.insert(outputLines, "")
|
|
|
|
|
|
table.insert(outputLines, colors.gray .. string.format(
|
|
|
|
|
|
"Total frames: %d (skipped %d debugger frames)",
|
|
|
|
|
|
frameCount, skippedDebuggerFrames) .. colors.reset)
|
|
|
|
|
|
|
|
|
|
|
|
-- 如果没有找到任何帧
|
|
|
|
|
|
if frameCount == 0 then
|
|
|
|
|
|
table.insert(outputLines,
|
|
|
|
|
|
colors.yellow .. "No stack frames found (possibly all frames were skipped)" .. colors.reset)
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- 添加分隔线
|
|
|
|
|
|
table.insert(outputLines, colors.white .. "====================" .. colors.reset)
|
|
|
|
|
|
|
|
|
|
|
|
return table.concat(outputLines, "\n")
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
function InnerFunction()
|
|
|
|
|
|
local x = 42
|
|
|
|
|
|
local name = "Test"
|
|
|
|
|
|
local data = { a = 1, b = 2 }
|
|
|
|
|
|
|
|
|
|
|
|
-- 打印堆栈信息
|
|
|
|
|
|
local trace = PrintStackTrace(2, {
|
|
|
|
|
|
showVariables = false,
|
|
|
|
|
|
colorOutput = false,
|
|
|
|
|
|
maxDepth = 20
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return trace
|
|
|
|
|
|
end
|
|
|
|
|
|
|