📄 gadgets.lua
字号:
-------------------------------------------------------------------------------------------------------------------------------------------------------------------- file: gadgets.lua-- brief: the gadget manager, a call-in router-- author: Dave Rodgers---- Copyright (C) 2007.-- Licensed under the terms of the GNU GPL, v2 or later.---------------------------------------------------------------------------------------------------------------------------------------------------------------------- TODO: - get rid of the ':'/self referencing, it's a waste of cycles-- - (De)RegisterCOBCallback(data)------------------------------------------------------------------------------------------------------------------------------------------------------------------local SAFEWRAP = 0-- 0: disabled-- 1: enabled, but can be overriden by widget.GetInfo().unsafe-- 2: always enabledlocal HANDLER_DIR = 'LuaGadgets/'local GADGETS_DIR = Script.GetName() .. '/Gadgets/'local VFSMODE = VFS.ZIP_ONLY -- FIXME: ZIP_FIRST ?if (Spring.IsDevLuaEnabled()) then VFSMODE = VFS.RAW_ONLYendVFS.Include(HANDLER_DIR .. 'setupdefs.lua', nil, VFSMODE)VFS.Include(HANDLER_DIR .. 'system.lua', nil, VFSMODE)VFS.Include(HANDLER_DIR .. 'callins.lua', nil, VFSMODE)local actionHandler = VFS.Include(HANDLER_DIR .. 'actions.lua', nil, VFSMODE)--------------------------------------------------------------------------------function pgl() -- (print gadget list) FIXME: move this into a gadget for k,v in ipairs(gadgetHandler.gadgets) do Spring.Echo( string.format("%3i %3i %s", k, v.ghInfo.layer, v.ghInfo.name) ) endend-------------------------------------------------------------------------------------------------------------------------------------------------------------------- the gadgetHandler object--gadgetHandler = { gadgets = {}, orderList = {}, knownGadgets = {}, knownCount = 0, knownChanged = true, GG = {}, -- shared table for gadgets globals = {}, -- global vars/funcs CMDIDs = {}, xViewSize = 1, yViewSize = 1, xViewSizeOld = 1, yViewSizeOld = 1,}-- these call-ins are set to 'nil' if not used-- they are setup in UpdateCallIns()local callInLists = { 'Shutdown', 'GameOver', 'TeamDied', 'GameFrame', 'ViewResize', -- FIXME ? 'TextCommand', -- FIXME ? 'GotChatMsg', -- Unit CallIns 'UnitCreated', 'UnitFinished', 'UnitFromFactory', 'UnitDestroyed', 'UnitIdle', 'UnitDamaged', 'UnitTaken', 'UnitGiven', 'UnitEnteredRadar', 'UnitEnteredLos', 'UnitLeftRadar', 'UnitLeftLos', 'UnitSeismicPing', 'UnitLoaded', 'UnitUnloaded', 'StockpileChanged', -- Feature CallIns 'FeatureCreated', 'FeatureDestroyed', -- Misc Synced CallIns 'Explosion', -- LuaRules CallIns 'CommandFallback', 'AllowCommand', 'AllowUnitCreation', 'AllowUnitTransfer', 'AllowUnitBuildStep', 'AllowFeatureCreation', 'AllowResourceLevel', 'AllowResourceTransfer', 'AllowDirectUnitControl', -- COB CallIn (FIXME?) 'CobCallback', -- Unsynced CallIns 'Update', 'DefaultCommand', 'DrawWorld', 'DrawWorldPreUnit', 'DrawWorldShadow', 'DrawWorldReflection', 'DrawWorldRefraction', 'DrawScreenEffects', 'DrawScreen', 'DrawInMiniMap', 'RecvFromSynced',}-- initialize the call-in listsdo for _,listname in ipairs(callInLists) do gadgetHandler[listname .. 'List'] = {} endend-- Utility calllocal isSyncedCode = (SendToUnsynced ~= nil)local function IsSyncedCode() return isSyncedCodeend-------------------------------------------------------------------------------------------------------------------------------------------------------------------- Reverse integer iterator for drawing--local function rev_iter(t, key) if (key <= 1) then return nil else local nkey = key - 1 return nkey, t[nkey] endendlocal function ripairs(t) return rev_iter, t, (1 + #t)end-------------------------------------------------------------------------------------------------------------------------------------------------------------------- returns: basename, dirname--local function Basename(fullpath) local _,_,base = string.find(fullpath, "([^\\/:]*)$") local _,_,path = string.find(fullpath, "(.*[\\/:])[^\\/:]*$") if (path == nil) then path = "" end return base, pathend----------------------------------------------------------------------------------------------------------------------------------------------------------------function gadgetHandler:Initialize() local unsortedGadgets = {} -- get the gadget names local gadgetFiles = VFS.DirList(GADGETS_DIR, "*.lua", VFSMODE)-- table.sort(gadgetFiles) for k,gf in ipairs(gadgetFiles) do Spring.Echo('gf1 = ' .. gf) -- FIXME end -- stuff the gadgets into unsortedGadgets for k,gf in ipairs(gadgetFiles) do Spring.Echo('gf2 = ' .. gf) -- FIXME local gadget = self:LoadGadget(gf) if (gadget) then table.insert(unsortedGadgets, gadget) end end -- sort the gadgets table.sort(unsortedGadgets, function(g1, g2) local l1 = g1.ghInfo.layer local l2 = g2.ghInfo.layer if (l1 ~= l2) then return (l1 < l2) end local n1 = g1.ghInfo.name local n2 = g2.ghInfo.name local o1 = self.orderList[n1] local o2 = self.orderList[n2] if (o1 ~= o2) then return (o1 < o2) else return (n1 < n2) end end) -- add the gadgets for _,g in ipairs(unsortedGadgets) do gadgetHandler:InsertGadget(g) local name = g.ghInfo.name local basename = g.ghInfo.basename Spring.Echo(string.format("Loaded gadget: %-18s <%s>", name, basename)) endendfunction gadgetHandler:LoadGadget(filename) local basename = Basename(filename) local text = VFS.LoadFile(filename, VFSMODE) if (text == nil) then Spring.Echo('1Failed to load: ' .. filename) return nil end local chunk, err = loadstring(text, filename) if (chunk == nil) then Spring.Echo('Failed to load: ' .. basename .. ' (' .. err .. ')') return nil end local gadget = gadgetHandler:NewGadget() setfenv(chunk, gadget) local success, err = pcall(chunk) if (not success) then Spring.Echo('Failed to load: ' .. basename .. ' (' .. err .. ')') return nil end if (err == false) then return nil -- gadget asked for a quiet death end self:FinalizeGadget(gadget, filename, basename) local name = gadget.ghInfo.name err = self:ValidateGadget(gadget) if (err) then Spring.Echo('Failed to load: ' .. basename .. ' (' .. err .. ')') return nil end local knownInfo = self.knownGadgets[name] if (knownInfo) then if (knownInfo.active) then Spring.Echo('Failed to load: ' .. basename .. ' (duplicate name)') return nil end else -- create a knownInfo table knownInfo = {} knownInfo.desc = gadget.ghInfo.desc knownInfo.author = gadget.ghInfo.author knownInfo.basename = gadget.ghInfo.basename knownInfo.filename = gadget.ghInfo.filename self.knownGadgets[name] = knownInfo self.knownCount = self.knownCount + 1 self.knownChanged = true end knownInfo.active = true local info = gadget.GetInfo and gadget:GetInfo() local order = self.orderList[name] if (((order ~= nil) and (order > 0)) or ((order == nil) and ((info == nil) or info.enabled))) then -- this will be an active gadget if (order == nil) then self.orderList[name] = 12345 -- back of the pack else self.orderList[name] = order end else self.orderList[name] = 0 self.knownGadgets[name].active = false return nil end return gadgetendfunction gadgetHandler:NewGadget() local gadget = {} -- load the system calls into the gadget table for k,v in pairs(System) do gadget[k] = v end gadget._G = _G -- the global table gadget.GG = self.GG -- the shared table gadget.gadget = gadget -- easy self referencing -- wrapped calls (closures) gadget.gadgetHandler = {} local gh = gadget.gadgetHandler local self = self gadget.include = function (f) return VFS.Include(f, gadget, VFSMODE) end gh.RaiseGadget = function (_) self:RaiseGadget(gadget) end gh.LowerGadget = function (_) self:LowerGadget(gadget) end gh.RemoveGadget = function (_) self:RemoveGadget(gadget) end gh.GetViewSizes = function (_) return self:GetViewSizes() end gh.GetHourTimer = function (_) return self:GetHourTimer() end gh.IsSyncedCode = function (_) return IsSyncedCode() end gh.UpdateCallIn = function (_, name) self:UpdateGadgetCallIn(name, gadget) end gh.RemoveCallIn = function (_, name) self:RemoveGadgetCallIn(name, gadget) end gh.RegisterCMDID = function(_, id) self:RegisterCMDID(gadget, id) end gh.RegisterGlobal = function(_, name, value) return self:RegisterGlobal(gadget, name, value) end gh.DeregisterGlobal = function(_, name) return self:DeregisterGlobal(gadget, name) end gh.SetGlobal = function(_, name, value) return self:SetGlobal(gadget, name, value) end gh.AddChatAction = function (_, cmd, func, help) return actionHandler.AddChatAction(gadget, cmd, func, help) end gh.RemoveChatAction = function (_, cmd) return actionHandler.RemoveChatAction(gadget, cmd) end if (not IsSyncedCode()) then gh.AddSyncAction = function(_, cmd, func, help) return actionHandler.AddSyncAction(gadget, cmd, func, help) end gh.RemoveSyncAction = function(_, cmd) return actionHandler.RemoveSyncAction(gadget, cmd) end end return gadgetendfunction gadgetHandler:FinalizeGadget(gadget, filename, basename) local gi = {} gi.filename = filename gi.basename = basename if (gadget.GetInfo == nil) then gi.name = basename gi.layer = 0 else local info = gadget:GetInfo() gi.name = info.name or basename gi.layer = info.layer or 0 gi.desc = info.desc or "" gi.author = info.author or "" gi.license = info.license or "" gi.enabled = info.enabled or false end gadget.ghInfo = {} -- a proxy table local mt = { __index = gi, __newindex = function() error("ghInfo tables are read-only") end, __metatable = "protected" } setmetatable(gadget.ghInfo, mt)endfunction gadgetHandler:ValidateGadget(gadget) if (gadget.GetTooltip and not gadget.IsAbove) then return "Gadget has GetTooltip() but not IsAbove()" end if (gadget.TweakGetTooltip and not gadget.TweakIsAbove) then return "Gadget has TweakGetTooltip() but not TweakIsAbove()" end return nilend----------------------------------------------------------------------------------------------------------------------------------------------------------------local function SafeWrap(func, funcName) local gh = gadgetHandler return function(g, ...) local r = { pcall(func, g, unpack(arg)) } if (r[1]) then table.remove(r, 1) return unpack(r) else if (funcName ~= 'Shutdown') then gadgetHandler:RemoveWidget(g) else Spring.Echo('Error in Shutdown') end local name = g.ghInfo.name Spring.Echo(r[2]) Spring.Echo('Removed gadget: ' .. name) return nil
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -